Commit 4d01b7f5e7576858b71cbaa72b541e17a229cb91

Authored by Jeff Layton
1 parent 03d12ddf84

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>

Showing 3 changed files with 23 additions and 13 deletions Side-by-side Diff

... ... @@ -427,9 +427,11 @@
427 427 }
428 428  
429 429 /* default lease lock manager operations */
430   -static void lease_break_callback(struct file_lock *fl)
  430 +static bool
  431 +lease_break_callback(struct file_lock *fl)
431 432 {
432 433 kill_fasync(&fl->fl_fasync, SIGIO, POLL_MSG);
  434 + return false;
433 435 }
434 436  
435 437 static void
... ... @@ -1382,7 +1384,7 @@
1382 1384 {
1383 1385 int error = 0;
1384 1386 struct file_lock *new_fl;
1385   - struct file_lock *fl;
  1387 + struct file_lock *fl, **before;
1386 1388 unsigned long break_time;
1387 1389 int want_write = (mode & O_ACCMODE) != O_RDONLY;
1388 1390 LIST_HEAD(dispose);
... ... @@ -1406,7 +1408,9 @@
1406 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 1414 if (!leases_conflict(fl, new_fl))
1411 1415 continue;
1412 1416 if (want_write) {
1413 1417  
... ... @@ -1420,8 +1424,13 @@
1420 1424 fl->fl_flags |= FL_DOWNGRADE_PENDING;
1421 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 }
  1430 +
  1431 + fl = inode->i_flock;
  1432 + if (!fl || !IS_LEASE(fl))
  1433 + goto out;
1425 1434  
1426 1435 if (mode & O_NONBLOCK) {
1427 1436 trace_break_lease_noblock(inode, new_fl);
... ... @@ -3391,18 +3391,20 @@
3391 3391 }
3392 3392  
3393 3393 /* Called from break_lease() with i_lock held. */
3394   -static void nfsd_break_deleg_cb(struct file_lock *fl)
  3394 +static bool
  3395 +nfsd_break_deleg_cb(struct file_lock *fl)
3395 3396 {
  3397 + bool ret = false;
3396 3398 struct nfs4_file *fp = (struct nfs4_file *)fl->fl_owner;
3397 3399 struct nfs4_delegation *dp;
3398 3400  
3399 3401 if (!fp) {
3400 3402 WARN(1, "(%p)->fl_owner NULL\n", fl);
3401   - return;
  3403 + return ret;
3402 3404 }
3403 3405 if (fp->fi_had_conflict) {
3404 3406 WARN(1, "duplicate break on %p\n", fp);
3405   - return;
  3407 + return ret;
3406 3408 }
3407 3409 /*
3408 3410 * We don't want the locks code to timeout the lease for us;
3409 3411  
3410 3412  
... ... @@ -3414,17 +3416,16 @@
3414 3416 spin_lock(&fp->fi_lock);
3415 3417 fp->fi_had_conflict = true;
3416 3418 /*
3417   - * If there are no delegations on the list, then we can't count on this
3418   - * lease ever being cleaned up. Set the fl_break_time to jiffies so that
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.
  3419 + * If there are no delegations on the list, then return true
  3420 + * so that the lease code will go ahead and delete it.
3421 3421 */
3422 3422 if (list_empty(&fp->fi_delegations))
3423   - fl->fl_break_time = jiffies;
  3423 + ret = true;
3424 3424 else
3425 3425 list_for_each_entry(dp, &fp->fi_delegations, dl_perfile)
3426 3426 nfsd_break_one_deleg(dp);
3427 3427 spin_unlock(&fp->fi_lock);
  3428 + return ret;
3428 3429 }
3429 3430  
3430 3431 static int
... ... @@ -872,7 +872,7 @@
872 872 void (*lm_put_owner)(struct file_lock *);
873 873 void (*lm_notify)(struct file_lock *); /* unblock callback */
874 874 int (*lm_grant)(struct file_lock *, int);
875   - void (*lm_break)(struct file_lock *);
  875 + bool (*lm_break)(struct file_lock *);
876 876 int (*lm_change)(struct file_lock **, int, struct list_head *);
877 877 void (*lm_setup)(struct file_lock *, void **);
878 878 };