Commit 541010e4 authored by Linus Torvalds's avatar Linus Torvalds

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
parents e457f790 5e7fc436
...@@ -145,7 +145,7 @@ fb/ ...@@ -145,7 +145,7 @@ fb/
feature-removal-schedule.txt feature-removal-schedule.txt
- list of files and features that are going to be removed. - list of files and features that are going to be removed.
filesystems/ filesystems/
- directory with info on the various filesystems that Linux supports. - info on the vfs and the various filesystems that Linux supports.
firmware_class/ firmware_class/
- request_firmware() hotplug interface info. - request_firmware() hotplug interface info.
floppy.txt floppy.txt
...@@ -230,8 +230,6 @@ local_ops.txt ...@@ -230,8 +230,6 @@ local_ops.txt
- semantics and behavior of local atomic operations. - semantics and behavior of local atomic operations.
lockdep-design.txt lockdep-design.txt
- documentation on the runtime locking correctness validator. - documentation on the runtime locking correctness validator.
locks.txt
- info on file locking implementations, flock() vs. fcntl(), etc.
logo.gif logo.gif
- full colour GIF image of Linux logo (penguin - Tux). - full colour GIF image of Linux logo (penguin - Tux).
logo.txt logo.txt
...@@ -240,8 +238,6 @@ m68k/ ...@@ -240,8 +238,6 @@ m68k/
- directory with info about Linux on Motorola 68k architecture. - directory with info about Linux on Motorola 68k architecture.
magic-number.txt magic-number.txt
- list of magic numbers used to mark/protect kernel data structures. - 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 mca.txt
- info on supporting Micro Channel Architecture (e.g. PS/2) systems. - info on supporting Micro Channel Architecture (e.g. PS/2) systems.
md.txt md.txt
......
...@@ -52,6 +52,10 @@ isofs.txt ...@@ -52,6 +52,10 @@ isofs.txt
- info and mount options for the ISO 9660 (CDROM) filesystem. - info and mount options for the ISO 9660 (CDROM) filesystem.
jfs.txt jfs.txt
- info and mount options for the JFS filesystem. - 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 ncpfs.txt
- info on Novell Netware(tm) filesystem using NCP protocol. - info on Novell Netware(tm) filesystem using NCP protocol.
ntfs.txt ntfs.txt
......
...@@ -53,11 +53,11 @@ fcntl(), with all the problems that implies. ...@@ -53,11 +53,11 @@ fcntl(), with all the problems that implies.
1.3 Mandatory Locking As A Mount Option 1.3 Mandatory Locking As A Mount Option
--------------------------------------- ---------------------------------------
Mandatory locking, as described in 'Documentation/mandatory.txt' was prior Mandatory locking, as described in 'Documentation/filesystems/mandatory.txt'
to this release a general configuration option that was valid for all was prior to this release a general configuration option that was valid for
mounted filesystems. This had a number of inherent dangers, not the least all mounted filesystems. This had a number of inherent dangers, not the
of which was the ability to freeze an NFS server by asking it to read a least of which was the ability to freeze an NFS server by asking it to read
file for which a mandatory lock existed. a file for which a mandatory lock existed.
From this release of the kernel, mandatory locking can be turned on and off 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'. on a per-filesystem basis, using the mount options 'mand' and 'nomand'.
......
...@@ -3,7 +3,26 @@ ...@@ -3,7 +3,26 @@
Andy Walker <andy@lysaker.kvaerner.no> Andy Walker <andy@lysaker.kvaerner.no>
15 April 1996 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? 1. What is mandatory locking?
------------------------------ ------------------------------
......
...@@ -105,7 +105,7 @@ static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl) ...@@ -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); P9_DPRINTK(P9_DEBUG_VFS, "filp: %p lock: %p\n", filp, fl);
/* No mandatory locks */ /* No mandatory locks */
if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) if (__mandatory_lock(inode))
return -ENOLCK; return -ENOLCK;
if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) { 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) ...@@ -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); (long long) fl->fl_start, (long long) fl->fl_end);
/* AFS doesn't support mandatory locks */ /* AFS doesn't support mandatory locks */
if ((vnode->vfs_inode.i_mode & (S_ISGID | S_IXGRP)) == S_ISGID && if (__mandatory_lock(&vnode->vfs_inode) && fl->fl_type != F_UNLCK)
fl->fl_type != F_UNLCK)
return -ENOLCK; return -ENOLCK;
if (IS_GETLK(cmd)) if (IS_GETLK(cmd))
......
...@@ -535,7 +535,7 @@ static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl) ...@@ -535,7 +535,7 @@ static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl)
if (!(fl->fl_flags & FL_POSIX)) if (!(fl->fl_flags & FL_POSIX))
return -ENOLCK; return -ENOLCK;
if ((ip->i_inode.i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) if (__mandatory_lock(&ip->i_inode))
return -ENOLCK; return -ENOLCK;
if (sdp->sd_args.ar_localflocks) { if (sdp->sd_args.ar_localflocks) {
...@@ -636,7 +636,7 @@ static int gfs2_flock(struct file *file, int cmd, struct file_lock *fl) ...@@ -636,7 +636,7 @@ static int gfs2_flock(struct file *file, int cmd, struct file_lock *fl)
if (!(fl->fl_flags & FL_FLOCK)) if (!(fl->fl_flags & FL_FLOCK))
return -ENOLCK; return -ENOLCK;
if ((ip->i_inode.i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) if (__mandatory_lock(&ip->i_inode))
return -ENOLCK; return -ENOLCK;
if (sdp->sd_args.ar_localflocks) if (sdp->sd_args.ar_localflocks)
......
...@@ -534,7 +534,9 @@ static void locks_insert_block(struct file_lock *blocker, ...@@ -534,7 +534,9 @@ static void locks_insert_block(struct file_lock *blocker,
static void locks_wake_up_blocks(struct file_lock *blocker) static void locks_wake_up_blocks(struct file_lock *blocker)
{ {
while (!list_empty(&blocker->fl_block)) { 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); struct file_lock, fl_block);
__locks_delete_block(waiter); __locks_delete_block(waiter);
if (waiter->fl_lmops && waiter->fl_lmops->fl_notify) if (waiter->fl_lmops && waiter->fl_lmops->fl_notify)
...@@ -668,7 +670,7 @@ posix_test_lock(struct file *filp, struct file_lock *fl) ...@@ -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) { for (cfl = filp->f_path.dentry->d_inode->i_flock; cfl; cfl = cfl->fl_next) {
if (!IS_POSIX(cfl)) if (!IS_POSIX(cfl))
continue; continue;
if (posix_locks_conflict(cfl, fl)) if (posix_locks_conflict(fl, cfl))
break; break;
} }
if (cfl) if (cfl)
...@@ -698,13 +700,12 @@ EXPORT_SYMBOL(posix_test_lock); ...@@ -698,13 +700,12 @@ EXPORT_SYMBOL(posix_test_lock);
static int posix_locks_deadlock(struct file_lock *caller_fl, static int posix_locks_deadlock(struct file_lock *caller_fl,
struct file_lock *block_fl) struct file_lock *block_fl)
{ {
struct list_head *tmp; struct file_lock *fl;
next_task: next_task:
if (posix_same_owner(caller_fl, block_fl)) if (posix_same_owner(caller_fl, block_fl))
return 1; return 1;
list_for_each(tmp, &blocked_list) { list_for_each_entry(fl, &blocked_list, fl_link) {
struct file_lock *fl = list_entry(tmp, struct file_lock, fl_link);
if (posix_same_owner(fl, block_fl)) { if (posix_same_owner(fl, block_fl)) {
fl = fl->fl_next; fl = fl->fl_next;
block_fl = fl; block_fl = fl;
...@@ -715,8 +716,7 @@ static int posix_locks_deadlock(struct file_lock *caller_fl, ...@@ -715,8 +716,7 @@ static int posix_locks_deadlock(struct file_lock *caller_fl,
} }
/* Try to create a FLOCK lock on filp. We always insert new FLOCK locks /* 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 * after any leases, but before any posix locks.
* flock_lock_file and posix_lock_file.
* *
* Note that if called with an FL_EXISTS argument, the caller may determine * 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 * 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) ...@@ -733,6 +733,15 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
lock_kernel(); lock_kernel();
if (request->fl_flags & FL_ACCESS) if (request->fl_flags & FL_ACCESS)
goto find_conflict; 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) { for_each_lock(inode, before) {
struct file_lock *fl = *before; struct file_lock *fl = *before;
if (IS_POSIX(fl)) if (IS_POSIX(fl))
...@@ -754,10 +763,6 @@ static int flock_lock_file(struct file *filp, struct file_lock *request) ...@@ -754,10 +763,6 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
goto out; 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, * If a higher-priority process was blocked on the old file lock,
* give it the opportunity to lock the file. * 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 ...@@ -819,7 +824,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
lock_kernel(); lock_kernel();
if (request->fl_type != F_UNLCK) { if (request->fl_type != F_UNLCK) {
for_each_lock(inode, before) { for_each_lock(inode, before) {
struct file_lock *fl = *before; fl = *before;
if (!IS_POSIX(fl)) if (!IS_POSIX(fl))
continue; continue;
if (!posix_locks_conflict(request, fl)) if (!posix_locks_conflict(request, fl))
...@@ -1113,7 +1118,7 @@ int locks_mandatory_area(int read_write, struct inode *inode, ...@@ -1113,7 +1118,7 @@ int locks_mandatory_area(int read_write, struct inode *inode,
* If we've been sleeping someone might have * If we've been sleeping someone might have
* changed the permissions behind our back. * changed the permissions behind our back.
*/ */
if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) if (__mandatory_lock(inode))
continue; continue;
} }
...@@ -1337,6 +1342,7 @@ int fcntl_getlease(struct file *filp) ...@@ -1337,6 +1342,7 @@ int fcntl_getlease(struct file *filp)
int generic_setlease(struct file *filp, long arg, struct file_lock **flp) int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
{ {
struct file_lock *fl, **before, **my_before = NULL, *lease; struct file_lock *fl, **before, **my_before = NULL, *lease;
struct file_lock *new_fl = NULL;
struct dentry *dentry = filp->f_path.dentry; struct dentry *dentry = filp->f_path.dentry;
struct inode *inode = dentry->d_inode; struct inode *inode = dentry->d_inode;
int error, rdlease_count = 0, wrlease_count = 0; int error, rdlease_count = 0, wrlease_count = 0;
...@@ -1363,6 +1369,11 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp) ...@@ -1363,6 +1369,11 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
|| (atomic_read(&inode->i_count) > 1))) || (atomic_read(&inode->i_count) > 1)))
goto out; 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 * At this point, we know that if there is an exclusive
* lease on this file, then we hold it on this filp * 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) ...@@ -1405,18 +1416,15 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
if (!leases_enable) if (!leases_enable)
goto out; goto out;
error = -ENOMEM; locks_copy_lock(new_fl, lease);
fl = locks_alloc_lock(); locks_insert_lock(before, new_fl);
if (fl == NULL)
goto out;
locks_copy_lock(fl, lease);
locks_insert_lock(before, fl); *flp = new_fl;
return 0;
*flp = fl;
error = 0;
out: out:
if (new_fl != NULL)
locks_free_lock(new_fl);
return error; return error;
} }
EXPORT_SYMBOL(generic_setlease); EXPORT_SYMBOL(generic_setlease);
...@@ -1752,9 +1760,7 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd, ...@@ -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 /* Don't allow mandatory locks on files that may be memory mapped
* and shared. * and shared.
*/ */
if (IS_MANDLOCK(inode) && if (mandatory_lock(inode) && mapping_writably_mapped(filp->f_mapping)) {
(inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID &&
mapping_writably_mapped(filp->f_mapping)) {
error = -EAGAIN; error = -EAGAIN;
goto out; goto out;
} }
...@@ -1878,9 +1884,7 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd, ...@@ -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 /* Don't allow mandatory locks on files that may be memory mapped
* and shared. * and shared.
*/ */
if (IS_MANDLOCK(inode) && if (mandatory_lock(inode) && mapping_writably_mapped(filp->f_mapping)) {
(inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID &&
mapping_writably_mapped(filp->f_mapping)) {
error = -EAGAIN; error = -EAGAIN;
goto out; goto out;
} }
...@@ -2062,138 +2066,114 @@ int vfs_cancel_lock(struct file *filp, struct file_lock *fl) ...@@ -2062,138 +2066,114 @@ int vfs_cancel_lock(struct file *filp, struct file_lock *fl)
EXPORT_SYMBOL_GPL(vfs_cancel_lock); 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; struct inode *inode = NULL;
if (fl->fl_file != NULL) if (fl->fl_file != NULL)
inode = fl->fl_file->f_path.dentry->d_inode; 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)) { if (IS_POSIX(fl)) {
out += sprintf(out, "%6s %s ", seq_printf(f, "%6s %s ",
(fl->fl_flags & FL_ACCESS) ? "ACCESS" : "POSIX ", (fl->fl_flags & FL_ACCESS) ? "ACCESS" : "POSIX ",
(inode == NULL) ? "*NOINODE*" : (inode == NULL) ? "*NOINODE*" :
(IS_MANDLOCK(inode) && mandatory_lock(inode) ? "MANDATORY" : "ADVISORY ");
(inode->i_mode & (S_IXGRP | S_ISGID)) == S_ISGID) ?
"MANDATORY" : "ADVISORY ");
} else if (IS_FLOCK(fl)) { } else if (IS_FLOCK(fl)) {
if (fl->fl_type & LOCK_MAND) { if (fl->fl_type & LOCK_MAND) {
out += sprintf(out, "FLOCK MSNFS "); seq_printf(f, "FLOCK MSNFS ");
} else { } else {
out += sprintf(out, "FLOCK ADVISORY "); seq_printf(f, "FLOCK ADVISORY ");
} }
} else if (IS_LEASE(fl)) { } else if (IS_LEASE(fl)) {
out += sprintf(out, "LEASE "); seq_printf(f, "LEASE ");
if (fl->fl_type & F_INPROGRESS) if (fl->fl_type & F_INPROGRESS)
out += sprintf(out, "BREAKING "); seq_printf(f, "BREAKING ");
else if (fl->fl_file) else if (fl->fl_file)
out += sprintf(out, "ACTIVE "); seq_printf(f, "ACTIVE ");
else else
out += sprintf(out, "BREAKER "); seq_printf(f, "BREAKER ");
} else { } else {
out += sprintf(out, "UNKNOWN UNKNOWN "); seq_printf(f, "UNKNOWN UNKNOWN ");
} }
if (fl->fl_type & LOCK_MAND) { if (fl->fl_type & LOCK_MAND) {
out += sprintf(out, "%s ", seq_printf(f, "%s ",
(fl->fl_type & LOCK_READ) (fl->fl_type & LOCK_READ)
? (fl->fl_type & LOCK_WRITE) ? "RW " : "READ " ? (fl->fl_type & LOCK_WRITE) ? "RW " : "READ "
: (fl->fl_type & LOCK_WRITE) ? "WRITE" : "NONE "); : (fl->fl_type & LOCK_WRITE) ? "WRITE" : "NONE ");
} else { } else {
out += sprintf(out, "%s ", seq_printf(f, "%s ",
(fl->fl_type & F_INPROGRESS) (fl->fl_type & F_INPROGRESS)
? (fl->fl_type & F_UNLCK) ? "UNLCK" : "READ " ? (fl->fl_type & F_UNLCK) ? "UNLCK" : "READ "
: (fl->fl_type & F_WRLCK) ? "WRITE" : "READ "); : (fl->fl_type & F_WRLCK) ? "WRITE" : "READ ");
} }
if (inode) { if (inode) {
#ifdef WE_CAN_BREAK_LSLK_NOW #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); inode->i_sb->s_id, inode->i_ino);
#else #else
/* userspace relies on this representation of dev_t ;-( */ /* 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), MAJOR(inode->i_sb->s_dev),
MINOR(inode->i_sb->s_dev), inode->i_ino); MINOR(inode->i_sb->s_dev), inode->i_ino);
#endif #endif
} else { } else {
out += sprintf(out, "%d <none>:0 ", fl->fl_pid); seq_printf(f, "%d <none>:0 ", fl->fl_pid);
} }
if (IS_POSIX(fl)) { if (IS_POSIX(fl)) {
if (fl->fl_end == OFFSET_MAX) 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 else
out += sprintf(out, "%Ld %Ld\n", fl->fl_start, seq_printf(f, "%Ld %Ld\n", fl->fl_start, fl->fl_end);
fl->fl_end);
} else { } 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; struct file_lock *fl, *bfl;
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;
}
/** fl = list_entry(v, struct file_lock, fl_link);
* 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) lock_get_status(f, fl, (long)f->private, "");
{
struct list_head *tmp;
char *q = buffer;
off_t pos = 0;
int i = 0;
lock_kernel(); list_for_each_entry(bfl, &fl->fl_block, fl_block)
list_for_each(tmp, &file_lock_list) { lock_get_status(f, bfl, (long)f->private, " ->");
struct list_head *btmp;
struct file_lock *fl = list_entry(tmp, struct file_lock, fl_link); f->private++;
lock_get_status(q, fl, ++i, ""); return 0;
move_lock_status(&q, &pos, offset); }
if(pos >= offset+length) static void *locks_start(struct seq_file *f, loff_t *pos)
goto done; {
lock_kernel();
f->private = (void *)1;
return seq_list_start(&file_lock_list, *pos);
}
list_for_each(btmp, &fl->fl_block) { static void *locks_next(struct seq_file *f, void *v, loff_t *pos)
struct file_lock *bfl = list_entry(btmp, {
struct file_lock, fl_block); return seq_list_next(v, &file_lock_list, pos);
lock_get_status(q, bfl, i, " ->"); }
move_lock_status(&q, &pos, offset);
if(pos >= offset+length) static void locks_stop(struct seq_file *f, void *v)
goto done; {
}
}
done:
unlock_kernel(); unlock_kernel();
*start = buffer;
if(q-buffer < length)
return (q-buffer);
return length;
} }
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 * lock_may_read - checks that the region is free of locks
* @inode: the inode that is being read * @inode: the inode that is being read
......
...@@ -577,8 +577,7 @@ static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl) ...@@ -577,8 +577,7 @@ static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
nfs_inc_stats(inode, NFSIOS_VFSLOCK); nfs_inc_stats(inode, NFSIOS_VFSLOCK);
/* No mandatory locks over NFS */ /* No mandatory locks over NFS */
if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID && if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK)
fl->fl_type != F_UNLCK)
return -ENOLCK; return -ENOLCK;
if (IS_GETLK(cmd)) if (IS_GETLK(cmd))
......
...@@ -2035,7 +2035,7 @@ static inline int ...@@ -2035,7 +2035,7 @@ static inline int
io_during_grace_disallowed(struct inode *inode, int flags) io_during_grace_disallowed(struct inode *inode, int flags)
{ {
return nfs4_in_grace() && (flags & (RD_STATE | WR_STATE)) return nfs4_in_grace() && (flags & (RD_STATE | WR_STATE))
&& MANDATORY_LOCK(inode); && mandatory_lock(inode);
} }
/* /*
......
...@@ -61,12 +61,6 @@ ...@@ -61,12 +61,6 @@
#define NFSDDBG_FACILITY NFSDDBG_FILEOP #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 * This is a cache of readahead params that help us choose the proper
* readahead strategy. Initially, we set all readahead parameters to 0 * 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, ...@@ -689,7 +683,12 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
err = nfserr_perm; err = nfserr_perm;
if (IS_APPEND(inode) && (access & MAY_WRITE)) if (IS_APPEND(inode) && (access & MAY_WRITE))
goto out; 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; goto out;
if (!inode->i_fop) if (!inode->i_fop)
......
...@@ -66,7 +66,6 @@ extern int get_stram_list(char *); ...@@ -66,7 +66,6 @@ extern int get_stram_list(char *);
extern int get_filesystem_list(char *); extern int get_filesystem_list(char *);
extern int get_exec_domain_list(char *); extern int get_exec_domain_list(char *);
extern int get_dma_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, static int proc_calc_metrics(char *page, char **start, off_t off,
int count, int *eof, int len) int count, int *eof, int len)
...@@ -624,16 +623,18 @@ static int cmdline_read_proc(char *page, char **start, off_t off, ...@@ -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); return proc_calc_metrics(page, start, off, count, eof, len);
} }
static int locks_read_proc(char *page, char **start, off_t off, static int locks_open(struct inode *inode, struct file *filp)
int count, int *eof, void *data)
{ {
int len = get_locks_status(page, start, off, count); return seq_open(filp, &locks_seq_operations);
if (len < count)
*eof = 1;
return len;
} }
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, static int execdomains_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data) int count, int *eof, void *data)
{ {
...@@ -691,7 +692,6 @@ void __init proc_misc_init(void) ...@@ -691,7 +692,6 @@ void __init proc_misc_init(void)
#endif #endif
{"filesystems", filesystems_read_proc}, {"filesystems", filesystems_read_proc},
{"cmdline", cmdline_read_proc}, {"cmdline", cmdline_read_proc},
{"locks", locks_read_proc},
{"execdomains", execdomains_read_proc}, {"execdomains", execdomains_read_proc},
{NULL,} {NULL,}
}; };
...@@ -709,6 +709,7 @@ void __init proc_misc_init(void) ...@@ -709,6 +709,7 @@ void __init proc_misc_init(void)
entry->proc_fops = &proc_kmsg_operations; entry->proc_fops = &proc_kmsg_operations;
} }
#endif #endif
create_seq_entry("locks", 0, &proc_locks_operations);
create_seq_entry("devices", 0, &proc_devinfo_operations); create_seq_entry("devices", 0, &proc_devinfo_operations);
create_seq_entry("cpuinfo", 0, &proc_cpuinfo_operations); create_seq_entry("cpuinfo", 0, &proc_cpuinfo_operations);
#ifdef CONFIG_BLOCK #ifdef CONFIG_BLOCK
......
...@@ -205,7 +205,7 @@ int rw_verify_area(int read_write, struct file *file, loff_t *ppos, size_t count ...@@ -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)) if (unlikely((pos < 0) || (loff_t) (pos + count) < 0))
goto Einval; goto Einval;
if (unlikely(inode->i_flock && MANDATORY_LOCK(inode))) { if (unlikely(inode->i_flock && mandatory_lock(inode))) {
int retval = locks_mandatory_area( int retval = locks_mandatory_area(
read_write == READ ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE, read_write == READ ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE,
inode, file, pos, count); inode, file, pos, count);
......
...@@ -883,6 +883,7 @@ extern int vfs_setlease(struct file *, long, struct file_lock **); ...@@ -883,6 +883,7 @@ extern int vfs_setlease(struct file *, long, struct file_lock **);
extern int lease_modify(struct file_lock **, int); 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_read(struct inode *, loff_t start, unsigned long count);
extern int lock_may_write(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 { struct fasync_struct {
int magic; int magic;
...@@ -1375,12 +1376,25 @@ extern int locks_mandatory_area(int, struct inode *, struct file *, loff_t, size ...@@ -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 * Candidates for mandatory locking have the setgid bit set
* but no group execute bit - an otherwise meaningless combination. * 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) static inline int locks_verify_locked(struct inode *inode)
{ {
if (MANDATORY_LOCK(inode)) if (mandatory_lock(inode))
return locks_mandatory_locked(inode); return locks_mandatory_locked(inode);
return 0; return 0;
} }
...@@ -1391,7 +1405,7 @@ static inline int locks_verify_truncate(struct inode *inode, ...@@ -1391,7 +1405,7 @@ static inline int locks_verify_truncate(struct inode *inode,
struct file *filp, struct file *filp,
loff_t size) loff_t size)
{ {
if (inode->i_flock && MANDATORY_LOCK(inode)) if (inode->i_flock && mandatory_lock(inode))
return locks_mandatory_area( return locks_mandatory_area(
FLOCK_VERIFY_WRITE, inode, filp, FLOCK_VERIFY_WRITE, inode, filp,
size < inode->i_size ? size : inode->i_size, size < inode->i_size ? size : inode->i_size,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment