diff options
-rw-r--r-- | Documentation/00-INDEX | 6 | ||||
-rw-r--r-- | Documentation/filesystems/00-INDEX | 4 | ||||
-rw-r--r-- | Documentation/filesystems/locks.txt (renamed from Documentation/locks.txt) | 10 | ||||
-rw-r--r-- | Documentation/filesystems/mandatory-locking.txt (renamed from Documentation/mandatory.txt) | 21 | ||||
-rw-r--r-- | fs/9p/vfs_file.c | 2 | ||||
-rw-r--r-- | fs/afs/flock.c | 3 | ||||
-rw-r--r-- | fs/gfs2/ops_file.c | 4 | ||||
-rw-r--r-- | fs/locks.c | 192 | ||||
-rw-r--r-- | fs/nfs/file.c | 3 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 2 | ||||
-rw-r--r-- | fs/nfsd/vfs.c | 13 | ||||
-rw-r--r-- | fs/proc/proc_misc.c | 19 | ||||
-rw-r--r-- | fs/read_write.c | 2 | ||||
-rw-r--r-- | include/linux/fs.h | 22 |
14 files changed, 157 insertions, 146 deletions
diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX index 43e89b1537d9..cc10ce7dc339 100644 --- a/Documentation/00-INDEX +++ b/Documentation/00-INDEX | |||
@@ -145,7 +145,7 @@ fb/ | |||
145 | feature-removal-schedule.txt | 145 | feature-removal-schedule.txt |
146 | - list of files and features that are going to be removed. | 146 | - list of files and features that are going to be removed. |
147 | filesystems/ | 147 | filesystems/ |
148 | - directory with info on the various filesystems that Linux supports. | 148 | - info on the vfs and the various filesystems that Linux supports. |
149 | firmware_class/ | 149 | firmware_class/ |
150 | - request_firmware() hotplug interface info. | 150 | - request_firmware() hotplug interface info. |
151 | floppy.txt | 151 | floppy.txt |
@@ -230,8 +230,6 @@ local_ops.txt | |||
230 | - semantics and behavior of local atomic operations. | 230 | - semantics and behavior of local atomic operations. |
231 | lockdep-design.txt | 231 | lockdep-design.txt |
232 | - documentation on the runtime locking correctness validator. | 232 | - documentation on the runtime locking correctness validator. |
233 | locks.txt | ||
234 | - info on file locking implementations, flock() vs. fcntl(), etc. | ||
235 | logo.gif | 233 | logo.gif |
236 | - full colour GIF image of Linux logo (penguin - Tux). | 234 | - full colour GIF image of Linux logo (penguin - Tux). |
237 | logo.txt | 235 | logo.txt |
@@ -240,8 +238,6 @@ m68k/ | |||
240 | - directory with info about Linux on Motorola 68k architecture. | 238 | - directory with info about Linux on Motorola 68k architecture. |
241 | magic-number.txt | 239 | magic-number.txt |
242 | - list of magic numbers used to mark/protect kernel data structures. | 240 | - list of magic numbers used to mark/protect kernel data structures. |
243 | mandatory.txt | ||
244 | - info on the Linux implementation of Sys V mandatory file locking. | ||
245 | mca.txt | 241 | mca.txt |
246 | - info on supporting Micro Channel Architecture (e.g. PS/2) systems. | 242 | - info on supporting Micro Channel Architecture (e.g. PS/2) systems. |
247 | md.txt | 243 | md.txt |
diff --git a/Documentation/filesystems/00-INDEX b/Documentation/filesystems/00-INDEX index 59db1bca7027..599593a17067 100644 --- a/Documentation/filesystems/00-INDEX +++ b/Documentation/filesystems/00-INDEX | |||
@@ -52,6 +52,10 @@ isofs.txt | |||
52 | - info and mount options for the ISO 9660 (CDROM) filesystem. | 52 | - info and mount options for the ISO 9660 (CDROM) filesystem. |
53 | jfs.txt | 53 | jfs.txt |
54 | - info and mount options for the JFS filesystem. | 54 | - info and mount options for the JFS filesystem. |
55 | locks.txt | ||
56 | - info on file locking implementations, flock() vs. fcntl(), etc. | ||
57 | mandatory-locking.txt | ||
58 | - info on the Linux implementation of Sys V mandatory file locking. | ||
55 | ncpfs.txt | 59 | ncpfs.txt |
56 | - info on Novell Netware(tm) filesystem using NCP protocol. | 60 | - info on Novell Netware(tm) filesystem using NCP protocol. |
57 | ntfs.txt | 61 | ntfs.txt |
diff --git a/Documentation/locks.txt b/Documentation/filesystems/locks.txt index e3b402ef33bd..fab857accbd6 100644 --- a/Documentation/locks.txt +++ b/Documentation/filesystems/locks.txt | |||
@@ -53,11 +53,11 @@ fcntl(), with all the problems that implies. | |||
53 | 1.3 Mandatory Locking As A Mount Option | 53 | 1.3 Mandatory Locking As A Mount Option |
54 | --------------------------------------- | 54 | --------------------------------------- |
55 | 55 | ||
56 | Mandatory locking, as described in 'Documentation/mandatory.txt' was prior | 56 | Mandatory locking, as described in 'Documentation/filesystems/mandatory.txt' |
57 | to this release a general configuration option that was valid for all | 57 | was prior to this release a general configuration option that was valid for |
58 | mounted filesystems. This had a number of inherent dangers, not the least | 58 | all mounted filesystems. This had a number of inherent dangers, not the |
59 | of which was the ability to freeze an NFS server by asking it to read a | 59 | least of which was the ability to freeze an NFS server by asking it to read |
60 | file for which a mandatory lock existed. | 60 | a file for which a mandatory lock existed. |
61 | 61 | ||
62 | From this release of the kernel, mandatory locking can be turned on and off | 62 | From this release of the kernel, mandatory locking can be turned on and off |
63 | on a per-filesystem basis, using the mount options 'mand' and 'nomand'. | 63 | on a per-filesystem basis, using the mount options 'mand' and 'nomand'. |
diff --git a/Documentation/mandatory.txt b/Documentation/filesystems/mandatory-locking.txt index bc449d49eee5..0979d1d2ca8b 100644 --- a/Documentation/mandatory.txt +++ b/Documentation/filesystems/mandatory-locking.txt | |||
@@ -3,7 +3,26 @@ | |||
3 | Andy Walker <andy@lysaker.kvaerner.no> | 3 | Andy Walker <andy@lysaker.kvaerner.no> |
4 | 4 | ||
5 | 15 April 1996 | 5 | 15 April 1996 |
6 | 6 | (Updated September 2007) | |
7 | |||
8 | 0. Why you should avoid mandatory locking | ||
9 | ----------------------------------------- | ||
10 | |||
11 | The Linux implementation is prey to a number of difficult-to-fix race | ||
12 | conditions which in practice make it not dependable: | ||
13 | |||
14 | - The write system call checks for a mandatory lock only once | ||
15 | at its start. It is therefore possible for a lock request to | ||
16 | be granted after this check but before the data is modified. | ||
17 | A process may then see file data change even while a mandatory | ||
18 | lock was held. | ||
19 | - Similarly, an exclusive lock may be granted on a file after | ||
20 | the kernel has decided to proceed with a read, but before the | ||
21 | read has actually completed, and the reading process may see | ||
22 | the file data in a state which should not have been visible | ||
23 | to it. | ||
24 | - Similar races make the claimed mutual exclusion between lock | ||
25 | and mmap similarly unreliable. | ||
7 | 26 | ||
8 | 1. What is mandatory locking? | 27 | 1. What is mandatory locking? |
9 | ------------------------------ | 28 | ------------------------------ |
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c index 2a40c2946d0a..716691689fd5 100644 --- a/fs/9p/vfs_file.c +++ b/fs/9p/vfs_file.c | |||
@@ -105,7 +105,7 @@ static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl) | |||
105 | P9_DPRINTK(P9_DEBUG_VFS, "filp: %p lock: %p\n", filp, fl); | 105 | P9_DPRINTK(P9_DEBUG_VFS, "filp: %p lock: %p\n", filp, fl); |
106 | 106 | ||
107 | /* No mandatory locks */ | 107 | /* No mandatory locks */ |
108 | if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) | 108 | if (__mandatory_lock(inode)) |
109 | return -ENOLCK; | 109 | return -ENOLCK; |
110 | 110 | ||
111 | if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) { | 111 | if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) { |
diff --git a/fs/afs/flock.c b/fs/afs/flock.c index af6952e39a18..210acafe4a9b 100644 --- a/fs/afs/flock.c +++ b/fs/afs/flock.c | |||
@@ -524,8 +524,7 @@ int afs_lock(struct file *file, int cmd, struct file_lock *fl) | |||
524 | (long long) fl->fl_start, (long long) fl->fl_end); | 524 | (long long) fl->fl_start, (long long) fl->fl_end); |
525 | 525 | ||
526 | /* AFS doesn't support mandatory locks */ | 526 | /* AFS doesn't support mandatory locks */ |
527 | if ((vnode->vfs_inode.i_mode & (S_ISGID | S_IXGRP)) == S_ISGID && | 527 | if (__mandatory_lock(&vnode->vfs_inode) && fl->fl_type != F_UNLCK) |
528 | fl->fl_type != F_UNLCK) | ||
529 | return -ENOLCK; | 528 | return -ENOLCK; |
530 | 529 | ||
531 | if (IS_GETLK(cmd)) | 530 | if (IS_GETLK(cmd)) |
diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index 46a9e10ff17b..7eb4b280ac66 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c | |||
@@ -535,7 +535,7 @@ static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl) | |||
535 | 535 | ||
536 | if (!(fl->fl_flags & FL_POSIX)) | 536 | if (!(fl->fl_flags & FL_POSIX)) |
537 | return -ENOLCK; | 537 | return -ENOLCK; |
538 | if ((ip->i_inode.i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) | 538 | if (__mandatory_lock(&ip->i_inode)) |
539 | return -ENOLCK; | 539 | return -ENOLCK; |
540 | 540 | ||
541 | if (sdp->sd_args.ar_localflocks) { | 541 | if (sdp->sd_args.ar_localflocks) { |
@@ -636,7 +636,7 @@ static int gfs2_flock(struct file *file, int cmd, struct file_lock *fl) | |||
636 | 636 | ||
637 | if (!(fl->fl_flags & FL_FLOCK)) | 637 | if (!(fl->fl_flags & FL_FLOCK)) |
638 | return -ENOLCK; | 638 | return -ENOLCK; |
639 | if ((ip->i_inode.i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) | 639 | if (__mandatory_lock(&ip->i_inode)) |
640 | return -ENOLCK; | 640 | return -ENOLCK; |
641 | 641 | ||
642 | if (sdp->sd_args.ar_localflocks) | 642 | if (sdp->sd_args.ar_localflocks) |
diff --git a/fs/locks.c b/fs/locks.c index c795eaaf6c4c..7f9a3ea47418 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
@@ -534,7 +534,9 @@ static void locks_insert_block(struct file_lock *blocker, | |||
534 | static void locks_wake_up_blocks(struct file_lock *blocker) | 534 | static void locks_wake_up_blocks(struct file_lock *blocker) |
535 | { | 535 | { |
536 | while (!list_empty(&blocker->fl_block)) { | 536 | while (!list_empty(&blocker->fl_block)) { |
537 | struct file_lock *waiter = list_entry(blocker->fl_block.next, | 537 | struct file_lock *waiter; |
538 | |||
539 | waiter = list_first_entry(&blocker->fl_block, | ||
538 | struct file_lock, fl_block); | 540 | struct file_lock, fl_block); |
539 | __locks_delete_block(waiter); | 541 | __locks_delete_block(waiter); |
540 | if (waiter->fl_lmops && waiter->fl_lmops->fl_notify) | 542 | if (waiter->fl_lmops && waiter->fl_lmops->fl_notify) |
@@ -668,7 +670,7 @@ posix_test_lock(struct file *filp, struct file_lock *fl) | |||
668 | for (cfl = filp->f_path.dentry->d_inode->i_flock; cfl; cfl = cfl->fl_next) { | 670 | for (cfl = filp->f_path.dentry->d_inode->i_flock; cfl; cfl = cfl->fl_next) { |
669 | if (!IS_POSIX(cfl)) | 671 | if (!IS_POSIX(cfl)) |
670 | continue; | 672 | continue; |
671 | if (posix_locks_conflict(cfl, fl)) | 673 | if (posix_locks_conflict(fl, cfl)) |
672 | break; | 674 | break; |
673 | } | 675 | } |
674 | if (cfl) | 676 | if (cfl) |
@@ -698,13 +700,12 @@ EXPORT_SYMBOL(posix_test_lock); | |||
698 | static int posix_locks_deadlock(struct file_lock *caller_fl, | 700 | static int posix_locks_deadlock(struct file_lock *caller_fl, |
699 | struct file_lock *block_fl) | 701 | struct file_lock *block_fl) |
700 | { | 702 | { |
701 | struct list_head *tmp; | 703 | struct file_lock *fl; |
702 | 704 | ||
703 | next_task: | 705 | next_task: |
704 | if (posix_same_owner(caller_fl, block_fl)) | 706 | if (posix_same_owner(caller_fl, block_fl)) |
705 | return 1; | 707 | return 1; |
706 | list_for_each(tmp, &blocked_list) { | 708 | list_for_each_entry(fl, &blocked_list, fl_link) { |
707 | struct file_lock *fl = list_entry(tmp, struct file_lock, fl_link); | ||
708 | if (posix_same_owner(fl, block_fl)) { | 709 | if (posix_same_owner(fl, block_fl)) { |
709 | fl = fl->fl_next; | 710 | fl = fl->fl_next; |
710 | block_fl = fl; | 711 | block_fl = fl; |
@@ -715,8 +716,7 @@ next_task: | |||
715 | } | 716 | } |
716 | 717 | ||
717 | /* Try to create a FLOCK lock on filp. We always insert new FLOCK locks | 718 | /* Try to create a FLOCK lock on filp. We always insert new FLOCK locks |
718 | * at the head of the list, but that's secret knowledge known only to | 719 | * after any leases, but before any posix locks. |
719 | * flock_lock_file and posix_lock_file. | ||
720 | * | 720 | * |
721 | * Note that if called with an FL_EXISTS argument, the caller may determine | 721 | * Note that if called with an FL_EXISTS argument, the caller may determine |
722 | * whether or not a lock was successfully freed by testing the return | 722 | * 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 | lock_kernel(); | 733 | lock_kernel(); |
734 | if (request->fl_flags & FL_ACCESS) | 734 | if (request->fl_flags & FL_ACCESS) |
735 | goto find_conflict; | 735 | goto find_conflict; |
736 | |||
737 | if (request->fl_type != F_UNLCK) { | ||
738 | error = -ENOMEM; | ||
739 | new_fl = locks_alloc_lock(); | ||
740 | if (new_fl == NULL) | ||
741 | goto out; | ||
742 | error = 0; | ||
743 | } | ||
744 | |||
736 | for_each_lock(inode, before) { | 745 | for_each_lock(inode, before) { |
737 | struct file_lock *fl = *before; | 746 | struct file_lock *fl = *before; |
738 | if (IS_POSIX(fl)) | 747 | if (IS_POSIX(fl)) |
@@ -754,10 +763,6 @@ static int flock_lock_file(struct file *filp, struct file_lock *request) | |||
754 | goto out; | 763 | goto out; |
755 | } | 764 | } |
756 | 765 | ||
757 | error = -ENOMEM; | ||
758 | new_fl = locks_alloc_lock(); | ||
759 | if (new_fl == NULL) | ||
760 | goto out; | ||
761 | /* | 766 | /* |
762 | * If a higher-priority process was blocked on the old file lock, | 767 | * If a higher-priority process was blocked on the old file lock, |
763 | * give it the opportunity to lock the file. | 768 | * 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 | lock_kernel(); | 824 | lock_kernel(); |
820 | if (request->fl_type != F_UNLCK) { | 825 | if (request->fl_type != F_UNLCK) { |
821 | for_each_lock(inode, before) { | 826 | for_each_lock(inode, before) { |
822 | struct file_lock *fl = *before; | 827 | fl = *before; |
823 | if (!IS_POSIX(fl)) | 828 | if (!IS_POSIX(fl)) |
824 | continue; | 829 | continue; |
825 | if (!posix_locks_conflict(request, fl)) | 830 | if (!posix_locks_conflict(request, fl)) |
@@ -1113,7 +1118,7 @@ int locks_mandatory_area(int read_write, struct inode *inode, | |||
1113 | * If we've been sleeping someone might have | 1118 | * If we've been sleeping someone might have |
1114 | * changed the permissions behind our back. | 1119 | * changed the permissions behind our back. |
1115 | */ | 1120 | */ |
1116 | if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) | 1121 | if (__mandatory_lock(inode)) |
1117 | continue; | 1122 | continue; |
1118 | } | 1123 | } |
1119 | 1124 | ||
@@ -1337,6 +1342,7 @@ int fcntl_getlease(struct file *filp) | |||
1337 | int generic_setlease(struct file *filp, long arg, struct file_lock **flp) | 1342 | int generic_setlease(struct file *filp, long arg, struct file_lock **flp) |
1338 | { | 1343 | { |
1339 | struct file_lock *fl, **before, **my_before = NULL, *lease; | 1344 | struct file_lock *fl, **before, **my_before = NULL, *lease; |
1345 | struct file_lock *new_fl = NULL; | ||
1340 | struct dentry *dentry = filp->f_path.dentry; | 1346 | struct dentry *dentry = filp->f_path.dentry; |
1341 | struct inode *inode = dentry->d_inode; | 1347 | struct inode *inode = dentry->d_inode; |
1342 | int error, rdlease_count = 0, wrlease_count = 0; | 1348 | 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 | || (atomic_read(&inode->i_count) > 1))) | 1369 | || (atomic_read(&inode->i_count) > 1))) |
1364 | goto out; | 1370 | goto out; |
1365 | 1371 | ||
1372 | error = -ENOMEM; | ||
1373 | new_fl = locks_alloc_lock(); | ||
1374 | if (new_fl == NULL) | ||
1375 | goto out; | ||
1376 | |||
1366 | /* | 1377 | /* |
1367 | * At this point, we know that if there is an exclusive | 1378 | * At this point, we know that if there is an exclusive |
1368 | * lease on this file, then we hold it on this filp | 1379 | * 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 | if (!leases_enable) | 1416 | if (!leases_enable) |
1406 | goto out; | 1417 | goto out; |
1407 | 1418 | ||
1408 | error = -ENOMEM; | 1419 | locks_copy_lock(new_fl, lease); |
1409 | fl = locks_alloc_lock(); | 1420 | locks_insert_lock(before, new_fl); |
1410 | if (fl == NULL) | ||
1411 | goto out; | ||
1412 | |||
1413 | locks_copy_lock(fl, lease); | ||
1414 | 1421 | ||
1415 | locks_insert_lock(before, fl); | 1422 | *flp = new_fl; |
1423 | return 0; | ||
1416 | 1424 | ||
1417 | *flp = fl; | ||
1418 | error = 0; | ||
1419 | out: | 1425 | out: |
1426 | if (new_fl != NULL) | ||
1427 | locks_free_lock(new_fl); | ||
1420 | return error; | 1428 | return error; |
1421 | } | 1429 | } |
1422 | EXPORT_SYMBOL(generic_setlease); | 1430 | EXPORT_SYMBOL(generic_setlease); |
@@ -1752,9 +1760,7 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd, | |||
1752 | /* Don't allow mandatory locks on files that may be memory mapped | 1760 | /* Don't allow mandatory locks on files that may be memory mapped |
1753 | * and shared. | 1761 | * and shared. |
1754 | */ | 1762 | */ |
1755 | if (IS_MANDLOCK(inode) && | 1763 | if (mandatory_lock(inode) && mapping_writably_mapped(filp->f_mapping)) { |
1756 | (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID && | ||
1757 | mapping_writably_mapped(filp->f_mapping)) { | ||
1758 | error = -EAGAIN; | 1764 | error = -EAGAIN; |
1759 | goto out; | 1765 | goto out; |
1760 | } | 1766 | } |
@@ -1878,9 +1884,7 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd, | |||
1878 | /* Don't allow mandatory locks on files that may be memory mapped | 1884 | /* Don't allow mandatory locks on files that may be memory mapped |
1879 | * and shared. | 1885 | * and shared. |
1880 | */ | 1886 | */ |
1881 | if (IS_MANDLOCK(inode) && | 1887 | if (mandatory_lock(inode) && mapping_writably_mapped(filp->f_mapping)) { |
1882 | (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID && | ||
1883 | mapping_writably_mapped(filp->f_mapping)) { | ||
1884 | error = -EAGAIN; | 1888 | error = -EAGAIN; |
1885 | goto out; | 1889 | goto out; |
1886 | } | 1890 | } |
@@ -2062,138 +2066,114 @@ int vfs_cancel_lock(struct file *filp, struct file_lock *fl) | |||
2062 | 2066 | ||
2063 | EXPORT_SYMBOL_GPL(vfs_cancel_lock); | 2067 | EXPORT_SYMBOL_GPL(vfs_cancel_lock); |
2064 | 2068 | ||
2065 | static void lock_get_status(char* out, struct file_lock *fl, int id, char *pfx) | 2069 | #ifdef CONFIG_PROC_FS |
2070 | #include <linux/seq_file.h> | ||
2071 | |||
2072 | static void lock_get_status(struct seq_file *f, struct file_lock *fl, | ||
2073 | int id, char *pfx) | ||
2066 | { | 2074 | { |
2067 | struct inode *inode = NULL; | 2075 | struct inode *inode = NULL; |
2068 | 2076 | ||
2069 | if (fl->fl_file != NULL) | 2077 | if (fl->fl_file != NULL) |
2070 | inode = fl->fl_file->f_path.dentry->d_inode; | 2078 | inode = fl->fl_file->f_path.dentry->d_inode; |
2071 | 2079 | ||
2072 | out += sprintf(out, "%d:%s ", id, pfx); | 2080 | seq_printf(f, "%d:%s ", id, pfx); |
2073 | if (IS_POSIX(fl)) { | 2081 | if (IS_POSIX(fl)) { |
2074 | out += sprintf(out, "%6s %s ", | 2082 | seq_printf(f, "%6s %s ", |
2075 | (fl->fl_flags & FL_ACCESS) ? "ACCESS" : "POSIX ", | 2083 | (fl->fl_flags & FL_ACCESS) ? "ACCESS" : "POSIX ", |
2076 | (inode == NULL) ? "*NOINODE*" : | 2084 | (inode == NULL) ? "*NOINODE*" : |
2077 | (IS_MANDLOCK(inode) && | 2085 | mandatory_lock(inode) ? "MANDATORY" : "ADVISORY "); |
2078 | (inode->i_mode & (S_IXGRP | S_ISGID)) == S_ISGID) ? | ||
2079 | "MANDATORY" : "ADVISORY "); | ||
2080 | } else if (IS_FLOCK(fl)) { | 2086 | } else if (IS_FLOCK(fl)) { |
2081 | if (fl->fl_type & LOCK_MAND) { | 2087 | if (fl->fl_type & LOCK_MAND) { |
2082 | out += sprintf(out, "FLOCK MSNFS "); | 2088 | seq_printf(f, "FLOCK MSNFS "); |
2083 | } else { | 2089 | } else { |
2084 | out += sprintf(out, "FLOCK ADVISORY "); | 2090 | seq_printf(f, "FLOCK ADVISORY "); |
2085 | } | 2091 | } |
2086 | } else if (IS_LEASE(fl)) { | 2092 | } else if (IS_LEASE(fl)) { |
2087 | out += sprintf(out, "LEASE "); | 2093 | seq_printf(f, "LEASE "); |
2088 | if (fl->fl_type & F_INPROGRESS) | 2094 | if (fl->fl_type & F_INPROGRESS) |
2089 | out += sprintf(out, "BREAKING "); | 2095 | seq_printf(f, "BREAKING "); |
2090 | else if (fl->fl_file) | 2096 | else if (fl->fl_file) |
2091 | out += sprintf(out, "ACTIVE "); | 2097 | seq_printf(f, "ACTIVE "); |
2092 | else | 2098 | else |
2093 | out += sprintf(out, "BREAKER "); | 2099 | seq_printf(f, "BREAKER "); |
2094 | } else { | 2100 | } else { |
2095 | out += sprintf(out, "UNKNOWN UNKNOWN "); | 2101 | seq_printf(f, "UNKNOWN UNKNOWN "); |
2096 | } | 2102 | } |
2097 | if (fl->fl_type & LOCK_MAND) { | 2103 | if (fl->fl_type & LOCK_MAND) { |
2098 | out += sprintf(out, "%s ", | 2104 | seq_printf(f, "%s ", |
2099 | (fl->fl_type & LOCK_READ) | 2105 | (fl->fl_type & LOCK_READ) |
2100 | ? (fl->fl_type & LOCK_WRITE) ? "RW " : "READ " | 2106 | ? (fl->fl_type & LOCK_WRITE) ? "RW " : "READ " |
2101 | : (fl->fl_type & LOCK_WRITE) ? "WRITE" : "NONE "); | 2107 | : (fl->fl_type & LOCK_WRITE) ? "WRITE" : "NONE "); |
2102 | } else { | 2108 | } else { |
2103 | out += sprintf(out, "%s ", | 2109 | seq_printf(f, "%s ", |
2104 | (fl->fl_type & F_INPROGRESS) | 2110 | (fl->fl_type & F_INPROGRESS) |
2105 | ? (fl->fl_type & F_UNLCK) ? "UNLCK" : "READ " | 2111 | ? (fl->fl_type & F_UNLCK) ? "UNLCK" : "READ " |
2106 | : (fl->fl_type & F_WRLCK) ? "WRITE" : "READ "); | 2112 | : (fl->fl_type & F_WRLCK) ? "WRITE" : "READ "); |
2107 | } | 2113 | } |
2108 | if (inode) { | 2114 | if (inode) { |
2109 | #ifdef WE_CAN_BREAK_LSLK_NOW | 2115 | #ifdef WE_CAN_BREAK_LSLK_NOW |
2110 | out += sprintf(out, "%d %s:%ld ", fl->fl_pid, | 2116 | seq_printf(f, "%d %s:%ld ", fl->fl_pid, |
2111 | inode->i_sb->s_id, inode->i_ino); | 2117 | inode->i_sb->s_id, inode->i_ino); |
2112 | #else | 2118 | #else |
2113 | /* userspace relies on this representation of dev_t ;-( */ | 2119 | /* userspace relies on this representation of dev_t ;-( */ |
2114 | out += sprintf(out, "%d %02x:%02x:%ld ", fl->fl_pid, | 2120 | seq_printf(f, "%d %02x:%02x:%ld ", fl->fl_pid, |
2115 | MAJOR(inode->i_sb->s_dev), | 2121 | MAJOR(inode->i_sb->s_dev), |
2116 | MINOR(inode->i_sb->s_dev), inode->i_ino); | 2122 | MINOR(inode->i_sb->s_dev), inode->i_ino); |
2117 | #endif | 2123 | #endif |
2118 | } else { | 2124 | } else { |
2119 | out += sprintf(out, "%d <none>:0 ", fl->fl_pid); | 2125 | seq_printf(f, "%d <none>:0 ", fl->fl_pid); |
2120 | } | 2126 | } |
2121 | if (IS_POSIX(fl)) { | 2127 | if (IS_POSIX(fl)) { |
2122 | if (fl->fl_end == OFFSET_MAX) | 2128 | if (fl->fl_end == OFFSET_MAX) |
2123 | out += sprintf(out, "%Ld EOF\n", fl->fl_start); | 2129 | seq_printf(f, "%Ld EOF\n", fl->fl_start); |
2124 | else | 2130 | else |
2125 | out += sprintf(out, "%Ld %Ld\n", fl->fl_start, | 2131 | seq_printf(f, "%Ld %Ld\n", fl->fl_start, fl->fl_end); |
2126 | fl->fl_end); | ||
2127 | } else { | 2132 | } else { |
2128 | out += sprintf(out, "0 EOF\n"); | 2133 | seq_printf(f, "0 EOF\n"); |
2129 | } | 2134 | } |
2130 | } | 2135 | } |
2131 | 2136 | ||
2132 | static void move_lock_status(char **p, off_t* pos, off_t offset) | 2137 | static int locks_show(struct seq_file *f, void *v) |
2133 | { | 2138 | { |
2134 | int len; | 2139 | struct file_lock *fl, *bfl; |
2135 | len = strlen(*p); | 2140 | |
2136 | if(*pos >= offset) { | 2141 | fl = list_entry(v, struct file_lock, fl_link); |
2137 | /* the complete line is valid */ | 2142 | |
2138 | *p += len; | 2143 | lock_get_status(f, fl, (long)f->private, ""); |
2139 | *pos += len; | 2144 | |
2140 | return; | 2145 | list_for_each_entry(bfl, &fl->fl_block, fl_block) |
2141 | } | 2146 | lock_get_status(f, bfl, (long)f->private, " ->"); |
2142 | if(*pos+len > offset) { | 2147 | |
2143 | /* use the second part of the line */ | 2148 | f->private++; |
2144 | int i = offset-*pos; | 2149 | return 0; |
2145 | memmove(*p,*p+i,len-i); | ||
2146 | *p += len-i; | ||
2147 | *pos += len; | ||
2148 | return; | ||
2149 | } | ||
2150 | /* discard the complete line */ | ||
2151 | *pos += len; | ||
2152 | } | 2150 | } |
2153 | 2151 | ||
2154 | /** | 2152 | static void *locks_start(struct seq_file *f, loff_t *pos) |
2155 | * get_locks_status - reports lock usage in /proc/locks | 2153 | { |
2156 | * @buffer: address in userspace to write into | 2154 | lock_kernel(); |
2157 | * @start: ? | 2155 | f->private = (void *)1; |
2158 | * @offset: how far we are through the buffer | 2156 | return seq_list_start(&file_lock_list, *pos); |
2159 | * @length: how much to read | 2157 | } |
2160 | */ | ||
2161 | 2158 | ||
2162 | int get_locks_status(char *buffer, char **start, off_t offset, int length) | 2159 | static void *locks_next(struct seq_file *f, void *v, loff_t *pos) |
2163 | { | 2160 | { |
2164 | struct list_head *tmp; | 2161 | return seq_list_next(v, &file_lock_list, pos); |
2165 | char *q = buffer; | 2162 | } |
2166 | off_t pos = 0; | ||
2167 | int i = 0; | ||
2168 | 2163 | ||
2169 | lock_kernel(); | 2164 | static void locks_stop(struct seq_file *f, void *v) |
2170 | list_for_each(tmp, &file_lock_list) { | 2165 | { |
2171 | struct list_head *btmp; | ||
2172 | struct file_lock *fl = list_entry(tmp, struct file_lock, fl_link); | ||
2173 | lock_get_status(q, fl, ++i, ""); | ||
2174 | move_lock_status(&q, &pos, offset); | ||
2175 | |||
2176 | if(pos >= offset+length) | ||
2177 | goto done; | ||
2178 | |||
2179 | list_for_each(btmp, &fl->fl_block) { | ||
2180 | struct file_lock *bfl = list_entry(btmp, | ||
2181 | struct file_lock, fl_block); | ||
2182 | lock_get_status(q, bfl, i, " ->"); | ||
2183 | move_lock_status(&q, &pos, offset); | ||
2184 | |||
2185 | if(pos >= offset+length) | ||
2186 | goto done; | ||
2187 | } | ||
2188 | } | ||
2189 | done: | ||
2190 | unlock_kernel(); | 2166 | unlock_kernel(); |
2191 | *start = buffer; | ||
2192 | if(q-buffer < length) | ||
2193 | return (q-buffer); | ||
2194 | return length; | ||
2195 | } | 2167 | } |
2196 | 2168 | ||
2169 | struct seq_operations locks_seq_operations = { | ||
2170 | .start = locks_start, | ||
2171 | .next = locks_next, | ||
2172 | .stop = locks_stop, | ||
2173 | .show = locks_show, | ||
2174 | }; | ||
2175 | #endif | ||
2176 | |||
2197 | /** | 2177 | /** |
2198 | * lock_may_read - checks that the region is free of locks | 2178 | * lock_may_read - checks that the region is free of locks |
2199 | * @inode: the inode that is being read | 2179 | * @inode: the inode that is being read |
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index c664bb921425..08c7c7387fce 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
@@ -577,8 +577,7 @@ static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl) | |||
577 | nfs_inc_stats(inode, NFSIOS_VFSLOCK); | 577 | nfs_inc_stats(inode, NFSIOS_VFSLOCK); |
578 | 578 | ||
579 | /* No mandatory locks over NFS */ | 579 | /* No mandatory locks over NFS */ |
580 | if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID && | 580 | if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK) |
581 | fl->fl_type != F_UNLCK) | ||
582 | return -ENOLCK; | 581 | return -ENOLCK; |
583 | 582 | ||
584 | if (IS_GETLK(cmd)) | 583 | if (IS_GETLK(cmd)) |
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 6f182d25793d..31673cd251c3 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -2035,7 +2035,7 @@ static inline int | |||
2035 | io_during_grace_disallowed(struct inode *inode, int flags) | 2035 | io_during_grace_disallowed(struct inode *inode, int flags) |
2036 | { | 2036 | { |
2037 | return nfs4_in_grace() && (flags & (RD_STATE | WR_STATE)) | 2037 | return nfs4_in_grace() && (flags & (RD_STATE | WR_STATE)) |
2038 | && MANDATORY_LOCK(inode); | 2038 | && mandatory_lock(inode); |
2039 | } | 2039 | } |
2040 | 2040 | ||
2041 | /* | 2041 | /* |
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index cec78c82b1f9..2a8d665b134b 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
@@ -61,12 +61,6 @@ | |||
61 | #define NFSDDBG_FACILITY NFSDDBG_FILEOP | 61 | #define NFSDDBG_FACILITY NFSDDBG_FILEOP |
62 | 62 | ||
63 | 63 | ||
64 | /* We must ignore files (but only files) which might have mandatory | ||
65 | * locks on them because there is no way to know if the accesser has | ||
66 | * the lock. | ||
67 | */ | ||
68 | #define IS_ISMNDLK(i) (S_ISREG((i)->i_mode) && MANDATORY_LOCK(i)) | ||
69 | |||
70 | /* | 64 | /* |
71 | * This is a cache of readahead params that help us choose the proper | 65 | * This is a cache of readahead params that help us choose the proper |
72 | * readahead strategy. Initially, we set all readahead parameters to 0 | 66 | * 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 | err = nfserr_perm; | 683 | err = nfserr_perm; |
690 | if (IS_APPEND(inode) && (access & MAY_WRITE)) | 684 | if (IS_APPEND(inode) && (access & MAY_WRITE)) |
691 | goto out; | 685 | goto out; |
692 | if (IS_ISMNDLK(inode)) | 686 | /* |
687 | * We must ignore files (but only files) which might have mandatory | ||
688 | * locks on them because there is no way to know if the accesser has | ||
689 | * the lock. | ||
690 | */ | ||
691 | if (S_ISREG((inode)->i_mode) && mandatory_lock(inode)) | ||
693 | goto out; | 692 | goto out; |
694 | 693 | ||
695 | if (!inode->i_fop) | 694 | if (!inode->i_fop) |
diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index b872a01ad3af..0071939c0095 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c | |||
@@ -66,7 +66,6 @@ extern int get_stram_list(char *); | |||
66 | extern int get_filesystem_list(char *); | 66 | extern int get_filesystem_list(char *); |
67 | extern int get_exec_domain_list(char *); | 67 | extern int get_exec_domain_list(char *); |
68 | extern int get_dma_list(char *); | 68 | extern int get_dma_list(char *); |
69 | extern int get_locks_status (char *, char **, off_t, int); | ||
70 | 69 | ||
71 | static int proc_calc_metrics(char *page, char **start, off_t off, | 70 | static int proc_calc_metrics(char *page, char **start, off_t off, |
72 | int count, int *eof, int len) | 71 | int count, int *eof, int len) |
@@ -624,16 +623,18 @@ static int cmdline_read_proc(char *page, char **start, off_t off, | |||
624 | return proc_calc_metrics(page, start, off, count, eof, len); | 623 | return proc_calc_metrics(page, start, off, count, eof, len); |
625 | } | 624 | } |
626 | 625 | ||
627 | static int locks_read_proc(char *page, char **start, off_t off, | 626 | static int locks_open(struct inode *inode, struct file *filp) |
628 | int count, int *eof, void *data) | ||
629 | { | 627 | { |
630 | int len = get_locks_status(page, start, off, count); | 628 | return seq_open(filp, &locks_seq_operations); |
631 | |||
632 | if (len < count) | ||
633 | *eof = 1; | ||
634 | return len; | ||
635 | } | 629 | } |
636 | 630 | ||
631 | static const struct file_operations proc_locks_operations = { | ||
632 | .open = locks_open, | ||
633 | .read = seq_read, | ||
634 | .llseek = seq_lseek, | ||
635 | .release = seq_release, | ||
636 | }; | ||
637 | |||
637 | static int execdomains_read_proc(char *page, char **start, off_t off, | 638 | static int execdomains_read_proc(char *page, char **start, off_t off, |
638 | int count, int *eof, void *data) | 639 | int count, int *eof, void *data) |
639 | { | 640 | { |
@@ -691,7 +692,6 @@ void __init proc_misc_init(void) | |||
691 | #endif | 692 | #endif |
692 | {"filesystems", filesystems_read_proc}, | 693 | {"filesystems", filesystems_read_proc}, |
693 | {"cmdline", cmdline_read_proc}, | 694 | {"cmdline", cmdline_read_proc}, |
694 | {"locks", locks_read_proc}, | ||
695 | {"execdomains", execdomains_read_proc}, | 695 | {"execdomains", execdomains_read_proc}, |
696 | {NULL,} | 696 | {NULL,} |
697 | }; | 697 | }; |
@@ -709,6 +709,7 @@ void __init proc_misc_init(void) | |||
709 | entry->proc_fops = &proc_kmsg_operations; | 709 | entry->proc_fops = &proc_kmsg_operations; |
710 | } | 710 | } |
711 | #endif | 711 | #endif |
712 | create_seq_entry("locks", 0, &proc_locks_operations); | ||
712 | create_seq_entry("devices", 0, &proc_devinfo_operations); | 713 | create_seq_entry("devices", 0, &proc_devinfo_operations); |
713 | create_seq_entry("cpuinfo", 0, &proc_cpuinfo_operations); | 714 | create_seq_entry("cpuinfo", 0, &proc_cpuinfo_operations); |
714 | #ifdef CONFIG_BLOCK | 715 | #ifdef CONFIG_BLOCK |
diff --git a/fs/read_write.c b/fs/read_write.c index 507ddff48a9a..124693e8d3fa 100644 --- a/fs/read_write.c +++ b/fs/read_write.c | |||
@@ -205,7 +205,7 @@ int rw_verify_area(int read_write, struct file *file, loff_t *ppos, size_t count | |||
205 | if (unlikely((pos < 0) || (loff_t) (pos + count) < 0)) | 205 | if (unlikely((pos < 0) || (loff_t) (pos + count) < 0)) |
206 | goto Einval; | 206 | goto Einval; |
207 | 207 | ||
208 | if (unlikely(inode->i_flock && MANDATORY_LOCK(inode))) { | 208 | if (unlikely(inode->i_flock && mandatory_lock(inode))) { |
209 | int retval = locks_mandatory_area( | 209 | int retval = locks_mandatory_area( |
210 | read_write == READ ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE, | 210 | read_write == READ ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE, |
211 | inode, file, pos, count); | 211 | inode, file, pos, count); |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 6d760f1ad875..4a6a21077bae 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -883,6 +883,7 @@ extern int vfs_setlease(struct file *, long, struct file_lock **); | |||
883 | extern int lease_modify(struct file_lock **, int); | 883 | extern int lease_modify(struct file_lock **, int); |
884 | extern int lock_may_read(struct inode *, loff_t start, unsigned long count); | 884 | extern int lock_may_read(struct inode *, loff_t start, unsigned long count); |
885 | extern int lock_may_write(struct inode *, loff_t start, unsigned long count); | 885 | extern int lock_may_write(struct inode *, loff_t start, unsigned long count); |
886 | extern struct seq_operations locks_seq_operations; | ||
886 | 887 | ||
887 | struct fasync_struct { | 888 | struct fasync_struct { |
888 | int magic; | 889 | int magic; |
@@ -1375,12 +1376,25 @@ extern int locks_mandatory_area(int, struct inode *, struct file *, loff_t, size | |||
1375 | * Candidates for mandatory locking have the setgid bit set | 1376 | * Candidates for mandatory locking have the setgid bit set |
1376 | * but no group execute bit - an otherwise meaningless combination. | 1377 | * but no group execute bit - an otherwise meaningless combination. |
1377 | */ | 1378 | */ |
1378 | #define MANDATORY_LOCK(inode) \ | 1379 | |
1379 | (IS_MANDLOCK(inode) && ((inode)->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) | 1380 | static inline int __mandatory_lock(struct inode *ino) |
1381 | { | ||
1382 | return (ino->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID; | ||
1383 | } | ||
1384 | |||
1385 | /* | ||
1386 | * ... and these candidates should be on MS_MANDLOCK mounted fs, | ||
1387 | * otherwise these will be advisory locks | ||
1388 | */ | ||
1389 | |||
1390 | static inline int mandatory_lock(struct inode *ino) | ||
1391 | { | ||
1392 | return IS_MANDLOCK(ino) && __mandatory_lock(ino); | ||
1393 | } | ||
1380 | 1394 | ||
1381 | static inline int locks_verify_locked(struct inode *inode) | 1395 | static inline int locks_verify_locked(struct inode *inode) |
1382 | { | 1396 | { |
1383 | if (MANDATORY_LOCK(inode)) | 1397 | if (mandatory_lock(inode)) |
1384 | return locks_mandatory_locked(inode); | 1398 | return locks_mandatory_locked(inode); |
1385 | return 0; | 1399 | return 0; |
1386 | } | 1400 | } |
@@ -1391,7 +1405,7 @@ static inline int locks_verify_truncate(struct inode *inode, | |||
1391 | struct file *filp, | 1405 | struct file *filp, |
1392 | loff_t size) | 1406 | loff_t size) |
1393 | { | 1407 | { |
1394 | if (inode->i_flock && MANDATORY_LOCK(inode)) | 1408 | if (inode->i_flock && mandatory_lock(inode)) |
1395 | return locks_mandatory_area( | 1409 | return locks_mandatory_area( |
1396 | FLOCK_VERIFY_WRITE, inode, filp, | 1410 | FLOCK_VERIFY_WRITE, inode, filp, |
1397 | size < inode->i_size ? size : inode->i_size, | 1411 | size < inode->i_size ? size : inode->i_size, |