summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNeil Brown <neilb@cse.unsw.edu.au>2005-03-09 16:57:19 -0800
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-03-09 16:57:19 -0800
commit690589732d253ffbfef15bb4262a47616cc027a6 (patch)
tree025b0cb7c2aa622c98bcfeac769c2e3dbe6d2415
parentc6399c163142ffcdec44cd9a5920c5a4d622903a (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.c15
-rw-r--r--fs/nfsd/nfs4state.c93
-rw-r--r--include/linux/fs.h3
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);