diff options
| author | Neil Brown <neilb@cse.unsw.edu.au> | 2005-03-09 16:57:19 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-03-09 16:57:19 -0800 |
| commit | 690589732d253ffbfef15bb4262a47616cc027a6 (patch) | |
| tree | 025b0cb7c2aa622c98bcfeac769c2e3dbe6d2415 | |
| parent | c6399c163142ffcdec44cd9a5920c5a4d622903a (diff) | |
[PATCH] nfsd4: move delegation decisions to lock_manager callbacks
Remove nfs4_check_deleg_recall(). Move its checks into __setlease() via two
new lock_manager callbacks, fl_mylease and fl_change, so that all leases (not
just NFSv4 lease as with nfs4_check_deleg_recall) are checked. Default
implementations of fl_mylease and fl_change are provided for the sake of the
fcntl_setlease interface. Both callbacks must always be defined.
fl_mylease:
for the NFSv4 server, this check is used to see if an existing lease
comes from the same client. For the fcntl_setlease interface, the existing
logic is preserved. the fl_mylease check sees if the existing lease is
from the input filp.
fl_change: called if the fl_mylease returns true
the NFSv4 server does not hand out a delegation to a client that already
has one. -EAGAIN is returned. Otherwise lease_modify is used. For the
fcntl_setlease interface, the exisiting logic is preserved: The callback
used in lease_modify().
Signed-off-by: Andy Adamson <andros@citi.umich.edu>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Signed-off-by: Neil Brown <neilb@cse.unsw.edu.au>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
| -rw-r--r-- | fs/locks.c | 15 | ||||
| -rw-r--r-- | fs/nfsd/nfs4state.c | 93 | ||||
| -rw-r--r-- | include/linux/fs.h | 3 |
3 files changed, 66 insertions, 45 deletions
diff --git a/fs/locks.c b/fs/locks.c index 8cbaae2c9fd0..6c98818efa3a 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -406,9 +406,16 @@ static void lease_release_private_callback(struct file_lock *fl) fl->fl_file->f_owner.signum = 0; } +static int lease_mylease_callback(struct file_lock *fl, struct file_lock *try) +{ + return fl->fl_file == try->fl_file; +} + struct lock_manager_operations lease_manager_ops = { .fl_break = lease_break_callback, .fl_release_private = lease_release_private_callback, + .fl_mylease = lease_mylease_callback, + .fl_change = lease_modify, }; /* @@ -1058,7 +1065,7 @@ int locks_mandatory_area(int read_write, struct inode *inode, EXPORT_SYMBOL(locks_mandatory_area); /* We already had a lease on this file; just change its type */ -static int lease_modify(struct file_lock **before, int arg) +int lease_modify(struct file_lock **before, int arg) { struct file_lock *fl = *before; int error = assign_type(fl, arg); @@ -1071,6 +1078,8 @@ static int lease_modify(struct file_lock **before, int arg) return 0; } +EXPORT_SYMBOL(lease_modify); + static void time_out_leases(struct inode *inode) { struct file_lock **before; @@ -1315,7 +1324,7 @@ int __setlease(struct file *filp, long arg, struct file_lock **flp) for (before = &inode->i_flock; ((fl = *before) != NULL) && IS_LEASE(fl); before = &fl->fl_next) { - if (fl->fl_file == filp) + if (lease->fl_lmops->fl_mylease(fl, lease)) my_before = before; else if (fl->fl_type == (F_INPROGRESS | F_UNLCK)) /* @@ -1333,7 +1342,7 @@ int __setlease(struct file *filp, long arg, struct file_lock **flp) goto out; if (my_before != NULL) { - error = lease_modify(my_before, arg); + error = lease->fl_lmops->fl_change(my_before, arg); goto out; } diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index dbd561ea3108..d5e40315c722 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1402,10 +1402,39 @@ void nfsd_copy_lock_deleg_cb(struct file_lock *new, struct file_lock *fl) dp->dl_flock = new; } +/* + * Called from __setlease() with lock_kernel() held + */ +static +int nfsd_same_client_deleg_cb(struct file_lock *onlist, struct file_lock *try) +{ + struct nfs4_delegation *onlistd = + (struct nfs4_delegation *)onlist->fl_owner; + struct nfs4_delegation *tryd = + (struct nfs4_delegation *)try->fl_owner; + + if (onlist->fl_lmops != try->fl_lmops) + return 0; + + return onlistd->dl_client == tryd->dl_client; +} + + +static +int nfsd_change_deleg_cb(struct file_lock **onlist, int arg) +{ + if (arg & F_UNLCK) + return lease_modify(onlist, arg); + else + return -EAGAIN; +} + struct lock_manager_operations nfsd_lease_mng_ops = { - .fl_break = nfsd_break_deleg_cb, - .fl_release_private = nfsd_release_deleg_cb, - .fl_copy_lock = nfsd_copy_lock_deleg_cb, + .fl_break = nfsd_break_deleg_cb, + .fl_release_private = nfsd_release_deleg_cb, + .fl_copy_lock = nfsd_copy_lock_deleg_cb, + .fl_mylease = nfsd_same_client_deleg_cb, + .fl_change = nfsd_change_deleg_cb, }; @@ -1501,25 +1530,6 @@ out: } static int -nfs4_check_deleg_recall(struct nfs4_file *fp, struct nfsd4_open *op, int *flag) -{ - struct nfs4_delegation *dp; - int status = 0; - - list_for_each_entry(dp, &fp->fi_del_perfile, dl_del_perfile) { - if (op->op_share_access & NFS4_SHARE_ACCESS_WRITE - || op->op_stateowner->so_client == dp->dl_client) { - *flag = NFS4_OPEN_DELEGATE_NONE; - goto out; - } - } -out: - dprintk("NFSD: nfs4_check_deleg_recall returns %d with flag %d\n", - status, *flag); - return status; -} - -static int nfs4_check_open(struct nfs4_file *fp, struct nfs4_stateowner *sop, struct nfsd4_open *open, struct nfs4_stateid **stpp) { struct nfs4_stateid *local; @@ -1623,31 +1633,28 @@ nfs4_set_claim_prev(struct nfsd4_open *open, int *status) * Attempt to hand out a delegation. */ static void -nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_stateid *stp, int *flag) +nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_stateid *stp) { struct nfs4_delegation *dp; struct nfs4_stateowner *sop = stp->st_stateowner; struct nfs4_callback *cb = &sop->so_client->cl_callback; struct file_lock fl, *flp = &fl; - int status; - - if (*flag == NFS4_OPEN_DELEGATE_NONE) - return; + int status, flag = 0; - *flag = NFS4_OPEN_DELEGATE_NONE; + flag = NFS4_OPEN_DELEGATE_NONE; if (open->op_claim_type != NFS4_OPEN_CLAIM_NULL || !atomic_read(&cb->cb_set) || !sop->so_confirmed) - return; + goto out; if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) - *flag = NFS4_OPEN_DELEGATE_WRITE; + flag = NFS4_OPEN_DELEGATE_WRITE; else - *flag = NFS4_OPEN_DELEGATE_READ; + flag = NFS4_OPEN_DELEGATE_READ; - dp = alloc_init_deleg(sop->so_client, stp, fh, *flag); + dp = alloc_init_deleg(sop->so_client, stp, fh, flag); if (dp == NULL) { - *flag = NFS4_OPEN_DELEGATE_NONE; - return; + flag = NFS4_OPEN_DELEGATE_NONE; + goto out; } locks_init_lock(&fl); fl.fl_lmops = &nfsd_lease_mng_ops; @@ -1657,15 +1664,18 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta fl.fl_file = stp->st_vfs_file; fl.fl_pid = current->tgid; + /* setlease checks to see if delegation should be handed out. + * the lock_manager callbacks fl_mylease and fl_change are used + */ if ((status = setlease(stp->st_vfs_file, - *flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK, &flp))) { + flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK, &flp))) { dprintk("NFSD: setlease failed [%d], no delegation\n", status); list_del(&dp->dl_del_perfile); list_del(&dp->dl_del_perclnt); nfs4_put_delegation(dp); free_delegation++; - *flag = NFS4_OPEN_DELEGATE_NONE; - return; + flag = NFS4_OPEN_DELEGATE_NONE; + goto out; } memcpy(&open->op_delegate_stateid, &dp->dl_stateid, sizeof(dp->dl_stateid)); @@ -1675,6 +1685,8 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta dp->dl_stateid.si_stateownerid, dp->dl_stateid.si_fileid, dp->dl_stateid.si_generation); +out: + open->op_delegate_type = flag; } /* @@ -1687,7 +1699,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf struct nfs4_file *fp = NULL; struct inode *ino = current_fh->fh_dentry->d_inode; struct nfs4_stateid *stp = NULL; - int status, delegflag = -1; + int status; status = nfserr_inval; if (!TEST_ACCESS(open->op_share_access) || !TEST_DENY(open->op_share_deny)) @@ -1701,8 +1713,6 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf if (fp) { if ((status = nfs4_check_open(fp, sop, open, &stp))) goto out; - if ((status = nfs4_check_deleg_recall(fp, open, &delegflag))) - goto out; } else { status = nfserr_resource; fp = alloc_init_file(ino); @@ -1748,8 +1758,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf * Attempt to hand out a delegation. No error return, because the * OPEN succeeds even if we fail. */ - nfs4_open_delegation(current_fh, open, stp, &delegflag); - open->op_delegate_type = delegflag; + nfs4_open_delegation(current_fh, open, stp); status = nfs_ok; diff --git a/include/linux/fs.h b/include/linux/fs.h index 3ea266972f06..c54298dd3b06 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -649,6 +649,8 @@ struct lock_manager_operations { void (*fl_copy_lock)(struct file_lock *, struct file_lock *); void (*fl_release_private)(struct file_lock *); void (*fl_break)(struct file_lock *); + int (*fl_mylease)(struct file_lock *, struct file_lock *); + int (*fl_change)(struct file_lock **, int); }; /* that will die - we need it for nfs_lock_info */ @@ -715,6 +717,7 @@ extern int flock_lock_file_wait(struct file *filp, struct file_lock *fl); extern int __break_lease(struct inode *inode, unsigned int flags); extern void lease_get_mtime(struct inode *, struct timespec *time); extern int setlease(struct file *, long, struct file_lock **); +extern int lease_modify(struct file_lock **, int); extern void remove_lease(struct file_lock *); extern int lock_may_read(struct inode *, loff_t start, unsigned long count); extern int lock_may_write(struct inode *, loff_t start, unsigned long count); |
