Merge branch 'locks' of git://linux-nfs.org/~bfields/linux
* 'locks' of git://linux-nfs.org/~bfields/linux: nfsd: remove IS_ISMNDLCK macro Rework /proc/locks via seq_files and seq_list helpers fs/locks.c: use list_for_each_entry() instead of list_for_each() NFS: clean up explicit check for mandatory locks AFS: clean up explicit check for mandatory locks 9PFS: clean up explicit check for mandatory locks GFS2: clean up explicit check for mandatory locks Cleanup macros for distinguishing mandatory locks Documentation: move locks.txt in filesystems/ locks: add warning about mandatory locking races Documentation: move mandatory locking documentation to filesystems/ locks: Fix potential OOPS in generic_setlease() Use list_first_entry in locks_wake_up_blocks locks: fix flock_lock_file() comment Memory shortage can result in inconsistent flocks state locks: kill redundant local variable locks: reverse order of posix_locks_conflict() arguments
This commit is contained in:
Коммит
541010e4b8
|
@ -145,7 +145,7 @@ fb/
|
|||
feature-removal-schedule.txt
|
||||
- list of files and features that are going to be removed.
|
||||
filesystems/
|
||||
- directory with info on the various filesystems that Linux supports.
|
||||
- info on the vfs and the various filesystems that Linux supports.
|
||||
firmware_class/
|
||||
- request_firmware() hotplug interface info.
|
||||
floppy.txt
|
||||
|
@ -230,8 +230,6 @@ local_ops.txt
|
|||
- semantics and behavior of local atomic operations.
|
||||
lockdep-design.txt
|
||||
- documentation on the runtime locking correctness validator.
|
||||
locks.txt
|
||||
- info on file locking implementations, flock() vs. fcntl(), etc.
|
||||
logo.gif
|
||||
- full colour GIF image of Linux logo (penguin - Tux).
|
||||
logo.txt
|
||||
|
@ -240,8 +238,6 @@ m68k/
|
|||
- directory with info about Linux on Motorola 68k architecture.
|
||||
magic-number.txt
|
||||
- list of magic numbers used to mark/protect kernel data structures.
|
||||
mandatory.txt
|
||||
- info on the Linux implementation of Sys V mandatory file locking.
|
||||
mca.txt
|
||||
- info on supporting Micro Channel Architecture (e.g. PS/2) systems.
|
||||
md.txt
|
||||
|
|
|
@ -52,6 +52,10 @@ isofs.txt
|
|||
- info and mount options for the ISO 9660 (CDROM) filesystem.
|
||||
jfs.txt
|
||||
- info and mount options for the JFS filesystem.
|
||||
locks.txt
|
||||
- info on file locking implementations, flock() vs. fcntl(), etc.
|
||||
mandatory-locking.txt
|
||||
- info on the Linux implementation of Sys V mandatory file locking.
|
||||
ncpfs.txt
|
||||
- info on Novell Netware(tm) filesystem using NCP protocol.
|
||||
ntfs.txt
|
||||
|
|
|
@ -53,11 +53,11 @@ fcntl(), with all the problems that implies.
|
|||
1.3 Mandatory Locking As A Mount Option
|
||||
---------------------------------------
|
||||
|
||||
Mandatory locking, as described in 'Documentation/mandatory.txt' was prior
|
||||
to this release a general configuration option that was valid for all
|
||||
mounted filesystems. This had a number of inherent dangers, not the least
|
||||
of which was the ability to freeze an NFS server by asking it to read a
|
||||
file for which a mandatory lock existed.
|
||||
Mandatory locking, as described in 'Documentation/filesystems/mandatory.txt'
|
||||
was prior to this release a general configuration option that was valid for
|
||||
all mounted filesystems. This had a number of inherent dangers, not the
|
||||
least of which was the ability to freeze an NFS server by asking it to read
|
||||
a file for which a mandatory lock existed.
|
||||
|
||||
From this release of the kernel, mandatory locking can be turned on and off
|
||||
on a per-filesystem basis, using the mount options 'mand' and 'nomand'.
|
|
@ -3,7 +3,26 @@
|
|||
Andy Walker <andy@lysaker.kvaerner.no>
|
||||
|
||||
15 April 1996
|
||||
(Updated September 2007)
|
||||
|
||||
0. Why you should avoid mandatory locking
|
||||
-----------------------------------------
|
||||
|
||||
The Linux implementation is prey to a number of difficult-to-fix race
|
||||
conditions which in practice make it not dependable:
|
||||
|
||||
- The write system call checks for a mandatory lock only once
|
||||
at its start. It is therefore possible for a lock request to
|
||||
be granted after this check but before the data is modified.
|
||||
A process may then see file data change even while a mandatory
|
||||
lock was held.
|
||||
- Similarly, an exclusive lock may be granted on a file after
|
||||
the kernel has decided to proceed with a read, but before the
|
||||
read has actually completed, and the reading process may see
|
||||
the file data in a state which should not have been visible
|
||||
to it.
|
||||
- Similar races make the claimed mutual exclusion between lock
|
||||
and mmap similarly unreliable.
|
||||
|
||||
1. What is mandatory locking?
|
||||
------------------------------
|
|
@ -105,7 +105,7 @@ static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl)
|
|||
P9_DPRINTK(P9_DEBUG_VFS, "filp: %p lock: %p\n", filp, fl);
|
||||
|
||||
/* No mandatory locks */
|
||||
if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
|
||||
if (__mandatory_lock(inode))
|
||||
return -ENOLCK;
|
||||
|
||||
if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) {
|
||||
|
|
|
@ -524,8 +524,7 @@ int afs_lock(struct file *file, int cmd, struct file_lock *fl)
|
|||
(long long) fl->fl_start, (long long) fl->fl_end);
|
||||
|
||||
/* AFS doesn't support mandatory locks */
|
||||
if ((vnode->vfs_inode.i_mode & (S_ISGID | S_IXGRP)) == S_ISGID &&
|
||||
fl->fl_type != F_UNLCK)
|
||||
if (__mandatory_lock(&vnode->vfs_inode) && fl->fl_type != F_UNLCK)
|
||||
return -ENOLCK;
|
||||
|
||||
if (IS_GETLK(cmd))
|
||||
|
|
|
@ -535,7 +535,7 @@ static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl)
|
|||
|
||||
if (!(fl->fl_flags & FL_POSIX))
|
||||
return -ENOLCK;
|
||||
if ((ip->i_inode.i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
|
||||
if (__mandatory_lock(&ip->i_inode))
|
||||
return -ENOLCK;
|
||||
|
||||
if (sdp->sd_args.ar_localflocks) {
|
||||
|
@ -636,7 +636,7 @@ static int gfs2_flock(struct file *file, int cmd, struct file_lock *fl)
|
|||
|
||||
if (!(fl->fl_flags & FL_FLOCK))
|
||||
return -ENOLCK;
|
||||
if ((ip->i_inode.i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
|
||||
if (__mandatory_lock(&ip->i_inode))
|
||||
return -ENOLCK;
|
||||
|
||||
if (sdp->sd_args.ar_localflocks)
|
||||
|
|
196
fs/locks.c
196
fs/locks.c
|
@ -534,7 +534,9 @@ static void locks_insert_block(struct file_lock *blocker,
|
|||
static void locks_wake_up_blocks(struct file_lock *blocker)
|
||||
{
|
||||
while (!list_empty(&blocker->fl_block)) {
|
||||
struct file_lock *waiter = list_entry(blocker->fl_block.next,
|
||||
struct file_lock *waiter;
|
||||
|
||||
waiter = list_first_entry(&blocker->fl_block,
|
||||
struct file_lock, fl_block);
|
||||
__locks_delete_block(waiter);
|
||||
if (waiter->fl_lmops && waiter->fl_lmops->fl_notify)
|
||||
|
@ -668,7 +670,7 @@ posix_test_lock(struct file *filp, struct file_lock *fl)
|
|||
for (cfl = filp->f_path.dentry->d_inode->i_flock; cfl; cfl = cfl->fl_next) {
|
||||
if (!IS_POSIX(cfl))
|
||||
continue;
|
||||
if (posix_locks_conflict(cfl, fl))
|
||||
if (posix_locks_conflict(fl, cfl))
|
||||
break;
|
||||
}
|
||||
if (cfl)
|
||||
|
@ -698,13 +700,12 @@ EXPORT_SYMBOL(posix_test_lock);
|
|||
static int posix_locks_deadlock(struct file_lock *caller_fl,
|
||||
struct file_lock *block_fl)
|
||||
{
|
||||
struct list_head *tmp;
|
||||
struct file_lock *fl;
|
||||
|
||||
next_task:
|
||||
if (posix_same_owner(caller_fl, block_fl))
|
||||
return 1;
|
||||
list_for_each(tmp, &blocked_list) {
|
||||
struct file_lock *fl = list_entry(tmp, struct file_lock, fl_link);
|
||||
list_for_each_entry(fl, &blocked_list, fl_link) {
|
||||
if (posix_same_owner(fl, block_fl)) {
|
||||
fl = fl->fl_next;
|
||||
block_fl = fl;
|
||||
|
@ -715,8 +716,7 @@ next_task:
|
|||
}
|
||||
|
||||
/* Try to create a FLOCK lock on filp. We always insert new FLOCK locks
|
||||
* at the head of the list, but that's secret knowledge known only to
|
||||
* flock_lock_file and posix_lock_file.
|
||||
* after any leases, but before any posix locks.
|
||||
*
|
||||
* Note that if called with an FL_EXISTS argument, the caller may determine
|
||||
* whether or not a lock was successfully freed by testing the return
|
||||
|
@ -733,6 +733,15 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
|
|||
lock_kernel();
|
||||
if (request->fl_flags & FL_ACCESS)
|
||||
goto find_conflict;
|
||||
|
||||
if (request->fl_type != F_UNLCK) {
|
||||
error = -ENOMEM;
|
||||
new_fl = locks_alloc_lock();
|
||||
if (new_fl == NULL)
|
||||
goto out;
|
||||
error = 0;
|
||||
}
|
||||
|
||||
for_each_lock(inode, before) {
|
||||
struct file_lock *fl = *before;
|
||||
if (IS_POSIX(fl))
|
||||
|
@ -754,10 +763,6 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
|
|||
goto out;
|
||||
}
|
||||
|
||||
error = -ENOMEM;
|
||||
new_fl = locks_alloc_lock();
|
||||
if (new_fl == NULL)
|
||||
goto out;
|
||||
/*
|
||||
* If a higher-priority process was blocked on the old file lock,
|
||||
* give it the opportunity to lock the file.
|
||||
|
@ -819,7 +824,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
|
|||
lock_kernel();
|
||||
if (request->fl_type != F_UNLCK) {
|
||||
for_each_lock(inode, before) {
|
||||
struct file_lock *fl = *before;
|
||||
fl = *before;
|
||||
if (!IS_POSIX(fl))
|
||||
continue;
|
||||
if (!posix_locks_conflict(request, fl))
|
||||
|
@ -1113,7 +1118,7 @@ int locks_mandatory_area(int read_write, struct inode *inode,
|
|||
* If we've been sleeping someone might have
|
||||
* changed the permissions behind our back.
|
||||
*/
|
||||
if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
|
||||
if (__mandatory_lock(inode))
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1337,6 +1342,7 @@ int fcntl_getlease(struct file *filp)
|
|||
int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
|
||||
{
|
||||
struct file_lock *fl, **before, **my_before = NULL, *lease;
|
||||
struct file_lock *new_fl = NULL;
|
||||
struct dentry *dentry = filp->f_path.dentry;
|
||||
struct inode *inode = dentry->d_inode;
|
||||
int error, rdlease_count = 0, wrlease_count = 0;
|
||||
|
@ -1363,6 +1369,11 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
|
|||
|| (atomic_read(&inode->i_count) > 1)))
|
||||
goto out;
|
||||
|
||||
error = -ENOMEM;
|
||||
new_fl = locks_alloc_lock();
|
||||
if (new_fl == NULL)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* At this point, we know that if there is an exclusive
|
||||
* lease on this file, then we hold it on this filp
|
||||
|
@ -1405,18 +1416,15 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
|
|||
if (!leases_enable)
|
||||
goto out;
|
||||
|
||||
error = -ENOMEM;
|
||||
fl = locks_alloc_lock();
|
||||
if (fl == NULL)
|
||||
goto out;
|
||||
locks_copy_lock(new_fl, lease);
|
||||
locks_insert_lock(before, new_fl);
|
||||
|
||||
locks_copy_lock(fl, lease);
|
||||
*flp = new_fl;
|
||||
return 0;
|
||||
|
||||
locks_insert_lock(before, fl);
|
||||
|
||||
*flp = fl;
|
||||
error = 0;
|
||||
out:
|
||||
if (new_fl != NULL)
|
||||
locks_free_lock(new_fl);
|
||||
return error;
|
||||
}
|
||||
EXPORT_SYMBOL(generic_setlease);
|
||||
|
@ -1752,9 +1760,7 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd,
|
|||
/* Don't allow mandatory locks on files that may be memory mapped
|
||||
* and shared.
|
||||
*/
|
||||
if (IS_MANDLOCK(inode) &&
|
||||
(inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID &&
|
||||
mapping_writably_mapped(filp->f_mapping)) {
|
||||
if (mandatory_lock(inode) && mapping_writably_mapped(filp->f_mapping)) {
|
||||
error = -EAGAIN;
|
||||
goto out;
|
||||
}
|
||||
|
@ -1878,9 +1884,7 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd,
|
|||
/* Don't allow mandatory locks on files that may be memory mapped
|
||||
* and shared.
|
||||
*/
|
||||
if (IS_MANDLOCK(inode) &&
|
||||
(inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID &&
|
||||
mapping_writably_mapped(filp->f_mapping)) {
|
||||
if (mandatory_lock(inode) && mapping_writably_mapped(filp->f_mapping)) {
|
||||
error = -EAGAIN;
|
||||
goto out;
|
||||
}
|
||||
|
@ -2062,138 +2066,114 @@ int vfs_cancel_lock(struct file *filp, struct file_lock *fl)
|
|||
|
||||
EXPORT_SYMBOL_GPL(vfs_cancel_lock);
|
||||
|
||||
static void lock_get_status(char* out, struct file_lock *fl, int id, char *pfx)
|
||||
#ifdef CONFIG_PROC_FS
|
||||
#include <linux/seq_file.h>
|
||||
|
||||
static void lock_get_status(struct seq_file *f, struct file_lock *fl,
|
||||
int id, char *pfx)
|
||||
{
|
||||
struct inode *inode = NULL;
|
||||
|
||||
if (fl->fl_file != NULL)
|
||||
inode = fl->fl_file->f_path.dentry->d_inode;
|
||||
|
||||
out += sprintf(out, "%d:%s ", id, pfx);
|
||||
seq_printf(f, "%d:%s ", id, pfx);
|
||||
if (IS_POSIX(fl)) {
|
||||
out += sprintf(out, "%6s %s ",
|
||||
seq_printf(f, "%6s %s ",
|
||||
(fl->fl_flags & FL_ACCESS) ? "ACCESS" : "POSIX ",
|
||||
(inode == NULL) ? "*NOINODE*" :
|
||||
(IS_MANDLOCK(inode) &&
|
||||
(inode->i_mode & (S_IXGRP | S_ISGID)) == S_ISGID) ?
|
||||
"MANDATORY" : "ADVISORY ");
|
||||
mandatory_lock(inode) ? "MANDATORY" : "ADVISORY ");
|
||||
} else if (IS_FLOCK(fl)) {
|
||||
if (fl->fl_type & LOCK_MAND) {
|
||||
out += sprintf(out, "FLOCK MSNFS ");
|
||||
seq_printf(f, "FLOCK MSNFS ");
|
||||
} else {
|
||||
out += sprintf(out, "FLOCK ADVISORY ");
|
||||
seq_printf(f, "FLOCK ADVISORY ");
|
||||
}
|
||||
} else if (IS_LEASE(fl)) {
|
||||
out += sprintf(out, "LEASE ");
|
||||
seq_printf(f, "LEASE ");
|
||||
if (fl->fl_type & F_INPROGRESS)
|
||||
out += sprintf(out, "BREAKING ");
|
||||
seq_printf(f, "BREAKING ");
|
||||
else if (fl->fl_file)
|
||||
out += sprintf(out, "ACTIVE ");
|
||||
seq_printf(f, "ACTIVE ");
|
||||
else
|
||||
out += sprintf(out, "BREAKER ");
|
||||
seq_printf(f, "BREAKER ");
|
||||
} else {
|
||||
out += sprintf(out, "UNKNOWN UNKNOWN ");
|
||||
seq_printf(f, "UNKNOWN UNKNOWN ");
|
||||
}
|
||||
if (fl->fl_type & LOCK_MAND) {
|
||||
out += sprintf(out, "%s ",
|
||||
seq_printf(f, "%s ",
|
||||
(fl->fl_type & LOCK_READ)
|
||||
? (fl->fl_type & LOCK_WRITE) ? "RW " : "READ "
|
||||
: (fl->fl_type & LOCK_WRITE) ? "WRITE" : "NONE ");
|
||||
} else {
|
||||
out += sprintf(out, "%s ",
|
||||
seq_printf(f, "%s ",
|
||||
(fl->fl_type & F_INPROGRESS)
|
||||
? (fl->fl_type & F_UNLCK) ? "UNLCK" : "READ "
|
||||
: (fl->fl_type & F_WRLCK) ? "WRITE" : "READ ");
|
||||
}
|
||||
if (inode) {
|
||||
#ifdef WE_CAN_BREAK_LSLK_NOW
|
||||
out += sprintf(out, "%d %s:%ld ", fl->fl_pid,
|
||||
seq_printf(f, "%d %s:%ld ", fl->fl_pid,
|
||||
inode->i_sb->s_id, inode->i_ino);
|
||||
#else
|
||||
/* userspace relies on this representation of dev_t ;-( */
|
||||
out += sprintf(out, "%d %02x:%02x:%ld ", fl->fl_pid,
|
||||
seq_printf(f, "%d %02x:%02x:%ld ", fl->fl_pid,
|
||||
MAJOR(inode->i_sb->s_dev),
|
||||
MINOR(inode->i_sb->s_dev), inode->i_ino);
|
||||
#endif
|
||||
} else {
|
||||
out += sprintf(out, "%d <none>:0 ", fl->fl_pid);
|
||||
seq_printf(f, "%d <none>:0 ", fl->fl_pid);
|
||||
}
|
||||
if (IS_POSIX(fl)) {
|
||||
if (fl->fl_end == OFFSET_MAX)
|
||||
out += sprintf(out, "%Ld EOF\n", fl->fl_start);
|
||||
seq_printf(f, "%Ld EOF\n", fl->fl_start);
|
||||
else
|
||||
out += sprintf(out, "%Ld %Ld\n", fl->fl_start,
|
||||
fl->fl_end);
|
||||
seq_printf(f, "%Ld %Ld\n", fl->fl_start, fl->fl_end);
|
||||
} else {
|
||||
out += sprintf(out, "0 EOF\n");
|
||||
seq_printf(f, "0 EOF\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void move_lock_status(char **p, off_t* pos, off_t offset)
|
||||
static int locks_show(struct seq_file *f, void *v)
|
||||
{
|
||||
int len;
|
||||
len = strlen(*p);
|
||||
if(*pos >= offset) {
|
||||
/* the complete line is valid */
|
||||
*p += len;
|
||||
*pos += len;
|
||||
return;
|
||||
}
|
||||
if(*pos+len > offset) {
|
||||
/* use the second part of the line */
|
||||
int i = offset-*pos;
|
||||
memmove(*p,*p+i,len-i);
|
||||
*p += len-i;
|
||||
*pos += len;
|
||||
return;
|
||||
}
|
||||
/* discard the complete line */
|
||||
*pos += len;
|
||||
struct file_lock *fl, *bfl;
|
||||
|
||||
fl = list_entry(v, struct file_lock, fl_link);
|
||||
|
||||
lock_get_status(f, fl, (long)f->private, "");
|
||||
|
||||
list_for_each_entry(bfl, &fl->fl_block, fl_block)
|
||||
lock_get_status(f, bfl, (long)f->private, " ->");
|
||||
|
||||
f->private++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* get_locks_status - reports lock usage in /proc/locks
|
||||
* @buffer: address in userspace to write into
|
||||
* @start: ?
|
||||
* @offset: how far we are through the buffer
|
||||
* @length: how much to read
|
||||
*/
|
||||
|
||||
int get_locks_status(char *buffer, char **start, off_t offset, int length)
|
||||
static void *locks_start(struct seq_file *f, loff_t *pos)
|
||||
{
|
||||
struct list_head *tmp;
|
||||
char *q = buffer;
|
||||
off_t pos = 0;
|
||||
int i = 0;
|
||||
|
||||
lock_kernel();
|
||||
list_for_each(tmp, &file_lock_list) {
|
||||
struct list_head *btmp;
|
||||
struct file_lock *fl = list_entry(tmp, struct file_lock, fl_link);
|
||||
lock_get_status(q, fl, ++i, "");
|
||||
move_lock_status(&q, &pos, offset);
|
||||
|
||||
if(pos >= offset+length)
|
||||
goto done;
|
||||
|
||||
list_for_each(btmp, &fl->fl_block) {
|
||||
struct file_lock *bfl = list_entry(btmp,
|
||||
struct file_lock, fl_block);
|
||||
lock_get_status(q, bfl, i, " ->");
|
||||
move_lock_status(&q, &pos, offset);
|
||||
|
||||
if(pos >= offset+length)
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
done:
|
||||
unlock_kernel();
|
||||
*start = buffer;
|
||||
if(q-buffer < length)
|
||||
return (q-buffer);
|
||||
return length;
|
||||
f->private = (void *)1;
|
||||
return seq_list_start(&file_lock_list, *pos);
|
||||
}
|
||||
|
||||
static void *locks_next(struct seq_file *f, void *v, loff_t *pos)
|
||||
{
|
||||
return seq_list_next(v, &file_lock_list, pos);
|
||||
}
|
||||
|
||||
static void locks_stop(struct seq_file *f, void *v)
|
||||
{
|
||||
unlock_kernel();
|
||||
}
|
||||
|
||||
struct seq_operations locks_seq_operations = {
|
||||
.start = locks_start,
|
||||
.next = locks_next,
|
||||
.stop = locks_stop,
|
||||
.show = locks_show,
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* lock_may_read - checks that the region is free of locks
|
||||
* @inode: the inode that is being read
|
||||
|
|
|
@ -577,8 +577,7 @@ static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
|
|||
nfs_inc_stats(inode, NFSIOS_VFSLOCK);
|
||||
|
||||
/* No mandatory locks over NFS */
|
||||
if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID &&
|
||||
fl->fl_type != F_UNLCK)
|
||||
if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK)
|
||||
return -ENOLCK;
|
||||
|
||||
if (IS_GETLK(cmd))
|
||||
|
|
|
@ -2035,7 +2035,7 @@ static inline int
|
|||
io_during_grace_disallowed(struct inode *inode, int flags)
|
||||
{
|
||||
return nfs4_in_grace() && (flags & (RD_STATE | WR_STATE))
|
||||
&& MANDATORY_LOCK(inode);
|
||||
&& mandatory_lock(inode);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -61,12 +61,6 @@
|
|||
#define NFSDDBG_FACILITY NFSDDBG_FILEOP
|
||||
|
||||
|
||||
/* We must ignore files (but only files) which might have mandatory
|
||||
* locks on them because there is no way to know if the accesser has
|
||||
* the lock.
|
||||
*/
|
||||
#define IS_ISMNDLK(i) (S_ISREG((i)->i_mode) && MANDATORY_LOCK(i))
|
||||
|
||||
/*
|
||||
* This is a cache of readahead params that help us choose the proper
|
||||
* readahead strategy. Initially, we set all readahead parameters to 0
|
||||
|
@ -689,7 +683,12 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
|
|||
err = nfserr_perm;
|
||||
if (IS_APPEND(inode) && (access & MAY_WRITE))
|
||||
goto out;
|
||||
if (IS_ISMNDLK(inode))
|
||||
/*
|
||||
* We must ignore files (but only files) which might have mandatory
|
||||
* locks on them because there is no way to know if the accesser has
|
||||
* the lock.
|
||||
*/
|
||||
if (S_ISREG((inode)->i_mode) && mandatory_lock(inode))
|
||||
goto out;
|
||||
|
||||
if (!inode->i_fop)
|
||||
|
|
|
@ -66,7 +66,6 @@ extern int get_stram_list(char *);
|
|||
extern int get_filesystem_list(char *);
|
||||
extern int get_exec_domain_list(char *);
|
||||
extern int get_dma_list(char *);
|
||||
extern int get_locks_status (char *, char **, off_t, int);
|
||||
|
||||
static int proc_calc_metrics(char *page, char **start, off_t off,
|
||||
int count, int *eof, int len)
|
||||
|
@ -624,16 +623,18 @@ static int cmdline_read_proc(char *page, char **start, off_t off,
|
|||
return proc_calc_metrics(page, start, off, count, eof, len);
|
||||
}
|
||||
|
||||
static int locks_read_proc(char *page, char **start, off_t off,
|
||||
int count, int *eof, void *data)
|
||||
static int locks_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
int len = get_locks_status(page, start, off, count);
|
||||
|
||||
if (len < count)
|
||||
*eof = 1;
|
||||
return len;
|
||||
return seq_open(filp, &locks_seq_operations);
|
||||
}
|
||||
|
||||
static const struct file_operations proc_locks_operations = {
|
||||
.open = locks_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = seq_release,
|
||||
};
|
||||
|
||||
static int execdomains_read_proc(char *page, char **start, off_t off,
|
||||
int count, int *eof, void *data)
|
||||
{
|
||||
|
@ -691,7 +692,6 @@ void __init proc_misc_init(void)
|
|||
#endif
|
||||
{"filesystems", filesystems_read_proc},
|
||||
{"cmdline", cmdline_read_proc},
|
||||
{"locks", locks_read_proc},
|
||||
{"execdomains", execdomains_read_proc},
|
||||
{NULL,}
|
||||
};
|
||||
|
@ -709,6 +709,7 @@ void __init proc_misc_init(void)
|
|||
entry->proc_fops = &proc_kmsg_operations;
|
||||
}
|
||||
#endif
|
||||
create_seq_entry("locks", 0, &proc_locks_operations);
|
||||
create_seq_entry("devices", 0, &proc_devinfo_operations);
|
||||
create_seq_entry("cpuinfo", 0, &proc_cpuinfo_operations);
|
||||
#ifdef CONFIG_BLOCK
|
||||
|
|
|
@ -205,7 +205,7 @@ int rw_verify_area(int read_write, struct file *file, loff_t *ppos, size_t count
|
|||
if (unlikely((pos < 0) || (loff_t) (pos + count) < 0))
|
||||
goto Einval;
|
||||
|
||||
if (unlikely(inode->i_flock && MANDATORY_LOCK(inode))) {
|
||||
if (unlikely(inode->i_flock && mandatory_lock(inode))) {
|
||||
int retval = locks_mandatory_area(
|
||||
read_write == READ ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE,
|
||||
inode, file, pos, count);
|
||||
|
|
|
@ -883,6 +883,7 @@ extern int vfs_setlease(struct file *, long, struct file_lock **);
|
|||
extern int lease_modify(struct file_lock **, int);
|
||||
extern int lock_may_read(struct inode *, loff_t start, unsigned long count);
|
||||
extern int lock_may_write(struct inode *, loff_t start, unsigned long count);
|
||||
extern struct seq_operations locks_seq_operations;
|
||||
|
||||
struct fasync_struct {
|
||||
int magic;
|
||||
|
@ -1375,12 +1376,25 @@ extern int locks_mandatory_area(int, struct inode *, struct file *, loff_t, size
|
|||
* Candidates for mandatory locking have the setgid bit set
|
||||
* but no group execute bit - an otherwise meaningless combination.
|
||||
*/
|
||||
#define MANDATORY_LOCK(inode) \
|
||||
(IS_MANDLOCK(inode) && ((inode)->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
|
||||
|
||||
static inline int __mandatory_lock(struct inode *ino)
|
||||
{
|
||||
return (ino->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID;
|
||||
}
|
||||
|
||||
/*
|
||||
* ... and these candidates should be on MS_MANDLOCK mounted fs,
|
||||
* otherwise these will be advisory locks
|
||||
*/
|
||||
|
||||
static inline int mandatory_lock(struct inode *ino)
|
||||
{
|
||||
return IS_MANDLOCK(ino) && __mandatory_lock(ino);
|
||||
}
|
||||
|
||||
static inline int locks_verify_locked(struct inode *inode)
|
||||
{
|
||||
if (MANDATORY_LOCK(inode))
|
||||
if (mandatory_lock(inode))
|
||||
return locks_mandatory_locked(inode);
|
||||
return 0;
|
||||
}
|
||||
|
@ -1391,7 +1405,7 @@ static inline int locks_verify_truncate(struct inode *inode,
|
|||
struct file *filp,
|
||||
loff_t size)
|
||||
{
|
||||
if (inode->i_flock && MANDATORY_LOCK(inode))
|
||||
if (inode->i_flock && mandatory_lock(inode))
|
||||
return locks_mandatory_area(
|
||||
FLOCK_VERIFY_WRITE, inode, filp,
|
||||
size < inode->i_size ? size : inode->i_size,
|
||||
|
|
Загрузка…
Ссылка в новой задаче