diff options
author | Marc Eshel <eshel@almaden.ibm.com> | 2007-01-18 16:15:35 -0500 |
---|---|---|
committer | J. Bruce Fields <bfields@citi.umich.edu> | 2007-05-06 19:23:24 -0400 |
commit | 150b393456e5a23513cace286a019e87151e47f0 (patch) | |
tree | 91599ec9b759f7e3c5defcb8dd361acd7288154c | |
parent | 7723ec9777d9832849b76475b1a21a2872a40d20 (diff) |
locks: allow {vfs,posix}_lock_file to return conflicting lock
The nfsv4 protocol's lock operation, in the case of a conflict, returns
information about the conflicting lock.
It's unclear how clients can use this, so for now we're not going so far as to
add a filesystem method that can return a conflicting lock, but we may as well
return something in the local case when it's easy to.
Signed-off-by: Marc Eshel <eshel@almaden.ibm.com>
Signed-off-by: "J. Bruce Fields" <bfields@citi.umich.edu>
-rw-r--r-- | fs/lockd/svclock.c | 6 | ||||
-rw-r--r-- | fs/lockd/svcsubs.c | 2 | ||||
-rw-r--r-- | fs/locks.c | 45 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 10 | ||||
-rw-r--r-- | include/linux/fs.h | 5 |
5 files changed, 32 insertions, 36 deletions
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index 97b0160ef10f..3b0e7a4b817b 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c | |||
@@ -363,7 +363,7 @@ again: | |||
363 | } else | 363 | } else |
364 | lock = &block->b_call->a_args.lock; | 364 | lock = &block->b_call->a_args.lock; |
365 | 365 | ||
366 | error = posix_lock_file(file->f_file, &lock->fl); | 366 | error = posix_lock_file(file->f_file, &lock->fl, NULL); |
367 | lock->fl.fl_flags &= ~FL_SLEEP; | 367 | lock->fl.fl_flags &= ~FL_SLEEP; |
368 | 368 | ||
369 | dprintk("lockd: posix_lock_file returned %d\n", error); | 369 | dprintk("lockd: posix_lock_file returned %d\n", error); |
@@ -467,7 +467,7 @@ nlmsvc_unlock(struct nlm_file *file, struct nlm_lock *lock) | |||
467 | nlmsvc_cancel_blocked(file, lock); | 467 | nlmsvc_cancel_blocked(file, lock); |
468 | 468 | ||
469 | lock->fl.fl_type = F_UNLCK; | 469 | lock->fl.fl_type = F_UNLCK; |
470 | error = posix_lock_file(file->f_file, &lock->fl); | 470 | error = posix_lock_file(file->f_file, &lock->fl, NULL); |
471 | 471 | ||
472 | return (error < 0)? nlm_lck_denied_nolocks : nlm_granted; | 472 | return (error < 0)? nlm_lck_denied_nolocks : nlm_granted; |
473 | } | 473 | } |
@@ -569,7 +569,7 @@ nlmsvc_grant_blocked(struct nlm_block *block) | |||
569 | 569 | ||
570 | /* Try the lock operation again */ | 570 | /* Try the lock operation again */ |
571 | lock->fl.fl_flags |= FL_SLEEP; | 571 | lock->fl.fl_flags |= FL_SLEEP; |
572 | error = posix_lock_file(file->f_file, &lock->fl); | 572 | error = posix_lock_file(file->f_file, &lock->fl, NULL); |
573 | lock->fl.fl_flags &= ~FL_SLEEP; | 573 | lock->fl.fl_flags &= ~FL_SLEEP; |
574 | 574 | ||
575 | switch (error) { | 575 | switch (error) { |
diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c index c0df00c74ce3..50957089be1f 100644 --- a/fs/lockd/svcsubs.c +++ b/fs/lockd/svcsubs.c | |||
@@ -182,7 +182,7 @@ again: | |||
182 | lock.fl_type = F_UNLCK; | 182 | lock.fl_type = F_UNLCK; |
183 | lock.fl_start = 0; | 183 | lock.fl_start = 0; |
184 | lock.fl_end = OFFSET_MAX; | 184 | lock.fl_end = OFFSET_MAX; |
185 | if (posix_lock_file(file->f_file, &lock) < 0) { | 185 | if (posix_lock_file(file->f_file, &lock, NULL) < 0) { |
186 | printk("lockd: unlock failure in %s:%d\n", | 186 | printk("lockd: unlock failure in %s:%d\n", |
187 | __FILE__, __LINE__); | 187 | __FILE__, __LINE__); |
188 | return 1; | 188 | return 1; |
diff --git a/fs/locks.c b/fs/locks.c index f4fd1515b6e2..ee46584c1a40 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
@@ -801,7 +801,7 @@ out: | |||
801 | return error; | 801 | return error; |
802 | } | 802 | } |
803 | 803 | ||
804 | static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request, struct file_lock *conflock) | 804 | static int __posix_lock_file(struct inode *inode, struct file_lock *request, struct file_lock *conflock) |
805 | { | 805 | { |
806 | struct file_lock *fl; | 806 | struct file_lock *fl; |
807 | struct file_lock *new_fl = NULL; | 807 | struct file_lock *new_fl = NULL; |
@@ -1007,6 +1007,7 @@ static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request | |||
1007 | * posix_lock_file - Apply a POSIX-style lock to a file | 1007 | * posix_lock_file - Apply a POSIX-style lock to a file |
1008 | * @filp: The file to apply the lock to | 1008 | * @filp: The file to apply the lock to |
1009 | * @fl: The lock to be applied | 1009 | * @fl: The lock to be applied |
1010 | * @conflock: Place to return a copy of the conflicting lock, if found. | ||
1010 | * | 1011 | * |
1011 | * Add a POSIX style lock to a file. | 1012 | * Add a POSIX style lock to a file. |
1012 | * We merge adjacent & overlapping locks whenever possible. | 1013 | * We merge adjacent & overlapping locks whenever possible. |
@@ -1016,26 +1017,12 @@ static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request | |||
1016 | * whether or not a lock was successfully freed by testing the return | 1017 | * whether or not a lock was successfully freed by testing the return |
1017 | * value for -ENOENT. | 1018 | * value for -ENOENT. |
1018 | */ | 1019 | */ |
1019 | int posix_lock_file(struct file *filp, struct file_lock *fl) | 1020 | int posix_lock_file(struct file *filp, struct file_lock *fl, |
1020 | { | ||
1021 | return __posix_lock_file_conf(filp->f_path.dentry->d_inode, fl, NULL); | ||
1022 | } | ||
1023 | EXPORT_SYMBOL(posix_lock_file); | ||
1024 | |||
1025 | /** | ||
1026 | * posix_lock_file_conf - Apply a POSIX-style lock to a file | ||
1027 | * @filp: The file to apply the lock to | ||
1028 | * @fl: The lock to be applied | ||
1029 | * @conflock: Place to return a copy of the conflicting lock, if found. | ||
1030 | * | ||
1031 | * Except for the conflock parameter, acts just like posix_lock_file. | ||
1032 | */ | ||
1033 | int posix_lock_file_conf(struct file *filp, struct file_lock *fl, | ||
1034 | struct file_lock *conflock) | 1021 | struct file_lock *conflock) |
1035 | { | 1022 | { |
1036 | return __posix_lock_file_conf(filp->f_path.dentry->d_inode, fl, conflock); | 1023 | return __posix_lock_file(filp->f_path.dentry->d_inode, fl, conflock); |
1037 | } | 1024 | } |
1038 | EXPORT_SYMBOL(posix_lock_file_conf); | 1025 | EXPORT_SYMBOL(posix_lock_file); |
1039 | 1026 | ||
1040 | /** | 1027 | /** |
1041 | * posix_lock_file_wait - Apply a POSIX-style lock to a file | 1028 | * posix_lock_file_wait - Apply a POSIX-style lock to a file |
@@ -1051,7 +1038,7 @@ int posix_lock_file_wait(struct file *filp, struct file_lock *fl) | |||
1051 | int error; | 1038 | int error; |
1052 | might_sleep (); | 1039 | might_sleep (); |
1053 | for (;;) { | 1040 | for (;;) { |
1054 | error = posix_lock_file(filp, fl); | 1041 | error = posix_lock_file(filp, fl, NULL); |
1055 | if ((error != -EAGAIN) || !(fl->fl_flags & FL_SLEEP)) | 1042 | if ((error != -EAGAIN) || !(fl->fl_flags & FL_SLEEP)) |
1056 | break; | 1043 | break; |
1057 | error = wait_event_interruptible(fl->fl_wait, !fl->fl_next); | 1044 | error = wait_event_interruptible(fl->fl_wait, !fl->fl_next); |
@@ -1123,7 +1110,7 @@ int locks_mandatory_area(int read_write, struct inode *inode, | |||
1123 | fl.fl_end = offset + count - 1; | 1110 | fl.fl_end = offset + count - 1; |
1124 | 1111 | ||
1125 | for (;;) { | 1112 | for (;;) { |
1126 | error = __posix_lock_file_conf(inode, &fl, NULL); | 1113 | error = __posix_lock_file(inode, &fl, NULL); |
1127 | if (error != -EAGAIN) | 1114 | if (error != -EAGAIN) |
1128 | break; | 1115 | break; |
1129 | if (!(fl.fl_flags & FL_SLEEP)) | 1116 | if (!(fl.fl_flags & FL_SLEEP)) |
@@ -1703,13 +1690,21 @@ out: | |||
1703 | * @filp: The file to apply the lock to | 1690 | * @filp: The file to apply the lock to |
1704 | * @cmd: type of locking operation (F_SETLK, F_GETLK, etc.) | 1691 | * @cmd: type of locking operation (F_SETLK, F_GETLK, etc.) |
1705 | * @fl: The lock to be applied | 1692 | * @fl: The lock to be applied |
1693 | * @conf: Place to return a copy of the conflicting lock, if found. | ||
1694 | * | ||
1695 | * A caller that doesn't care about the conflicting lock may pass NULL | ||
1696 | * as the final argument. | ||
1697 | * | ||
1698 | * If the filesystem defines a private ->lock() method, then @conf will | ||
1699 | * be left unchanged; so a caller that cares should initialize it to | ||
1700 | * some acceptable default. | ||
1706 | */ | 1701 | */ |
1707 | int vfs_lock_file(struct file *filp, unsigned int cmd, struct file_lock *fl) | 1702 | int vfs_lock_file(struct file *filp, unsigned int cmd, struct file_lock *fl, struct file_lock *conf) |
1708 | { | 1703 | { |
1709 | if (filp->f_op && filp->f_op->lock) | 1704 | if (filp->f_op && filp->f_op->lock) |
1710 | return filp->f_op->lock(filp, cmd, fl); | 1705 | return filp->f_op->lock(filp, cmd, fl); |
1711 | else | 1706 | else |
1712 | return posix_lock_file(filp, fl); | 1707 | return posix_lock_file(filp, fl, conf); |
1713 | } | 1708 | } |
1714 | EXPORT_SYMBOL_GPL(vfs_lock_file); | 1709 | EXPORT_SYMBOL_GPL(vfs_lock_file); |
1715 | 1710 | ||
@@ -1776,7 +1771,7 @@ again: | |||
1776 | goto out; | 1771 | goto out; |
1777 | 1772 | ||
1778 | for (;;) { | 1773 | for (;;) { |
1779 | error = vfs_lock_file(filp, cmd, file_lock); | 1774 | error = vfs_lock_file(filp, cmd, file_lock, NULL); |
1780 | if (error != -EAGAIN || cmd == F_SETLK) | 1775 | if (error != -EAGAIN || cmd == F_SETLK) |
1781 | break; | 1776 | break; |
1782 | error = wait_event_interruptible(file_lock->fl_wait, | 1777 | error = wait_event_interruptible(file_lock->fl_wait, |
@@ -1902,7 +1897,7 @@ again: | |||
1902 | goto out; | 1897 | goto out; |
1903 | 1898 | ||
1904 | for (;;) { | 1899 | for (;;) { |
1905 | error = vfs_lock_file(filp, cmd, file_lock); | 1900 | error = vfs_lock_file(filp, cmd, file_lock, NULL); |
1906 | if (error != -EAGAIN || cmd == F_SETLK64) | 1901 | if (error != -EAGAIN || cmd == F_SETLK64) |
1907 | break; | 1902 | break; |
1908 | error = wait_event_interruptible(file_lock->fl_wait, | 1903 | error = wait_event_interruptible(file_lock->fl_wait, |
@@ -1956,7 +1951,7 @@ void locks_remove_posix(struct file *filp, fl_owner_t owner) | |||
1956 | lock.fl_ops = NULL; | 1951 | lock.fl_ops = NULL; |
1957 | lock.fl_lmops = NULL; | 1952 | lock.fl_lmops = NULL; |
1958 | 1953 | ||
1959 | vfs_lock_file(filp, F_SETLK, &lock); | 1954 | vfs_lock_file(filp, F_SETLK, &lock, NULL); |
1960 | 1955 | ||
1961 | if (lock.fl_ops && lock.fl_ops->fl_release_private) | 1956 | if (lock.fl_ops && lock.fl_ops->fl_release_private) |
1962 | lock.fl_ops->fl_release_private(&lock); | 1957 | lock.fl_ops->fl_release_private(&lock); |
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index e42c7a0eb6fa..03b0578781cb 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -2657,6 +2657,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2657 | struct file_lock conflock; | 2657 | struct file_lock conflock; |
2658 | __be32 status = 0; | 2658 | __be32 status = 0; |
2659 | unsigned int strhashval; | 2659 | unsigned int strhashval; |
2660 | unsigned int cmd; | ||
2660 | int err; | 2661 | int err; |
2661 | 2662 | ||
2662 | dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n", | 2663 | dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n", |
@@ -2739,10 +2740,12 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2739 | case NFS4_READ_LT: | 2740 | case NFS4_READ_LT: |
2740 | case NFS4_READW_LT: | 2741 | case NFS4_READW_LT: |
2741 | file_lock.fl_type = F_RDLCK; | 2742 | file_lock.fl_type = F_RDLCK; |
2743 | cmd = F_SETLK; | ||
2742 | break; | 2744 | break; |
2743 | case NFS4_WRITE_LT: | 2745 | case NFS4_WRITE_LT: |
2744 | case NFS4_WRITEW_LT: | 2746 | case NFS4_WRITEW_LT: |
2745 | file_lock.fl_type = F_WRLCK; | 2747 | file_lock.fl_type = F_WRLCK; |
2748 | cmd = F_SETLK; | ||
2746 | break; | 2749 | break; |
2747 | default: | 2750 | default: |
2748 | status = nfserr_inval; | 2751 | status = nfserr_inval; |
@@ -2769,9 +2772,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2769 | 2772 | ||
2770 | /* XXX?: Just to divert the locks_release_private at the start of | 2773 | /* XXX?: Just to divert the locks_release_private at the start of |
2771 | * locks_copy_lock: */ | 2774 | * locks_copy_lock: */ |
2772 | conflock.fl_ops = NULL; | 2775 | locks_init_lock(&conflock); |
2773 | conflock.fl_lmops = NULL; | 2776 | err = posix_lock_file(filp, &file_lock, &conflock); |
2774 | err = posix_lock_file_conf(filp, &file_lock, &conflock); | ||
2775 | switch (-err) { | 2777 | switch (-err) { |
2776 | case 0: /* success! */ | 2778 | case 0: /* success! */ |
2777 | update_stateid(&lock_stp->st_stateid); | 2779 | update_stateid(&lock_stp->st_stateid); |
@@ -2933,7 +2935,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2933 | /* | 2935 | /* |
2934 | * Try to unlock the file in the VFS. | 2936 | * Try to unlock the file in the VFS. |
2935 | */ | 2937 | */ |
2936 | err = posix_lock_file(filp, &file_lock); | 2938 | err = posix_lock_file(filp, &file_lock, NULL); |
2937 | if (err) { | 2939 | if (err) { |
2938 | dprintk("NFSD: nfs4_locku: posix_lock_file failed!\n"); | 2940 | dprintk("NFSD: nfs4_locku: posix_lock_file failed!\n"); |
2939 | goto out_nfserr; | 2941 | goto out_nfserr; |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 1d5ccdd7c68d..c92d0bdff39f 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -852,12 +852,11 @@ extern void locks_copy_lock(struct file_lock *, struct file_lock *); | |||
852 | extern void locks_remove_posix(struct file *, fl_owner_t); | 852 | extern void locks_remove_posix(struct file *, fl_owner_t); |
853 | extern void locks_remove_flock(struct file *); | 853 | extern void locks_remove_flock(struct file *); |
854 | extern int posix_test_lock(struct file *, struct file_lock *); | 854 | extern int posix_test_lock(struct file *, struct file_lock *); |
855 | extern int posix_lock_file_conf(struct file *, struct file_lock *, struct file_lock *); | 855 | extern int posix_lock_file(struct file *, struct file_lock *, struct file_lock *); |
856 | extern int posix_lock_file(struct file *, struct file_lock *); | ||
857 | extern int posix_lock_file_wait(struct file *, struct file_lock *); | 856 | extern int posix_lock_file_wait(struct file *, struct file_lock *); |
858 | extern int posix_unblock_lock(struct file *, struct file_lock *); | 857 | extern int posix_unblock_lock(struct file *, struct file_lock *); |
859 | extern int vfs_test_lock(struct file *, struct file_lock *); | 858 | extern int vfs_test_lock(struct file *, struct file_lock *); |
860 | extern int vfs_lock_file(struct file *, unsigned int, struct file_lock *); | 859 | extern int vfs_lock_file(struct file *, unsigned int, struct file_lock *, struct file_lock *); |
861 | extern int flock_lock_file_wait(struct file *filp, struct file_lock *fl); | 860 | extern int flock_lock_file_wait(struct file *filp, struct file_lock *fl); |
862 | extern int __break_lease(struct inode *inode, unsigned int flags); | 861 | extern int __break_lease(struct inode *inode, unsigned int flags); |
863 | extern void lease_get_mtime(struct inode *, struct timespec *time); | 862 | extern void lease_get_mtime(struct inode *, struct timespec *time); |