fs/nfs/delegation.h | 9 +++++ fs/nfs/dir.c | 70 +++++++++++++++++++++------------------ fs/nfs/nfs4proc.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++--- fs/nfs/nfs4state.c | 4 ++ include/linux/nfs_fs.h | 1 5 files changed, 135 insertions(+), 36 deletions(-) diff -u --recursive --new-file --show-c-function linux-2.6.7-13-delegation_recall2/fs/nfs/delegation.h linux-2.6.7-14-delegation_open/fs/nfs/delegation.h --- linux-2.6.7-13-delegation_recall2/fs/nfs/delegation.h 2004-06-08 17:02:27.000000000 -0400 +++ linux-2.6.7-14-delegation_open/fs/nfs/delegation.h 2004-06-08 17:02:47.000000000 -0400 @@ -18,4 +18,13 @@ void nfs_return_all_delegations(struct s int nfs4_proc_delegreturn(struct inode *inode); int nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state); +static inline int nfs_have_delegation(struct inode *inode, int flags) +{ + struct nfs_delegation *delegation = &NFS_I(inode)->delegation; + + flags &= (FMODE_READ|FMODE_WRITE); + return !list_empty(&delegation->list) && + ((delegation->type & flags) == flags); +} + #endif diff -u --recursive --new-file --show-c-function linux-2.6.7-13-delegation_recall2/fs/nfs/dir.c linux-2.6.7-14-delegation_open/fs/nfs/dir.c --- linux-2.6.7-13-delegation_recall2/fs/nfs/dir.c 2004-06-08 16:59:10.000000000 -0400 +++ linux-2.6.7-14-delegation_open/fs/nfs/dir.c 2004-06-08 17:02:47.000000000 -0400 @@ -1498,10 +1498,46 @@ out: return error; } +int nfs_check_access(struct inode *inode, int mask, struct rpc_cred *cred) +{ + struct nfs_access_cache *cache = &NFS_I(inode)->cache_access; + int res; + + lock_kernel(); + if (cache->cred == cred + && time_before(jiffies, cache->jiffies + NFS_ATTRTIMEO(inode)) + && !(NFS_FLAGS(inode) & NFS_INO_INVALID_ATTR)) { + if (!(res = cache->err)) { + /* Is the mask a subset of an accepted mask? */ + if ((cache->mask & mask) == mask) + goto out; + } else { + /* ...or is it a superset of a rejected mask? */ + if ((cache->mask & mask) == cache->mask) + goto out; + } + } + + res = NFS_PROTO(inode)->access(inode, cred, mask); + if (!res || res == -EACCES) + goto add_cache; +out: + unlock_kernel(); + return res; +add_cache: + cache->jiffies = jiffies; + if (cache->cred) + put_rpccred(cache->cred); + cache->cred = cred; + cache->mask = mask; + cache->err = res; + unlock_kernel(); + return res; +} + int nfs_permission(struct inode *inode, int mask, struct nameidata *nd) { - struct nfs_access_cache *cache = &NFS_I(inode)->cache_access; struct rpc_cred *cred; int mode = inode->i_mode; int res; @@ -1536,46 +1572,16 @@ nfs_permission(struct inode *inode, int return 0; } - lock_kernel(); - if (!NFS_PROTO(inode)->access) goto out_notsup; cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0); - if (cache->cred == cred - && time_before(jiffies, cache->jiffies + NFS_ATTRTIMEO(inode)) - && !(NFS_FLAGS(inode) & NFS_INO_INVALID_ATTR)) { - if (!(res = cache->err)) { - /* Is the mask a subset of an accepted mask? */ - if ((cache->mask & mask) == mask) - goto out; - } else { - /* ...or is it a superset of a rejected mask? */ - if ((cache->mask & mask) == cache->mask) - goto out; - } - } - - res = NFS_PROTO(inode)->access(inode, cred, mask); - if (!res || res == -EACCES) - goto add_cache; -out: + res = nfs_check_access(inode, mask, cred); put_rpccred(cred); - unlock_kernel(); return res; out_notsup: nfs_revalidate_inode(NFS_SERVER(inode), inode); res = vfs_permission(inode, mask); - unlock_kernel(); - return res; -add_cache: - cache->jiffies = jiffies; - if (cache->cred) - put_rpccred(cache->cred); - cache->cred = cred; - cache->mask = mask; - cache->err = res; - unlock_kernel(); return res; } diff -u --recursive --new-file --show-c-function linux-2.6.7-13-delegation_recall2/fs/nfs/nfs4proc.c linux-2.6.7-14-delegation_open/fs/nfs/nfs4proc.c --- linux-2.6.7-13-delegation_recall2/fs/nfs/nfs4proc.c 2004-06-08 17:02:28.000000000 -0400 +++ linux-2.6.7-14-delegation_open/fs/nfs/nfs4proc.c 2004-06-08 18:36:08.000000000 -0400 @@ -324,6 +324,79 @@ static int nfs4_proc_open_confirm(struct } /* + * Returns an nfs4_state + an extra reference to the inode + */ +struct nfs4_state *nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred *cred) +{ + struct nfs_delegation *delegation = &NFS_I(inode)->delegation; + struct nfs_server *server = NFS_SERVER(inode); + struct nfs4_state_owner *sp; + struct nfs4_state *state = NULL; + int open_flags = flags & (FMODE_READ|FMODE_WRITE); + int mask = 0; + int err = 0; + + if (!nfs_have_delegation(inode, open_flags)) + return NULL; + if (!(sp = nfs4_get_state_owner(server, cred))) { + dprintk("%s: nfs4_get_state_owner failed!\n", __FUNCTION__); + return ERR_PTR(-ENOMEM); + } + down(&sp->so_sema); + state = nfs4_get_open_state(inode, sp); + if (state == NULL) { + state = ERR_PTR(-ENOMEM); + goto out_up; + } + if ((state->state & open_flags) == open_flags) { + spin_lock(&inode->i_lock); + if (open_flags & FMODE_READ) + state->nreaders++; + if (open_flags & FMODE_WRITE) + state->nwriters++; + spin_unlock(&inode->i_lock); + goto out_up; + } else if (state->state != 0) + goto discard_state; + if (flags & FMODE_READ) + mask |= MAY_READ; + if (flags & FMODE_WRITE) + mask |= MAY_WRITE; + if (flags & O_APPEND) + mask |= MAY_APPEND; + err = nfs_check_access(inode, mask, cred); + if (err != 0) + goto discard_state; + spin_lock(&inode->i_lock); + if (!nfs_have_delegation(inode, open_flags)) { + spin_unlock(&inode->i_lock); + goto discard_state; + } + memcpy(state->stateid.data, delegation->stateid.data, + sizeof(state->stateid.data)); + state->state |= open_flags; + if (open_flags & FMODE_READ) + state->nreaders++; + if (open_flags & FMODE_WRITE) + state->nwriters++; + set_bit(NFS_DELEGATED_STATE, &state->flags); + spin_unlock(&inode->i_lock); +out_up: + up(&sp->so_sema); +out: + nfs4_put_state_owner(sp); + /* For compatibility with nfs4_do_open() */ + if (state != NULL && !IS_ERR(state)) + igrab(inode); + return state; +discard_state: + up(&sp->so_sema); + nfs4_put_open_state(state); + state = ERR_PTR(err); + goto out; +} + +/* * Returns an nfs4_state + an referenced inode */ struct nfs4_state * @@ -580,7 +653,9 @@ nfs4_open_revalidate(struct inode *dir, struct inode *inode; cred = rpcauth_lookupcred(NFS_SERVER(dir)->client->cl_auth, 0); - state = nfs4_do_open(dir, &dentry->d_name, openflags, NULL, cred); + state = nfs4_open_delegated(dentry->d_inode, openflags, cred); + if (state == NULL) + state = nfs4_do_open(dir, &dentry->d_name, openflags, NULL, cred); put_rpccred(cred); if (state == ERR_PTR(-ENOENT) && dentry->d_inode == 0) return 1; @@ -758,9 +833,13 @@ nfs4_proc_setattr(struct dentry *dentry, if (size_change) { struct rpc_cred *cred = rpcauth_lookupcred(NFS_SERVER(inode)->client->cl_auth, 0); state = nfs4_find_state(inode, cred, FMODE_WRITE); - if (!state) { - state = nfs4_do_open(dentry->d_parent->d_inode, - &dentry->d_name, FMODE_WRITE, NULL, cred); + if (state == NULL) { + state = nfs4_open_delegated(dentry->d_inode, + FMODE_WRITE, cred); + if (state == NULL) + state = nfs4_do_open(dentry->d_parent->d_inode, + &dentry->d_name, FMODE_WRITE, + NULL, cred); need_iput = 1; } put_rpccred(cred); diff -u --recursive --new-file --show-c-function linux-2.6.7-13-delegation_recall2/fs/nfs/nfs4state.c linux-2.6.7-14-delegation_open/fs/nfs/nfs4state.c --- linux-2.6.7-13-delegation_recall2/fs/nfs/nfs4state.c 2004-06-08 17:02:03.000000000 -0400 +++ linux-2.6.7-14-delegation_open/fs/nfs/nfs4state.c 2004-06-08 17:02:47.000000000 -0400 @@ -462,6 +462,8 @@ __nfs4_put_open_state(struct nfs4_state list_del(&state->open_states); if (state->state != 0) { do { + if (test_bit(NFS_DELEGATED_STATE, &state->flags)) + break; status = nfs4_do_close(inode, state); if (!status) break; @@ -504,6 +506,8 @@ nfs4_close_state(struct nfs4_state *stat newstate = 0; if (state->state == 0) break; + if (test_bit(NFS_DELEGATED_STATE, &state->flags)) + break; if (state->nreaders) newstate |= FMODE_READ; if (state->nwriters) diff -u --recursive --new-file --show-c-function linux-2.6.7-13-delegation_recall2/include/linux/nfs_fs.h linux-2.6.7-14-delegation_open/include/linux/nfs_fs.h --- linux-2.6.7-13-delegation_recall2/include/linux/nfs_fs.h 2004-06-08 17:02:28.000000000 -0400 +++ linux-2.6.7-14-delegation_open/include/linux/nfs_fs.h 2004-06-08 17:02:47.000000000 -0400 @@ -307,6 +307,7 @@ extern struct inode *nfs_fhget(struct su extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *); extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *); extern int nfs_permission(struct inode *, int, struct nameidata *); +extern int nfs_check_access(struct inode *, int, struct rpc_cred *); extern int nfs_open(struct inode *, struct file *); extern int nfs_release(struct inode *, struct file *); extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *);