[PATCH 16/70] NFSd: Protect the nfs4_file delegation fields using the fi_lock

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Signed-off-by: Trond Myklebust <trond.myklebust@xxxxxxxxxxxxxxx>
---
 fs/nfsd/nfs4state.c | 33 ++++++++++++++++++++++++++-------
 1 file changed, 26 insertions(+), 7 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 73e7da308d37..5105dbc76888 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -479,6 +479,7 @@ nfs4_put_delegation(struct nfs4_delegation *dp)
 	}
 }
 
+/* Call under fp->fi_lock */
 static void nfs4_put_deleg_lease(struct nfs4_file *fp)
 {
 	if (atomic_dec_and_test(&fp->fi_delegees)) {
@@ -511,6 +512,7 @@ unhash_delegation(struct nfs4_delegation *dp)
 	struct nfs4_file *fp = dp->dl_file;
 
 	spin_lock(&state_lock);
+	spin_lock(&fp->fi_lock);
 	list_del_init(&dp->dl_perclnt);
 	list_del_init(&dp->dl_recall_lru);
 	if (!list_empty(&dp->dl_perfile)) {
@@ -518,10 +520,11 @@ unhash_delegation(struct nfs4_delegation *dp)
 		list_del_init(&dp->dl_perfile);
 		spin_unlock(&fp->fi_inode->i_lock);
 	}
-	spin_unlock(&state_lock);
 	nfs4_put_deleg_lease(fp);
-	put_nfs4_file(fp);
 	dp->dl_file = NULL;
+	spin_unlock(&fp->fi_lock);
+	spin_unlock(&state_lock);
+	put_nfs4_file(fp);
 }
 
 
@@ -3153,23 +3156,33 @@ static int nfs4_setlease(struct nfs4_delegation *dp)
 {
 	struct nfs4_file *fp = dp->dl_file;
 	struct file_lock *fl;
-	int status;
+	int status = 0;
 
 	fl = nfs4_alloc_init_lease(dp, NFS4_OPEN_DELEGATE_READ);
 	if (!fl)
 		return -ENOMEM;
 	fl->fl_file = find_readable_file(fp);
+	spin_lock(&state_lock);
+	spin_lock(&fp->fi_lock);
+	/* Race breaker */
+	if (fp->fi_lease) {
+		atomic_inc(&fp->fi_delegees);
+		hash_delegation_locked(dp, fp);
+		goto out_free;
+	}
 	status = vfs_setlease(fl->fl_file, fl->fl_type, &fl);
 	if (status)
 		goto out_free;
 	fp->fi_lease = fl;
 	fp->fi_deleg_file = fl->fl_file;
 	atomic_set(&fp->fi_delegees, 1);
-	spin_lock(&state_lock);
 	hash_delegation_locked(dp, fp);
+	spin_unlock(&fp->fi_lock);
 	spin_unlock(&state_lock);
 	return 0;
 out_free:
+	spin_unlock(&fp->fi_lock);
+	spin_unlock(&state_lock);
 	if (fl->fl_file)
 		fput(fl->fl_file);
 	locks_free_lock(fl);
@@ -3183,23 +3196,29 @@ static int nfs4_set_delegation(struct nfs4_delegation *dp, struct nfs4_file *fp)
 	if (fp->fi_had_conflict)
 		return -EAGAIN;
 	get_nfs4_file(fp);
+	spin_lock(&state_lock);
+	spin_lock(&fp->fi_lock);
 	dp->dl_file = fp;
 	if (!fp->fi_lease) {
+		spin_unlock(&fp->fi_lock);
+		spin_unlock(&state_lock);
 		status = nfs4_setlease(dp);
 		if (status)
 			goto out_free;
 		return 0;
 	}
-	spin_lock(&state_lock);
 	if (fp->fi_had_conflict) {
-		spin_unlock(&state_lock);
 		status = -EAGAIN;
-		goto out_free;
+		goto unlock_and_free;
 	}
 	atomic_inc(&fp->fi_delegees);
 	hash_delegation_locked(dp, fp);
+	spin_unlock(&fp->fi_lock);
 	spin_unlock(&state_lock);
 	return 0;
+unlock_and_free:
+	spin_unlock(&fp->fi_lock);
+	spin_unlock(&state_lock);
 out_free:
 	put_nfs4_file(fp);
 	dp->dl_file = fp;
-- 
1.9.0

--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Filesystem Development]     [Linux USB Development]     [Linux Media Development]     [Video for Linux]     [Linux NILFS]     [Linux Audio Users]     [Yosemite Info]     [Linux SCSI]

  Powered by Linux