diff options
Diffstat (limited to 'fs/nfsd/nfs4state.c')
-rw-r--r-- | fs/nfsd/nfs4state.c | 56 |
1 files changed, 25 insertions, 31 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 1143cfb64549..47ec112b266c 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -49,6 +49,7 @@ | |||
49 | #include <linux/nfsd/state.h> | 49 | #include <linux/nfsd/state.h> |
50 | #include <linux/nfsd/xdr4.h> | 50 | #include <linux/nfsd/xdr4.h> |
51 | #include <linux/namei.h> | 51 | #include <linux/namei.h> |
52 | #include <linux/mutex.h> | ||
52 | 53 | ||
53 | #define NFSDDBG_FACILITY NFSDDBG_PROC | 54 | #define NFSDDBG_FACILITY NFSDDBG_PROC |
54 | 55 | ||
@@ -77,11 +78,11 @@ static void nfs4_set_recdir(char *recdir); | |||
77 | 78 | ||
78 | /* Locking: | 79 | /* Locking: |
79 | * | 80 | * |
80 | * client_sema: | 81 | * client_mutex: |
81 | * protects clientid_hashtbl[], clientstr_hashtbl[], | 82 | * protects clientid_hashtbl[], clientstr_hashtbl[], |
82 | * unconfstr_hashtbl[], uncofid_hashtbl[]. | 83 | * unconfstr_hashtbl[], uncofid_hashtbl[]. |
83 | */ | 84 | */ |
84 | static DECLARE_MUTEX(client_sema); | 85 | static DEFINE_MUTEX(client_mutex); |
85 | 86 | ||
86 | static kmem_cache_t *stateowner_slab = NULL; | 87 | static kmem_cache_t *stateowner_slab = NULL; |
87 | static kmem_cache_t *file_slab = NULL; | 88 | static kmem_cache_t *file_slab = NULL; |
@@ -91,13 +92,13 @@ static kmem_cache_t *deleg_slab = NULL; | |||
91 | void | 92 | void |
92 | nfs4_lock_state(void) | 93 | nfs4_lock_state(void) |
93 | { | 94 | { |
94 | down(&client_sema); | 95 | mutex_lock(&client_mutex); |
95 | } | 96 | } |
96 | 97 | ||
97 | void | 98 | void |
98 | nfs4_unlock_state(void) | 99 | nfs4_unlock_state(void) |
99 | { | 100 | { |
100 | up(&client_sema); | 101 | mutex_unlock(&client_mutex); |
101 | } | 102 | } |
102 | 103 | ||
103 | static inline u32 | 104 | static inline u32 |
@@ -2639,7 +2640,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock | |||
2639 | struct nfs4_stateid *lock_stp; | 2640 | struct nfs4_stateid *lock_stp; |
2640 | struct file *filp; | 2641 | struct file *filp; |
2641 | struct file_lock file_lock; | 2642 | struct file_lock file_lock; |
2642 | struct file_lock *conflock; | 2643 | struct file_lock conflock; |
2643 | int status = 0; | 2644 | int status = 0; |
2644 | unsigned int strhashval; | 2645 | unsigned int strhashval; |
2645 | 2646 | ||
@@ -2749,37 +2750,31 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock | |||
2749 | * Note: locks.c uses the BKL to protect the inode's lock list. | 2750 | * Note: locks.c uses the BKL to protect the inode's lock list. |
2750 | */ | 2751 | */ |
2751 | 2752 | ||
2752 | status = posix_lock_file(filp, &file_lock); | 2753 | /* XXX?: Just to divert the locks_release_private at the start of |
2753 | dprintk("NFSD: nfsd4_lock: posix_lock_file status %d\n",status); | 2754 | * locks_copy_lock: */ |
2755 | conflock.fl_ops = NULL; | ||
2756 | conflock.fl_lmops = NULL; | ||
2757 | status = posix_lock_file_conf(filp, &file_lock, &conflock); | ||
2758 | dprintk("NFSD: nfsd4_lock: posix_lock_file_conf status %d\n",status); | ||
2754 | switch (-status) { | 2759 | switch (-status) { |
2755 | case 0: /* success! */ | 2760 | case 0: /* success! */ |
2756 | update_stateid(&lock_stp->st_stateid); | 2761 | update_stateid(&lock_stp->st_stateid); |
2757 | memcpy(&lock->lk_resp_stateid, &lock_stp->st_stateid, | 2762 | memcpy(&lock->lk_resp_stateid, &lock_stp->st_stateid, |
2758 | sizeof(stateid_t)); | 2763 | sizeof(stateid_t)); |
2759 | goto out; | 2764 | break; |
2760 | case (EAGAIN): | 2765 | case (EAGAIN): /* conflock holds conflicting lock */ |
2761 | goto conflicting_lock; | 2766 | status = nfserr_denied; |
2767 | dprintk("NFSD: nfsd4_lock: conflicting lock found!\n"); | ||
2768 | nfs4_set_lock_denied(&conflock, &lock->lk_denied); | ||
2769 | break; | ||
2762 | case (EDEADLK): | 2770 | case (EDEADLK): |
2763 | status = nfserr_deadlock; | 2771 | status = nfserr_deadlock; |
2764 | dprintk("NFSD: nfsd4_lock: posix_lock_file() failed! status %d\n",status); | 2772 | break; |
2765 | goto out; | ||
2766 | default: | 2773 | default: |
2767 | status = nfserrno(status); | 2774 | dprintk("NFSD: nfsd4_lock: posix_lock_file_conf() failed! status %d\n",status); |
2768 | dprintk("NFSD: nfsd4_lock: posix_lock_file() failed! status %d\n",status); | 2775 | status = nfserr_resource; |
2769 | goto out; | 2776 | break; |
2770 | } | ||
2771 | |||
2772 | conflicting_lock: | ||
2773 | dprintk("NFSD: nfsd4_lock: conflicting lock found!\n"); | ||
2774 | status = nfserr_denied; | ||
2775 | /* XXX There is a race here. Future patch needed to provide | ||
2776 | * an atomic posix_lock_and_test_file | ||
2777 | */ | ||
2778 | if (!(conflock = posix_test_lock(filp, &file_lock))) { | ||
2779 | status = nfserr_serverfault; | ||
2780 | goto out; | ||
2781 | } | 2777 | } |
2782 | nfs4_set_lock_denied(conflock, &lock->lk_denied); | ||
2783 | out: | 2778 | out: |
2784 | if (status && lock->lk_is_new && lock_sop) | 2779 | if (status && lock->lk_is_new && lock_sop) |
2785 | release_stateowner(lock_sop); | 2780 | release_stateowner(lock_sop); |
@@ -2800,7 +2795,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock | |||
2800 | struct inode *inode; | 2795 | struct inode *inode; |
2801 | struct file file; | 2796 | struct file file; |
2802 | struct file_lock file_lock; | 2797 | struct file_lock file_lock; |
2803 | struct file_lock *conflicting_lock; | 2798 | struct file_lock conflock; |
2804 | int status; | 2799 | int status; |
2805 | 2800 | ||
2806 | if (nfs4_in_grace()) | 2801 | if (nfs4_in_grace()) |
@@ -2864,10 +2859,9 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock | |||
2864 | file.f_dentry = current_fh->fh_dentry; | 2859 | file.f_dentry = current_fh->fh_dentry; |
2865 | 2860 | ||
2866 | status = nfs_ok; | 2861 | status = nfs_ok; |
2867 | conflicting_lock = posix_test_lock(&file, &file_lock); | 2862 | if (posix_test_lock(&file, &file_lock, &conflock)) { |
2868 | if (conflicting_lock) { | ||
2869 | status = nfserr_denied; | 2863 | status = nfserr_denied; |
2870 | nfs4_set_lock_denied(conflicting_lock, &lockt->lt_denied); | 2864 | nfs4_set_lock_denied(&conflock, &lockt->lt_denied); |
2871 | } | 2865 | } |
2872 | out: | 2866 | out: |
2873 | nfs4_unlock_state(); | 2867 | nfs4_unlock_state(); |