aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/nfs4state.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfsd/nfs4state.c')
-rw-r--r--fs/nfsd/nfs4state.c56
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 */
84static DECLARE_MUTEX(client_sema); 85static DEFINE_MUTEX(client_mutex);
85 86
86static kmem_cache_t *stateowner_slab = NULL; 87static kmem_cache_t *stateowner_slab = NULL;
87static kmem_cache_t *file_slab = NULL; 88static kmem_cache_t *file_slab = NULL;
@@ -91,13 +92,13 @@ static kmem_cache_t *deleg_slab = NULL;
91void 92void
92nfs4_lock_state(void) 93nfs4_lock_state(void)
93{ 94{
94 down(&client_sema); 95 mutex_lock(&client_mutex);
95} 96}
96 97
97void 98void
98nfs4_unlock_state(void) 99nfs4_unlock_state(void)
99{ 100{
100 up(&client_sema); 101 mutex_unlock(&client_mutex);
101} 102}
102 103
103static inline u32 104static 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
2772conflicting_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);
2783out: 2778out:
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 }
2872out: 2866out:
2873 nfs4_unlock_state(); 2867 nfs4_unlock_state();