aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Layton <jlayton@primarydata.com>2014-09-01 15:06:54 -0400
committerJeff Layton <jlayton@primarydata.com>2014-10-07 14:06:13 -0400
commit4d01b7f5e7576858b71cbaa72b541e17a229cb91 (patch)
tree5ea9a839335ca6159ac24f1cf5ddfbe3ff1e7c74
parent03d12ddf845a4eb874ffa558d65a548aee9b715b (diff)
locks: give lm_break a return value
Christoph suggests: "Add a return value to lm_break so that the lock manager can tell the core code "you can delete this lease right now". That gets rid of the games with the timeout which require all kinds of race avoidance code in the users." Do that here and have the nfsd lease break routine use it when it detects that there was a race between setting up the lease and it being broken. Signed-off-by: Jeff Layton <jlayton@primarydata.com> Reviewed-by: Christoph Hellwig <hch@lst.de>
-rw-r--r--fs/locks.c17
-rw-r--r--fs/nfsd/nfs4state.c17
-rw-r--r--include/linux/fs.h2
3 files changed, 23 insertions, 13 deletions
diff --git a/fs/locks.c b/fs/locks.c
index 7d627ac0ed87..aed4a957d232 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -427,9 +427,11 @@ static int flock_to_posix_lock(struct file *filp, struct file_lock *fl,
427} 427}
428 428
429/* default lease lock manager operations */ 429/* default lease lock manager operations */
430static void lease_break_callback(struct file_lock *fl) 430static bool
431lease_break_callback(struct file_lock *fl)
431{ 432{
432 kill_fasync(&fl->fl_fasync, SIGIO, POLL_MSG); 433 kill_fasync(&fl->fl_fasync, SIGIO, POLL_MSG);
434 return false;
433} 435}
434 436
435static void 437static void
@@ -1382,7 +1384,7 @@ int __break_lease(struct inode *inode, unsigned int mode, unsigned int type)
1382{ 1384{
1383 int error = 0; 1385 int error = 0;
1384 struct file_lock *new_fl; 1386 struct file_lock *new_fl;
1385 struct file_lock *fl; 1387 struct file_lock *fl, **before;
1386 unsigned long break_time; 1388 unsigned long break_time;
1387 int want_write = (mode & O_ACCMODE) != O_RDONLY; 1389 int want_write = (mode & O_ACCMODE) != O_RDONLY;
1388 LIST_HEAD(dispose); 1390 LIST_HEAD(dispose);
@@ -1406,7 +1408,9 @@ int __break_lease(struct inode *inode, unsigned int mode, unsigned int type)
1406 break_time++; /* so that 0 means no break time */ 1408 break_time++; /* so that 0 means no break time */
1407 } 1409 }
1408 1410
1409 for (fl = inode->i_flock; fl && IS_LEASE(fl); fl = fl->fl_next) { 1411 for (before = &inode->i_flock;
1412 ((fl = *before) != NULL) && IS_LEASE(fl);
1413 before = &fl->fl_next) {
1410 if (!leases_conflict(fl, new_fl)) 1414 if (!leases_conflict(fl, new_fl))
1411 continue; 1415 continue;
1412 if (want_write) { 1416 if (want_write) {
@@ -1420,9 +1424,14 @@ int __break_lease(struct inode *inode, unsigned int mode, unsigned int type)
1420 fl->fl_flags |= FL_DOWNGRADE_PENDING; 1424 fl->fl_flags |= FL_DOWNGRADE_PENDING;
1421 fl->fl_downgrade_time = break_time; 1425 fl->fl_downgrade_time = break_time;
1422 } 1426 }
1423 fl->fl_lmops->lm_break(fl); 1427 if (fl->fl_lmops->lm_break(fl))
1428 locks_delete_lock(before, &dispose);
1424 } 1429 }
1425 1430
1431 fl = inode->i_flock;
1432 if (!fl || !IS_LEASE(fl))
1433 goto out;
1434
1426 if (mode & O_NONBLOCK) { 1435 if (mode & O_NONBLOCK) {
1427 trace_break_lease_noblock(inode, new_fl); 1436 trace_break_lease_noblock(inode, new_fl);
1428 error = -EWOULDBLOCK; 1437 error = -EWOULDBLOCK;
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 604ab6decd28..d1b851548b7a 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -3391,18 +3391,20 @@ static void nfsd_break_one_deleg(struct nfs4_delegation *dp)
3391} 3391}
3392 3392
3393/* Called from break_lease() with i_lock held. */ 3393/* Called from break_lease() with i_lock held. */
3394static void nfsd_break_deleg_cb(struct file_lock *fl) 3394static bool
3395nfsd_break_deleg_cb(struct file_lock *fl)
3395{ 3396{
3397 bool ret = false;
3396 struct nfs4_file *fp = (struct nfs4_file *)fl->fl_owner; 3398 struct nfs4_file *fp = (struct nfs4_file *)fl->fl_owner;
3397 struct nfs4_delegation *dp; 3399 struct nfs4_delegation *dp;
3398 3400
3399 if (!fp) { 3401 if (!fp) {
3400 WARN(1, "(%p)->fl_owner NULL\n", fl); 3402 WARN(1, "(%p)->fl_owner NULL\n", fl);
3401 return; 3403 return ret;
3402 } 3404 }
3403 if (fp->fi_had_conflict) { 3405 if (fp->fi_had_conflict) {
3404 WARN(1, "duplicate break on %p\n", fp); 3406 WARN(1, "duplicate break on %p\n", fp);
3405 return; 3407 return ret;
3406 } 3408 }
3407 /* 3409 /*
3408 * We don't want the locks code to timeout the lease for us; 3410 * We don't want the locks code to timeout the lease for us;
@@ -3414,17 +3416,16 @@ static void nfsd_break_deleg_cb(struct file_lock *fl)
3414 spin_lock(&fp->fi_lock); 3416 spin_lock(&fp->fi_lock);
3415 fp->fi_had_conflict = true; 3417 fp->fi_had_conflict = true;
3416 /* 3418 /*
3417 * If there are no delegations on the list, then we can't count on this 3419 * If there are no delegations on the list, then return true
3418 * lease ever being cleaned up. Set the fl_break_time to jiffies so that 3420 * so that the lease code will go ahead and delete it.
3419 * time_out_leases will do it ASAP. The fact that fi_had_conflict is now
3420 * true should keep any new delegations from being hashed.
3421 */ 3421 */
3422 if (list_empty(&fp->fi_delegations)) 3422 if (list_empty(&fp->fi_delegations))
3423 fl->fl_break_time = jiffies; 3423 ret = true;
3424 else 3424 else
3425 list_for_each_entry(dp, &fp->fi_delegations, dl_perfile) 3425 list_for_each_entry(dp, &fp->fi_delegations, dl_perfile)
3426 nfsd_break_one_deleg(dp); 3426 nfsd_break_one_deleg(dp);
3427 spin_unlock(&fp->fi_lock); 3427 spin_unlock(&fp->fi_lock);
3428 return ret;
3428} 3429}
3429 3430
3430static int 3431static int
diff --git a/include/linux/fs.h b/include/linux/fs.h
index f419f718e447..ed4e1897099c 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -872,7 +872,7 @@ struct lock_manager_operations {
872 void (*lm_put_owner)(struct file_lock *); 872 void (*lm_put_owner)(struct file_lock *);
873 void (*lm_notify)(struct file_lock *); /* unblock callback */ 873 void (*lm_notify)(struct file_lock *); /* unblock callback */
874 int (*lm_grant)(struct file_lock *, int); 874 int (*lm_grant)(struct file_lock *, int);
875 void (*lm_break)(struct file_lock *); 875 bool (*lm_break)(struct file_lock *);
876 int (*lm_change)(struct file_lock **, int, struct list_head *); 876 int (*lm_change)(struct file_lock **, int, struct list_head *);
877 void (*lm_setup)(struct file_lock *, void **); 877 void (*lm_setup)(struct file_lock *, void **);
878}; 878};