Commit 3e1f900b authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.linux-nfs.org/pub/linux/nfs-2.6

* git://git.linux-nfs.org/pub/linux/nfs-2.6:
  NFSv4: handle lack of clientaddr in option string
  NFSv4: debug print ntohl(status) in nfs client callback xdr code
  SUNRPC: Clean up the sillyrename code
  NFS: Introduce struct nfs_removeargs+nfs_removeres
  NFS: Use dentry->d_time to store the parent directory verifier.
  SUNRPC: move bkl locking and xdr proc invocation into a common helper
  NFSv4: Fix the nfsv4 readlink reply buffer alignment
  NFSv4: Fix the readdir reply buffer alignment
  NFSv4: More NFSv4 xdr cleanups
  NFSv4: Try to recover from getfh failures in nfs4_xdr_dec_open
  NFSv4: 'constify' lookup arguments.
  NFSv4: Don't fail nfs4_xdr_dec_open if decode_restorefh() failed
  NFSv4: Fix open state recovery
  NFSD/SUNRPC: Fix the automatic selection of RPCSEC_GSS
parents 12795067 0a87cf12
...@@ -1674,7 +1674,7 @@ config NFSD_V3_ACL ...@@ -1674,7 +1674,7 @@ config NFSD_V3_ACL
config NFSD_V4 config NFSD_V4
bool "Provide NFSv4 server support (EXPERIMENTAL)" bool "Provide NFSv4 server support (EXPERIMENTAL)"
depends on NFSD_V3 && EXPERIMENTAL depends on NFSD && NFSD_V3 && EXPERIMENTAL
select RPCSEC_GSS_KRB5 select RPCSEC_GSS_KRB5
help help
If you would like to include the NFSv4 server as well as the NFSv2 If you would like to include the NFSv4 server as well as the NFSv2
......
...@@ -179,7 +179,7 @@ static __be32 decode_getattr_args(struct svc_rqst *rqstp, struct xdr_stream *xdr ...@@ -179,7 +179,7 @@ static __be32 decode_getattr_args(struct svc_rqst *rqstp, struct xdr_stream *xdr
args->addr = svc_addr_in(rqstp); args->addr = svc_addr_in(rqstp);
status = decode_bitmap(xdr, args->bitmap); status = decode_bitmap(xdr, args->bitmap);
out: out:
dprintk("%s: exit with status = %d\n", __FUNCTION__, status); dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(status));
return status; return status;
} }
...@@ -200,7 +200,7 @@ static __be32 decode_recall_args(struct svc_rqst *rqstp, struct xdr_stream *xdr, ...@@ -200,7 +200,7 @@ static __be32 decode_recall_args(struct svc_rqst *rqstp, struct xdr_stream *xdr,
args->truncate = ntohl(*p); args->truncate = ntohl(*p);
status = decode_fh(xdr, &args->fh); status = decode_fh(xdr, &args->fh);
out: out:
dprintk("%s: exit with status = %d\n", __FUNCTION__, status); dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(status));
return status; return status;
} }
...@@ -349,7 +349,7 @@ static __be32 encode_getattr_res(struct svc_rqst *rqstp, struct xdr_stream *xdr, ...@@ -349,7 +349,7 @@ static __be32 encode_getattr_res(struct svc_rqst *rqstp, struct xdr_stream *xdr,
status = encode_attr_mtime(xdr, res->bitmap, &res->mtime); status = encode_attr_mtime(xdr, res->bitmap, &res->mtime);
*savep = htonl((unsigned int)((char *)xdr->p - (char *)(savep+1))); *savep = htonl((unsigned int)((char *)xdr->p - (char *)(savep+1)));
out: out:
dprintk("%s: exit with status = %d\n", __FUNCTION__, status); dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(status));
return status; return status;
} }
...@@ -392,7 +392,7 @@ static __be32 process_op(struct svc_rqst *rqstp, ...@@ -392,7 +392,7 @@ static __be32 process_op(struct svc_rqst *rqstp,
status = res; status = res;
if (op->encode_res != NULL && status == 0) if (op->encode_res != NULL && status == 0)
status = op->encode_res(rqstp, xdr_out, resp); status = op->encode_res(rqstp, xdr_out, resp);
dprintk("%s: done, status = %d\n", __FUNCTION__, status); dprintk("%s: done, status = %d\n", __FUNCTION__, ntohl(status));
return status; return status;
} }
...@@ -431,7 +431,7 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r ...@@ -431,7 +431,7 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r
} }
*hdr_res.status = status; *hdr_res.status = status;
*hdr_res.nops = htonl(nops); *hdr_res.nops = htonl(nops);
dprintk("%s: done, status = %u\n", __FUNCTION__, status); dprintk("%s: done, status = %u\n", __FUNCTION__, ntohl(status));
return rpc_success; return rpc_success;
} }
......
...@@ -654,7 +654,7 @@ static int nfs_check_verifier(struct inode *dir, struct dentry *dentry) ...@@ -654,7 +654,7 @@ static int nfs_check_verifier(struct inode *dir, struct dentry *dentry)
if (IS_ROOT(dentry)) if (IS_ROOT(dentry))
return 1; return 1;
verf = (unsigned long)dentry->d_fsdata; verf = dentry->d_time;
if (nfs_caches_unstable(dir) if (nfs_caches_unstable(dir)
|| verf != NFS_I(dir)->cache_change_attribute) || verf != NFS_I(dir)->cache_change_attribute)
return 0; return 0;
...@@ -663,7 +663,7 @@ static int nfs_check_verifier(struct inode *dir, struct dentry *dentry) ...@@ -663,7 +663,7 @@ static int nfs_check_verifier(struct inode *dir, struct dentry *dentry)
static inline void nfs_set_verifier(struct dentry * dentry, unsigned long verf) static inline void nfs_set_verifier(struct dentry * dentry, unsigned long verf)
{ {
dentry->d_fsdata = (void *)verf; dentry->d_time = verf;
} }
static void nfs_refresh_verifier(struct dentry * dentry, unsigned long verf) static void nfs_refresh_verifier(struct dentry * dentry, unsigned long verf)
...@@ -869,7 +869,7 @@ static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode) ...@@ -869,7 +869,7 @@ static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode)
if (dentry->d_flags & DCACHE_NFSFS_RENAMED) { if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
lock_kernel(); lock_kernel();
drop_nlink(inode); drop_nlink(inode);
nfs_complete_unlink(dentry); nfs_complete_unlink(dentry, inode);
unlock_kernel(); unlock_kernel();
} }
/* When creating a negative dentry, we want to renew d_time */ /* When creating a negative dentry, we want to renew d_time */
...@@ -1411,7 +1411,7 @@ static int nfs_sillyrename(struct inode *dir, struct dentry *dentry) ...@@ -1411,7 +1411,7 @@ static int nfs_sillyrename(struct inode *dir, struct dentry *dentry)
nfs_renew_times(dentry); nfs_renew_times(dentry);
nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
d_move(dentry, sdentry); d_move(dentry, sdentry);
error = nfs_async_unlink(dentry); error = nfs_async_unlink(dir, dentry);
/* If we return 0 we don't unlink */ /* If we return 0 we don't unlink */
} }
dput(sdentry); dput(sdentry);
......
...@@ -43,6 +43,7 @@ ...@@ -43,6 +43,7 @@
#define NFS_entry_sz (NFS_filename_sz+3) #define NFS_entry_sz (NFS_filename_sz+3)
#define NFS_diropargs_sz (NFS_fhandle_sz+NFS_filename_sz) #define NFS_diropargs_sz (NFS_fhandle_sz+NFS_filename_sz)
#define NFS_removeargs_sz (NFS_fhandle_sz+NFS_filename_sz)
#define NFS_sattrargs_sz (NFS_fhandle_sz+NFS_sattr_sz) #define NFS_sattrargs_sz (NFS_fhandle_sz+NFS_sattr_sz)
#define NFS_readlinkargs_sz (NFS_fhandle_sz) #define NFS_readlinkargs_sz (NFS_fhandle_sz)
#define NFS_readargs_sz (NFS_fhandle_sz+3) #define NFS_readargs_sz (NFS_fhandle_sz+3)
...@@ -66,7 +67,7 @@ ...@@ -66,7 +67,7 @@
* Common NFS XDR functions as inlines * Common NFS XDR functions as inlines
*/ */
static inline __be32 * static inline __be32 *
xdr_encode_fhandle(__be32 *p, struct nfs_fh *fhandle) xdr_encode_fhandle(__be32 *p, const struct nfs_fh *fhandle)
{ {
memcpy(p, fhandle->data, NFS2_FHSIZE); memcpy(p, fhandle->data, NFS2_FHSIZE);
return p + XDR_QUADLEN(NFS2_FHSIZE); return p + XDR_QUADLEN(NFS2_FHSIZE);
...@@ -204,7 +205,7 @@ nfs_xdr_sattrargs(struct rpc_rqst *req, __be32 *p, struct nfs_sattrargs *args) ...@@ -204,7 +205,7 @@ nfs_xdr_sattrargs(struct rpc_rqst *req, __be32 *p, struct nfs_sattrargs *args)
/* /*
* Encode directory ops argument * Encode directory ops argument
* LOOKUP, REMOVE, RMDIR * LOOKUP, RMDIR
*/ */
static int static int
nfs_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs_diropargs *args) nfs_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs_diropargs *args)
...@@ -215,6 +216,18 @@ nfs_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs_diropargs *args) ...@@ -215,6 +216,18 @@ nfs_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs_diropargs *args)
return 0; return 0;
} }
/*
* Encode REMOVE argument
*/
static int
nfs_xdr_removeargs(struct rpc_rqst *req, __be32 *p, const struct nfs_removeargs *args)
{
p = xdr_encode_fhandle(p, args->fh);
p = xdr_encode_array(p, args->name.name, args->name.len);
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
return 0;
}
/* /*
* Arguments to a READ call. Since we read data directly into the page * Arguments to a READ call. Since we read data directly into the page
* cache, we also set up the reply iovec here so that iov[1] points * cache, we also set up the reply iovec here so that iov[1] points
...@@ -705,7 +718,7 @@ struct rpc_procinfo nfs_procedures[] = { ...@@ -705,7 +718,7 @@ struct rpc_procinfo nfs_procedures[] = {
PROC(READ, readargs, readres, 3), PROC(READ, readargs, readres, 3),
PROC(WRITE, writeargs, writeres, 4), PROC(WRITE, writeargs, writeres, 4),
PROC(CREATE, createargs, diropres, 0), PROC(CREATE, createargs, diropres, 0),
PROC(REMOVE, diropargs, stat, 0), PROC(REMOVE, removeargs, stat, 0),
PROC(RENAME, renameargs, stat, 0), PROC(RENAME, renameargs, stat, 0),
PROC(LINK, linkargs, stat, 0), PROC(LINK, linkargs, stat, 0),
PROC(SYMLINK, symlinkargs, stat, 0), PROC(SYMLINK, symlinkargs, stat, 0),
......
...@@ -349,62 +349,42 @@ out: ...@@ -349,62 +349,42 @@ out:
static int static int
nfs3_proc_remove(struct inode *dir, struct qstr *name) nfs3_proc_remove(struct inode *dir, struct qstr *name)
{ {
struct nfs_fattr dir_attr; struct nfs_removeargs arg = {
struct nfs3_diropargs arg = {
.fh = NFS_FH(dir), .fh = NFS_FH(dir),
.name = name->name, .name.len = name->len,
.len = name->len .name.name = name->name,
}; };
struct nfs_removeres res;
struct rpc_message msg = { struct rpc_message msg = {
.rpc_proc = &nfs3_procedures[NFS3PROC_REMOVE], .rpc_proc = &nfs3_procedures[NFS3PROC_REMOVE],
.rpc_argp = &arg, .rpc_argp = &arg,
.rpc_resp = &dir_attr, .rpc_resp = &res,
}; };
int status; int status;
dprintk("NFS call remove %s\n", name->name); dprintk("NFS call remove %s\n", name->name);
nfs_fattr_init(&dir_attr); nfs_fattr_init(&res.dir_attr);
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
nfs_post_op_update_inode(dir, &dir_attr); nfs_post_op_update_inode(dir, &res.dir_attr);
dprintk("NFS reply remove: %d\n", status); dprintk("NFS reply remove: %d\n", status);
return status; return status;
} }
static int static void
nfs3_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, struct qstr *name) nfs3_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)
{ {
struct unlinkxdr {
struct nfs3_diropargs arg;
struct nfs_fattr res;
} *ptr;
ptr = kmalloc(sizeof(*ptr), GFP_KERNEL);
if (!ptr)
return -ENOMEM;
ptr->arg.fh = NFS_FH(dir->d_inode);
ptr->arg.name = name->name;
ptr->arg.len = name->len;
nfs_fattr_init(&ptr->res);
msg->rpc_proc = &nfs3_procedures[NFS3PROC_REMOVE]; msg->rpc_proc = &nfs3_procedures[NFS3PROC_REMOVE];
msg->rpc_argp = &ptr->arg;
msg->rpc_resp = &ptr->res;
return 0;
} }
static int static int
nfs3_proc_unlink_done(struct dentry *dir, struct rpc_task *task) nfs3_proc_unlink_done(struct rpc_task *task, struct inode *dir)
{ {
struct rpc_message *msg = &task->tk_msg; struct nfs_removeres *res;
struct nfs_fattr *dir_attr; if (nfs3_async_handle_jukebox(task, dir))
if (nfs3_async_handle_jukebox(task, dir->d_inode))
return 1;
if (msg->rpc_argp) {
dir_attr = (struct nfs_fattr*)msg->rpc_resp;
nfs_post_op_update_inode(dir->d_inode, dir_attr);
kfree(msg->rpc_argp);
}
return 0; return 0;
res = task->tk_msg.rpc_resp;
nfs_post_op_update_inode(dir, &res->dir_attr);
return 1;
} }
static int static int
......
...@@ -50,6 +50,7 @@ ...@@ -50,6 +50,7 @@
#define NFS3_sattrargs_sz (NFS3_fh_sz+NFS3_sattr_sz+3) #define NFS3_sattrargs_sz (NFS3_fh_sz+NFS3_sattr_sz+3)
#define NFS3_diropargs_sz (NFS3_fh_sz+NFS3_filename_sz) #define NFS3_diropargs_sz (NFS3_fh_sz+NFS3_filename_sz)
#define NFS3_removeargs_sz (NFS3_fh_sz+NFS3_filename_sz)
#define NFS3_accessargs_sz (NFS3_fh_sz+1) #define NFS3_accessargs_sz (NFS3_fh_sz+1)
#define NFS3_readlinkargs_sz (NFS3_fh_sz) #define NFS3_readlinkargs_sz (NFS3_fh_sz)
#define NFS3_readargs_sz (NFS3_fh_sz+3) #define NFS3_readargs_sz (NFS3_fh_sz+3)
...@@ -65,6 +66,7 @@ ...@@ -65,6 +66,7 @@
#define NFS3_attrstat_sz (1+NFS3_fattr_sz) #define NFS3_attrstat_sz (1+NFS3_fattr_sz)
#define NFS3_wccstat_sz (1+NFS3_wcc_data_sz) #define NFS3_wccstat_sz (1+NFS3_wcc_data_sz)
#define NFS3_removeres_sz (NFS3_wccstat_sz)
#define NFS3_lookupres_sz (1+NFS3_fh_sz+(2 * NFS3_post_op_attr_sz)) #define NFS3_lookupres_sz (1+NFS3_fh_sz+(2 * NFS3_post_op_attr_sz))
#define NFS3_accessres_sz (1+NFS3_post_op_attr_sz+1) #define NFS3_accessres_sz (1+NFS3_post_op_attr_sz+1)
#define NFS3_readlinkres_sz (1+NFS3_post_op_attr_sz+1) #define NFS3_readlinkres_sz (1+NFS3_post_op_attr_sz+1)
...@@ -106,7 +108,7 @@ static struct { ...@@ -106,7 +108,7 @@ static struct {
* Common NFS XDR functions as inlines * Common NFS XDR functions as inlines
*/ */
static inline __be32 * static inline __be32 *
xdr_encode_fhandle(__be32 *p, struct nfs_fh *fh) xdr_encode_fhandle(__be32 *p, const struct nfs_fh *fh)
{ {
return xdr_encode_array(p, fh->data, fh->size); return xdr_encode_array(p, fh->data, fh->size);
} }
...@@ -299,6 +301,18 @@ nfs3_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs3_diropargs *args) ...@@ -299,6 +301,18 @@ nfs3_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs3_diropargs *args)
return 0; return 0;
} }
/*
* Encode REMOVE argument
*/
static int
nfs3_xdr_removeargs(struct rpc_rqst *req, __be32 *p, const struct nfs_removeargs *args)
{
p = xdr_encode_fhandle(p, args->fh);
p = xdr_encode_array(p, args->name.name, args->name.len);
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
return 0;
}
/* /*
* Encode access() argument * Encode access() argument
*/ */
...@@ -736,6 +750,12 @@ nfs3_xdr_wccstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr) ...@@ -736,6 +750,12 @@ nfs3_xdr_wccstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
return status; return status;
} }
static int
nfs3_xdr_removeres(struct rpc_rqst *req, __be32 *p, struct nfs_removeres *res)
{
return nfs3_xdr_wccstat(req, p, &res->dir_attr);
}
/* /*
* Decode LOOKUP reply * Decode LOOKUP reply
*/ */
...@@ -1126,7 +1146,7 @@ struct rpc_procinfo nfs3_procedures[] = { ...@@ -1126,7 +1146,7 @@ struct rpc_procinfo nfs3_procedures[] = {
PROC(MKDIR, mkdirargs, createres, 0), PROC(MKDIR, mkdirargs, createres, 0),
PROC(SYMLINK, symlinkargs, createres, 0), PROC(SYMLINK, symlinkargs, createres, 0),
PROC(MKNOD, mknodargs, createres, 0), PROC(MKNOD, mknodargs, createres, 0),
PROC(REMOVE, diropargs, wccstat, 0), PROC(REMOVE, removeargs, removeres, 0),
PROC(RMDIR, diropargs, wccstat, 0), PROC(RMDIR, diropargs, wccstat, 0),
PROC(RENAME, renameargs, renameres, 0), PROC(RENAME, renameargs, renameres, 0),
PROC(LINK, linkargs, linkres, 0), PROC(LINK, linkargs, linkres, 0),
......
...@@ -182,7 +182,7 @@ extern int nfs4_do_close(struct path *path, struct nfs4_state *state); ...@@ -182,7 +182,7 @@ extern int nfs4_do_close(struct path *path, struct nfs4_state *state);
extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *); extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *);
extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *); extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *);
extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle); extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle);
extern int nfs4_proc_fs_locations(struct inode *dir, struct qstr *name, extern int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name,
struct nfs4_fs_locations *fs_locations, struct page *page); struct nfs4_fs_locations *fs_locations, struct page *page);
extern struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops; extern struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops;
......
...@@ -66,6 +66,8 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry ...@@ -66,6 +66,8 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception); static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception);
static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs_client *clp); static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs_client *clp);
static int _nfs4_do_access(struct inode *inode, struct rpc_cred *cred, int openflags); static int _nfs4_do_access(struct inode *inode, struct rpc_cred *cred, int openflags);
static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr);
static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr);
/* Prevent leaks of NFSv4 errors into userland */ /* Prevent leaks of NFSv4 errors into userland */
int nfs4_map_errors(int err) int nfs4_map_errors(int err)
...@@ -552,6 +554,18 @@ static struct nfs_open_context *nfs4_state_find_open_context(struct nfs4_state * ...@@ -552,6 +554,18 @@ static struct nfs_open_context *nfs4_state_find_open_context(struct nfs4_state *
return ERR_PTR(-ENOENT); return ERR_PTR(-ENOENT);
} }
static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context *ctx, struct nfs4_state *state)
{
struct nfs4_opendata *opendata;
opendata = nfs4_opendata_alloc(&ctx->path, state->owner, 0, NULL);
if (opendata == NULL)
return ERR_PTR(-ENOMEM);
opendata->state = state;
atomic_inc(&state->count);
return opendata;
}
static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, mode_t openflags, struct nfs4_state **res) static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, mode_t openflags, struct nfs4_state **res)
{ {
struct nfs4_state *newstate; struct nfs4_state *newstate;
...@@ -626,12 +640,11 @@ static int _nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state ...@@ -626,12 +640,11 @@ static int _nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state
int delegation_type = 0; int delegation_type = 0;
int status; int status;
opendata = nfs4_opendata_alloc(&ctx->path, state->owner, 0, NULL); opendata = nfs4_open_recoverdata_alloc(ctx, state);
if (opendata == NULL) if (IS_ERR(opendata))
return -ENOMEM; return PTR_ERR(opendata);
opendata->o_arg.claim = NFS4_OPEN_CLAIM_PREVIOUS; opendata->o_arg.claim = NFS4_OPEN_CLAIM_PREVIOUS;
opendata->o_arg.fh = NFS_FH(state->inode); opendata->o_arg.fh = NFS_FH(state->inode);
nfs_copy_fh(&opendata->o_res.fh, opendata->o_arg.fh);
rcu_read_lock(); rcu_read_lock();
delegation = rcu_dereference(NFS_I(state->inode)->delegation); delegation = rcu_dereference(NFS_I(state->inode)->delegation);
if (delegation != NULL && (delegation->flags & NFS_DELEGATION_NEED_RECLAIM) != 0) if (delegation != NULL && (delegation->flags & NFS_DELEGATION_NEED_RECLAIM) != 0)
...@@ -672,13 +685,12 @@ static int nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *sta ...@@ -672,13 +685,12 @@ static int nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *sta
static int _nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid) static int _nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid)
{ {
struct nfs4_state_owner *sp = state->owner;
struct nfs4_opendata *opendata; struct nfs4_opendata *opendata;
int ret; int ret;
opendata = nfs4_opendata_alloc(&ctx->path, sp, 0, NULL); opendata = nfs4_open_recoverdata_alloc(ctx, state);
if (opendata == NULL) if (IS_ERR(opendata))
return -ENOMEM; return PTR_ERR(opendata);
opendata->o_arg.claim = NFS4_OPEN_CLAIM_DELEGATE_CUR; opendata->o_arg.claim = NFS4_OPEN_CLAIM_DELEGATE_CUR;
memcpy(opendata->o_arg.u.delegation.data, stateid->data, memcpy(opendata->o_arg.u.delegation.data, stateid->data,
sizeof(opendata->o_arg.u.delegation.data)); sizeof(opendata->o_arg.u.delegation.data));
...@@ -823,8 +835,10 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata) ...@@ -823,8 +835,10 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
/* Update sequence id. */ /* Update sequence id. */
data->o_arg.id = sp->so_owner_id.id; data->o_arg.id = sp->so_owner_id.id;
data->o_arg.clientid = sp->so_client->cl_clientid; data->o_arg.clientid = sp->so_client->cl_clientid;
if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) {
msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR]; msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR];
nfs_copy_fh(&data->o_res.fh, data->o_arg.fh);
}
data->timestamp = jiffies; data->timestamp = jiffies;
rpc_call_setup(task, &msg, 0); rpc_call_setup(task, &msg, 0);
return; return;
...@@ -918,6 +932,9 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) ...@@ -918,6 +932,9 @@ static int _nfs4_proc_open(struct nfs4_opendata *data)
if (status != 0 || !data->rpc_done) if (status != 0 || !data->rpc_done)
return status; return status;
if (o_res->fh.size == 0)
_nfs4_proc_lookup(dir, o_arg->name, &o_res->fh, o_res->f_attr);
if (o_arg->open_flags & O_CREAT) { if (o_arg->open_flags & O_CREAT) {
update_changeattr(dir, &o_res->cinfo); update_changeattr(dir, &o_res->cinfo);
nfs_post_op_update_inode(dir, o_res->dir_attr); nfs_post_op_update_inode(dir, o_res->dir_attr);
...@@ -929,7 +946,7 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) ...@@ -929,7 +946,7 @@ static int _nfs4_proc_open(struct nfs4_opendata *data)
return status; return status;
} }
if (!(o_res->f_attr->valid & NFS_ATTR_FATTR)) if (!(o_res->f_attr->valid & NFS_ATTR_FATTR))
return server->nfs_client->rpc_ops->getattr(server, &o_res->fh, o_res->f_attr); _nfs4_proc_getattr(server, &o_res->fh, o_res->f_attr);
return 0; return 0;
} }
...@@ -989,9 +1006,9 @@ static int _nfs4_open_expired(struct nfs_open_context *ctx, struct nfs4_state *s ...@@ -989,9 +1006,9 @@ static int _nfs4_open_expired(struct nfs_open_context *ctx, struct nfs4_state *s
struct nfs4_opendata *opendata; struct nfs4_opendata *opendata;
int ret; int ret;
opendata = nfs4_opendata_alloc(&ctx->path, state->owner, 0, NULL); opendata = nfs4_open_recoverdata_alloc(ctx, state);
if (opendata == NULL) if (IS_ERR(opendata))
return -ENOMEM; return PTR_ERR(opendata);
ret = nfs4_open_recover(opendata, state); ret = nfs4_open_recover(opendata, state);
if (ret == -ESTALE) { if (ret == -ESTALE) {
/* Invalidate the state owner so we don't ever use it again */ /* Invalidate the state owner so we don't ever use it again */
...@@ -1553,7 +1570,7 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -1553,7 +1570,7 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
* Note that we'll actually follow the referral later when * Note that we'll actually follow the referral later when
* we detect fsid mismatch in inode revalidation * we detect fsid mismatch in inode revalidation
*/ */
static int nfs4_get_referral(struct inode *dir, struct qstr *name, struct nfs_fattr *fattr, struct nfs_fh *fhandle) static int nfs4_get_referral(struct inode *dir, const struct qstr *name, struct nfs_fattr *fattr, struct nfs_fh *fhandle)
{ {
int status = -ENOMEM; int status = -ENOMEM;
struct page *page = NULL; struct page *page = NULL;
...@@ -1668,8 +1685,8 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, ...@@ -1668,8 +1685,8 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
return status; return status;
} }
static int _nfs4_proc_lookupfh(struct nfs_server *server, struct nfs_fh *dirfh, static int _nfs4_proc_lookupfh(struct nfs_server *server, const struct nfs_fh *dirfh,
struct qstr *name, struct nfs_fh *fhandle, const struct qstr *name, struct nfs_fh *fhandle,
struct nfs_fattr *fattr) struct nfs_fattr *fattr)
{ {
int status; int status;
...@@ -1715,7 +1732,7 @@ static int nfs4_proc_lookupfh(struct nfs_server *server, struct nfs_fh *dirfh, ...@@ -1715,7 +1732,7 @@ static int nfs4_proc_lookupfh(struct nfs_server *server, struct nfs_fh *dirfh,
return err; return err;
} }
static int _nfs4_proc_lookup(struct inode *dir, struct qstr *name, static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name,
struct nfs_fh *fhandle, struct nfs_fattr *fattr) struct nfs_fh *fhandle, struct nfs_fattr *fattr)
{ {
int status; int status;
...@@ -1908,15 +1925,14 @@ out: ...@@ -1908,15 +1925,14 @@ out:
static int _nfs4_proc_remove(struct inode *dir, struct qstr *name) static int _nfs4_proc_remove(struct inode *dir, struct qstr *name)
{ {
struct nfs_server *server = NFS_SERVER(dir); struct nfs_server *server = NFS_SERVER(dir);
struct nfs4_remove_arg args = { struct nfs_removeargs args = {
.fh = NFS_FH(dir), .fh = NFS_FH(dir),
.name = name, .name.len = name->len,
.name.name = name->name,
.bitmask = server->attr_bitmask, .bitmask = server->attr_bitmask,
}; };
struct nfs_fattr dir_attr; struct nfs_removeres res = {
struct nfs4_remove_res res = {
.server = server, .server = server,
.dir_attr = &dir_attr,
}; };
struct rpc_message msg = { struct rpc_message msg = {
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE], .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE],
...@@ -1925,11 +1941,11 @@ static int _nfs4_proc_remove(struct inode *dir, struct qstr *name) ...@@ -1925,11 +1941,11 @@ static int _nfs4_proc_remove(struct inode *dir, struct qstr *name)
}; };
int status; int status;
nfs_fattr_init(res.dir_attr); nfs_fattr_init(&res.dir_attr);
status = rpc_call_sync(server->client, &msg, 0); status = rpc_call_sync(server->client, &msg, 0);
if (status == 0) { if (status == 0) {
update_changeattr(dir, &res.cinfo); update_changeattr(dir, &res.cinfo);
nfs_post_op_update_inode(dir, res.dir_attr); nfs_post_op_update_inode(dir, &res.dir_attr);
} }
return status; return status;
} }
...@@ -1946,48 +1962,26 @@ static int nfs4_proc_remove(struct inode *dir, struct qstr *name) ...@@ -1946,48 +1962,26 @@ static int nfs4_proc_remove(struct inode *dir, struct qstr *name)
return err; return err;
} }
struct unlink_desc { static void nfs4_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)
struct nfs4_remove_arg args;
struct nfs4_remove_res res;
struct nfs_fattr dir_attr;
};
static int nfs4_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir,
struct qstr *name)
{ {
struct nfs_server *server = NFS_SERVER(dir->d_inode); struct nfs_server *server = NFS_SERVER(dir);
struct unlink_desc *up; struct nfs_removeargs *args = msg->rpc_argp;
struct nfs_removeres *res = msg->rpc_resp;
up = kmalloc(sizeof(*up), GFP_KERNEL);
if (!up)
return -ENOMEM;
up->args.fh = NFS_FH(dir->d_inode);
up->args.name = name;
up->args.bitmask = server->attr_bitmask;
up->res.server = server;
up->res.dir_attr = &up->dir_attr;
args->bitmask = server->attr_bitmask;
res->server = server;
msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE]; msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE];
msg->rpc_argp = &up->args;
msg->rpc_resp = &up->res;
return 0;
} }
static int nfs4_proc_unlink_done(struct dentry *dir, struct rpc_task *task) static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir)
{ {
struct rpc_message *msg = &task->tk_msg; struct nfs_removeres *res = task->tk_msg.rpc_resp;
struct unlink_desc *up;
if (msg->rpc_resp != NULL) { if (nfs4_async_handle_error(task, res->server) == -EAGAIN)
up = container_of(msg->rpc_resp, struct unlink_desc, res);
update_changeattr(dir->d_inode, &up->res.cinfo);
nfs_post_op_update_inode(dir->d_inode, up->res.dir_attr);
kfree(up);
msg->rpc_resp = NULL;
msg->rpc_argp = NULL;
}
return 0; return 0;
update_changeattr(dir, &res->cinfo);
nfs_post_op_update_inode(dir, &res->dir_attr);
return 1;
} }
static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name, static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name,
...@@ -3672,7 +3666,7 @@ ssize_t nfs4_listxattr(struct dentry *dentry, char *buf, size_t buflen) ...@@ -3672,7 +3666,7 @@ ssize_t nfs4_listxattr(struct dentry *dentry, char *buf, size_t buflen)
return len; return len;
} }
int nfs4_proc_fs_locations(struct inode *dir, struct qstr *name, int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name,
struct nfs4_fs_locations *fs_locations, struct page *page) struct nfs4_fs_locations *fs_locations, struct page *page)
{ {
struct nfs_server *server = NFS_SERVER(dir); struct nfs_server *server = NFS_SERVER(dir);
......
This diff is collapsed.
...@@ -272,10 +272,10 @@ nfs_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr, ...@@ -272,10 +272,10 @@ nfs_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
static int static int
nfs_proc_remove(struct inode *dir, struct qstr *name) nfs_proc_remove(struct inode *dir, struct qstr *name)
{ {
struct nfs_diropargs arg = { struct nfs_removeargs arg = {
.fh = NFS_FH(dir), .fh = NFS_FH(dir),
.name = name->name, .name.len = name->len,
.len = name->len .name.name = name->name,
}; };
struct rpc_message msg = { struct rpc_message msg = {
.rpc_proc = &nfs_procedures[NFSPROC_REMOVE], .rpc_proc = &nfs_procedures[NFSPROC_REMOVE],
...@@ -291,32 +291,16 @@ nfs_proc_remove(struct inode *dir, struct qstr *name) ...@@ -291,32 +291,16 @@ nfs_proc_remove(struct inode *dir, struct qstr *name)
return status; return status;
} }
static int static void
nfs_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, struct qstr *name) nfs_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)
{ {
struct nfs_diropargs *arg;
arg = kmalloc(sizeof(*arg), GFP_KERNEL);
if (!arg)
return -ENOMEM;
arg->fh = NFS_FH(dir->d_inode);
arg->name = name->name;
arg->len = name->len;
msg->rpc_proc = &nfs_procedures[NFSPROC_REMOVE]; msg->rpc_proc = &nfs_procedures[NFSPROC_REMOVE];
msg->rpc_argp = arg;
return 0;
} }
static int static int nfs_proc_unlink_done(struct rpc_task *task, struct inode *dir)
nfs_proc_unlink_done(struct dentry *dir, struct rpc_task *task)
{ {
struct rpc_message *msg = &task->tk_msg; nfs_mark_for_revalidate(dir);
return 1;
if (msg->rpc_argp) {
nfs_mark_for_revalidate(dir->d_inode);
kfree(msg->rpc_argp);
}
return 0;
} }
static int static int
......
...@@ -1685,6 +1685,9 @@ static int nfs4_validate_mount_data(struct nfs4_mount_data **options, ...@@ -1685,6 +1685,9 @@ static int nfs4_validate_mount_data(struct nfs4_mount_data **options,
dprintk("MNTPATH: %s\n", *mntpath); dprintk("MNTPATH: %s\n", *mntpath);
if (args.client_address == NULL)
goto out_no_client_address;
*ip_addr = args.client_address; *ip_addr = args.client_address;
break; break;
...@@ -1705,6 +1708,10 @@ out_inval_auth: ...@@ -1705,6 +1708,10 @@ out_inval_auth:
out_no_address: out_no_address:
dfprintk(MOUNT, "NFS4: mount program didn't pass remote address\n"); dfprintk(MOUNT, "NFS4: mount program didn't pass remote address\n");
return -EINVAL; return -EINVAL;
out_no_client_address:
dfprintk(MOUNT, "NFS4: mount program didn't pass callback address\n");
return -EINVAL;
} }
/* /*
......
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
* *
* nfs sillydelete handling * nfs sillydelete handling
* *
* NOTE: we rely on holding the BKL for list manipulation protection.
*/ */
#include <linux/slab.h> #include <linux/slab.h>
...@@ -15,46 +14,23 @@ ...@@ -15,46 +14,23 @@
struct nfs_unlinkdata { struct nfs_unlinkdata {
struct nfs_unlinkdata *next; struct nfs_removeargs args;
struct dentry *dir, *dentry; struct nfs_removeres res;
struct qstr name; struct inode *dir;
struct rpc_task task;
struct rpc_cred *cred; struct rpc_cred *cred;
unsigned int count;
}; };
static struct nfs_unlinkdata *nfs_deletes;
static RPC_WAITQ(nfs_delete_queue, "nfs_delete_queue");
/**
* nfs_detach_unlinkdata - Remove asynchronous unlink from global list
* @data: pointer to descriptor
*/
static inline void
nfs_detach_unlinkdata(struct nfs_unlinkdata *data)
{
struct nfs_unlinkdata **q;
for (q = &nfs_deletes; *q != NULL; q = &((*q)->next)) {
if (*q == data) {
*q = data->next;
break;
}
}
}
/** /**
* nfs_put_unlinkdata - release data from a sillydelete operation. * nfs_free_unlinkdata - release data from a sillydelete operation.
* @data: pointer to unlink structure. * @data: pointer to unlink structure.
*/ */
static void static void
nfs_put_unlinkdata(struct nfs_unlinkdata *data) nfs_free_unlinkdata(struct nfs_unlinkdata *data)
{ {
if (--data->count == 0) { iput(data->dir);
nfs_detach_unlinkdata(data); put_rpccred(data->cred);
kfree(data->name.name); kfree(data->args.name.name);
kfree(data); kfree(data);
}
} }
#define NAME_ALLOC_LEN(len) ((len+16) & ~15) #define NAME_ALLOC_LEN(len) ((len+16) & ~15)
...@@ -63,50 +39,36 @@ nfs_put_unlinkdata(struct nfs_unlinkdata *data) ...@@ -63,50 +39,36 @@ nfs_put_unlinkdata(struct nfs_unlinkdata *data)
* @dentry: pointer to dentry * @dentry: pointer to dentry
* @data: nfs_unlinkdata * @data: nfs_unlinkdata
*/ */
static inline void static int nfs_copy_dname(struct dentry *dentry, struct nfs_unlinkdata *data)
nfs_copy_dname(struct dentry *dentry, struct nfs_unlinkdata *data)
{ {
char *str; char *str;
int len = dentry->d_name.len; int len = dentry->d_name.len;
str = kmalloc(NAME_ALLOC_LEN(len), GFP_KERNEL); str = kmemdup(dentry->d_name.name, NAME_ALLOC_LEN(len), GFP_KERNEL);
if (!str) if (!str)
return; return -ENOMEM;
memcpy(str, dentry->d_name.name, len); data->args.name.len = len;
if (!data->name.len) { data->args.name.name = str;
data->name.len = len; return 0;
data->name.name = str;
} else
kfree(str);
} }
/** /**
* nfs_async_unlink_init - Initialize the RPC info * nfs_async_unlink_init - Initialize the RPC info
* @task: rpc_task of the sillydelete * task: rpc_task of the sillydelete
*
* We delay initializing RPC info until after the call to dentry_iput()
* in order to minimize races against rename().
*/ */
static void nfs_async_unlink_init(struct rpc_task *task, void *calldata) static void nfs_async_unlink_init(struct rpc_task *task, void *calldata)
{ {
struct nfs_unlinkdata *data = calldata; struct nfs_unlinkdata *data = calldata;
struct dentry *dir = data->dir; struct inode *dir = data->dir;
struct rpc_message msg = { struct rpc_message msg = {
.rpc_argp = &data->args,
.rpc_resp = &data->res,
.rpc_cred = data->cred, .rpc_cred = data->cred,
}; };
int status = -ENOENT;
if (!data->name.len) nfs_begin_data_update(dir);
goto out_err; NFS_PROTO(dir)->unlink_setup(&msg, dir);
status = NFS_PROTO(dir->d_inode)->unlink_setup(&msg, dir, &data->name);
if (status < 0)
goto out_err;
nfs_begin_data_update(dir->d_inode);
rpc_call_setup(task, &msg, 0); rpc_call_setup(task, &msg, 0);
return;
out_err:
rpc_exit(task, status);
} }
/** /**
...@@ -118,18 +80,12 @@ static void nfs_async_unlink_init(struct rpc_task *task, void *calldata) ...@@ -118,18 +80,12 @@ static void nfs_async_unlink_init(struct rpc_task *task, void *calldata)
static void nfs_async_unlink_done(struct rpc_task *task, void *calldata) static void nfs_async_unlink_done(struct rpc_task *task, void *calldata)
{ {
struct nfs_unlinkdata *data = calldata; struct nfs_unlinkdata *data = calldata;
struct dentry *dir = data->dir; struct inode *dir = data->dir;
struct inode *dir_i;
if (!NFS_PROTO(dir)->unlink_done(task, dir))
if (!dir) rpc_restart_call(task);
return; else
dir_i = dir->d_inode; nfs_end_data_update(dir);
nfs_end_data_update(dir_i);
if (NFS_PROTO(dir_i)->unlink_done(dir, task))
return;
put_rpccred(data->cred);
data->cred = NULL;
dput(dir);
} }
/** /**
...@@ -142,7 +98,7 @@ static void nfs_async_unlink_done(struct rpc_task *task, void *calldata) ...@@ -142,7 +98,7 @@ static void nfs_async_unlink_done(struct rpc_task *task, void *calldata)
static void nfs_async_unlink_release(void *calldata) static void nfs_async_unlink_release(void *calldata)
{ {
struct nfs_unlinkdata *data = calldata; struct nfs_unlinkdata *data = calldata;
nfs_put_unlinkdata(data); nfs_free_unlinkdata(data);
} }
static const struct rpc_call_ops nfs_unlink_ops = { static const struct rpc_call_ops nfs_unlink_ops = {
...@@ -151,73 +107,94 @@ static const struct rpc_call_ops nfs_unlink_ops = { ...@@ -151,73 +107,94 @@ static const struct rpc_call_ops nfs_unlink_ops = {
.rpc_release = nfs_async_unlink_release, .rpc_release = nfs_async_unlink_release,
}; };
static int nfs_call_unlink(struct dentry *dentry, struct nfs_unlinkdata *data)
{
struct rpc_task *task;
struct dentry *parent;
struct inode *dir;
if (nfs_copy_dname(dentry, data) < 0)
goto out_free;
parent = dget_parent(dentry);
if (parent == NULL)
goto out_free;
dir = igrab(parent->d_inode);
dput(parent);
if (dir == NULL)
goto out_free;
data->dir = dir;
data->args.fh = NFS_FH(dir);
nfs_fattr_init(&data->res.dir_attr);
task = rpc_run_task(NFS_CLIENT(dir), RPC_TASK_ASYNC, &nfs_unlink_ops, data);
if (!IS_ERR(task))
rpc_put_task(task);
return 1;
out_free:
return 0;
}
/** /**
* nfs_async_unlink - asynchronous unlinking of a file * nfs_async_unlink - asynchronous unlinking of a file
* @dir: parent directory of dentry
* @dentry: dentry to unlink * @dentry: dentry to unlink
*/ */
int int
nfs_async_unlink(struct dentry *dentry) nfs_async_unlink(struct inode *dir, struct dentry *dentry)
{ {
struct dentry *dir = dentry->d_parent;
struct nfs_unlinkdata *data; struct nfs_unlinkdata *data;
struct rpc_clnt *clnt = NFS_CLIENT(dir->d_inode);
int status = -ENOMEM; int status = -ENOMEM;
data = kzalloc(sizeof(*data), GFP_KERNEL); data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data) if (data == NULL)
goto out; goto out;
data->cred = rpcauth_lookupcred(clnt->cl_auth, 0); data->cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0);
if (IS_ERR(data->cred)) { if (IS_ERR(data->cred)) {
status = PTR_ERR(data->cred); status = PTR_ERR(data->cred);
goto out_free; goto out_free;
} }
data->dir = dget(dir);
data->dentry = dentry;
data->next = nfs_deletes;
nfs_deletes = data;
data->count = 1;
rpc_init_task(&data->task, clnt, RPC_TASK_ASYNC, &nfs_unlink_ops, data);
status = -EBUSY;
spin_lock(&dentry->d_lock); spin_lock(&dentry->d_lock);
if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
goto out_unlock;
dentry->d_flags |= DCACHE_NFSFS_RENAMED; dentry->d_flags |= DCACHE_NFSFS_RENAMED;
dentry->d_fsdata = data;
spin_unlock(&dentry->d_lock); spin_unlock(&dentry->d_lock);
return 0;
rpc_sleep_on(&nfs_delete_queue, &data->task, NULL, NULL); out_unlock:
status = 0; spin_unlock(&dentry->d_lock);
out: put_rpccred(data->cred);
return status;
out_free: out_free:
kfree(data); kfree(data);
out:
return status; return status;
} }
/** /**
* nfs_complete_unlink - Initialize completion of the sillydelete * nfs_complete_unlink - Initialize completion of the sillydelete
* @dentry: dentry to delete * @dentry: dentry to delete
* @inode: inode
* *
* Since we're most likely to be called by dentry_iput(), we * Since we're most likely to be called by dentry_iput(), we
* only use the dentry to find the sillydelete. We then copy the name * only use the dentry to find the sillydelete. We then copy the name
* into the qstr. * into the qstr.
*/ */
void void
nfs_complete_unlink(struct dentry *dentry) nfs_complete_unlink(struct dentry *dentry, struct inode *inode)
{ {
struct nfs_unlinkdata *data; struct nfs_unlinkdata *data = NULL;
for(data = nfs_deletes; data != NULL; data = data->next) {
if (dentry == data->dentry)
break;
}
if (!data)
return;
data->count++;
nfs_copy_dname(dentry, data);
spin_lock(&dentry->d_lock); spin_lock(&dentry->d_lock);
if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
dentry->d_flags &= ~DCACHE_NFSFS_RENAMED; dentry->d_flags &= ~DCACHE_NFSFS_RENAMED;
data = dentry->d_fsdata;
}
spin_unlock(&dentry->d_lock); spin_unlock(&dentry->d_lock);
rpc_wake_up_task(&data->task);
nfs_put_unlinkdata(data); if (data != NULL && (NFS_STALE(inode) || !nfs_call_unlink(dentry, data)))
nfs_free_unlinkdata(data);
} }
...@@ -407,8 +407,8 @@ extern void nfs_release_automount_timer(void); ...@@ -407,8 +407,8 @@ extern void nfs_release_automount_timer(void);
/* /*
* linux/fs/nfs/unlink.c * linux/fs/nfs/unlink.c
*/ */
extern int nfs_async_unlink(struct dentry *); extern int nfs_async_unlink(struct inode *dir, struct dentry *dentry);
extern void nfs_complete_unlink(struct dentry *); extern void nfs_complete_unlink(struct dentry *dentry, struct inode *);
/* /*
* linux/fs/nfs/write.c * linux/fs/nfs/write.c
......
...@@ -277,6 +277,21 @@ struct nfs_writeres { ...@@ -277,6 +277,21 @@ struct nfs_writeres {
const struct nfs_server *server; const struct nfs_server *server;
}; };
/*
* Common arguments to the unlink call
*/
struct nfs_removeargs {
const struct nfs_fh *fh;
struct qstr name;
const u32 * bitmask;
};
struct nfs_removeres {
const struct nfs_server *server;
struct nfs4_change_info cinfo;
struct nfs_fattr dir_attr;
};
/* /*
* Argument struct for decode_entry function * Argument struct for decode_entry function
*/ */
...@@ -631,18 +646,6 @@ struct nfs4_readlink { ...@@ -631,18 +646,6 @@ struct nfs4_readlink {
struct page ** pages; /* zero-copy data */ struct page ** pages; /* zero-copy data */
}; };
struct nfs4_remove_arg {
const struct nfs_fh * fh;
const struct qstr * name;
const u32 * bitmask;
};
struct nfs4_remove_res {
const struct nfs_server * server;
struct nfs4_change_info cinfo;
struct nfs_fattr * dir_attr;
};
struct nfs4_rename_arg { struct nfs4_rename_arg {
const struct nfs_fh * old_dir; const struct nfs_fh * old_dir;
const struct nfs_fh * new_dir; const struct nfs_fh * new_dir;
...@@ -788,9 +791,8 @@ struct nfs_rpc_ops { ...@@ -788,9 +791,8 @@ struct nfs_rpc_ops {
int (*create) (struct inode *, struct dentry *, int (*create) (struct inode *, struct dentry *,
struct iattr *, int, struct nameidata *); struct iattr *, int, struct nameidata *);
int (*remove) (struct inode *, struct qstr *); int (*remove) (struct inode *, struct qstr *);
int (*unlink_setup) (struct rpc_message *, void (*unlink_setup) (struct rpc_message *, struct inode *dir);
struct dentry *, struct qstr *); int (*unlink_done) (struct rpc_task *, struct inode *);
int (*unlink_done) (struct dentry *, struct rpc_task *);
int (*rename) (struct inode *, struct qstr *, int (*rename) (struct inode *, struct qstr *,
struct inode *, struct qstr *); struct inode *, struct qstr *);
int (*link) (struct inode *, struct inode *, struct qstr *); int (*link) (struct inode *, struct inode *, struct qstr *);
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/uio.h> #include <linux/uio.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
#include <linux/scatterlist.h> #include <linux/scatterlist.h>
#include <linux/smp_lock.h>
/* /*
* Buffer adjustment * Buffer adjustment
...@@ -35,6 +36,21 @@ struct xdr_netobj { ...@@ -35,6 +36,21 @@ struct xdr_netobj {
*/ */
typedef int (*kxdrproc_t)(void *rqstp, __be32 *data, void *obj); typedef int (*kxdrproc_t)(void *rqstp, __be32 *data, void *obj);
/*
* We're still requiring the BKL in the xdr code until it's been
* more carefully audited, at which point this wrapper will become
* unnecessary.
*/
static inline int rpc_call_xdrproc(kxdrproc_t xdrproc, void *rqstp, __be32 *data, void *obj)
{
int ret;
lock_kernel();
ret = xdrproc(rqstp, data, obj);
unlock_kernel();
return ret;
}
/* /*
* Basic structure for transmission/reception of a client XDR message. * Basic structure for transmission/reception of a client XDR message.
* Features a header (for a linear buffer containing RPC headers * Features a header (for a linear buffer containing RPC headers
......
...@@ -13,7 +13,6 @@ ...@@ -13,7 +13,6 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/sunrpc/clnt.h> #include <linux/sunrpc/clnt.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/smp_lock.h>
#ifdef RPC_DEBUG #ifdef RPC_DEBUG
# define RPCDBG_FACILITY RPCDBG_AUTH # define RPCDBG_FACILITY RPCDBG_AUTH
...@@ -476,17 +475,13 @@ rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp, ...@@ -476,17 +475,13 @@ rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp,
__be32 *data, void *obj) __be32 *data, void *obj)
{ {
struct rpc_cred *cred = task->tk_msg.rpc_cred; struct rpc_cred *cred = task->tk_msg.rpc_cred;
int ret;
dprintk("RPC: %5u using %s cred %p to wrap rpc data\n", dprintk("RPC: %5u using %s cred %p to wrap rpc data\n",
task->tk_pid, cred->cr_ops->cr_name, cred); task->tk_pid, cred->cr_ops->cr_name, cred);
if (cred->cr_ops->crwrap_req) if (cred->cr_ops->crwrap_req)
return cred->cr_ops->crwrap_req(task, encode, rqstp, data, obj); return cred->cr_ops->crwrap_req(task, encode, rqstp, data, obj);
/* By default, we encode the arguments normally. */ /* By default, we encode the arguments normally. */
lock_kernel(); return rpc_call_xdrproc(encode, rqstp, data, obj);
ret = encode(rqstp, data, obj);
unlock_kernel();
return ret;
} }
int int
...@@ -494,7 +489,6 @@ rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp, ...@@ -494,7 +489,6 @@ rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp,
__be32 *data, void *obj) __be32 *data, void *obj)
{ {
struct rpc_cred *cred = task->tk_msg.rpc_cred; struct rpc_cred *cred = task->tk_msg.rpc_cred;
int ret;
dprintk("RPC: %5u using %s cred %p to unwrap rpc data\n", dprintk("RPC: %5u using %s cred %p to unwrap rpc data\n",
task->tk_pid, cred->cr_ops->cr_name, cred); task->tk_pid, cred->cr_ops->cr_name, cred);
...@@ -502,10 +496,7 @@ rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp, ...@@ -502,10 +496,7 @@ rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp,
return cred->cr_ops->crunwrap_resp(task, decode, rqstp, return cred->cr_ops->crunwrap_resp(task, decode, rqstp,
data, obj); data, obj);
/* By default, we decode the arguments normally. */ /* By default, we decode the arguments normally. */
lock_kernel(); return rpc_call_xdrproc(decode, rqstp, data, obj);
ret = decode(rqstp, data, obj);
unlock_kernel();
return ret;
} }
int int
......
...@@ -43,7 +43,6 @@ ...@@ -43,7 +43,6 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/smp_lock.h>
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/sunrpc/clnt.h> #include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/auth.h> #include <linux/sunrpc/auth.h>
...@@ -1000,9 +999,7 @@ gss_wrap_req_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx, ...@@ -1000,9 +999,7 @@ gss_wrap_req_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
offset = (u8 *)p - (u8 *)snd_buf->head[0].iov_base; offset = (u8 *)p - (u8 *)snd_buf->head[0].iov_base;
*p++ = htonl(rqstp->rq_seqno); *p++ = htonl(rqstp->rq_seqno);
lock_kernel(); status = rpc_call_xdrproc(encode, rqstp, p, obj);
status = encode(rqstp, p, obj);
unlock_kernel();
if (status) if (status)
return status; return status;
...@@ -1096,9 +1093,7 @@ gss_wrap_req_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx, ...@@ -1096,9 +1093,7 @@ gss_wrap_req_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
offset = (u8 *)p - (u8 *)snd_buf->head[0].iov_base; offset = (u8 *)p - (u8 *)snd_buf->head[0].iov_base;
*p++ = htonl(rqstp->rq_seqno); *p++ = htonl(rqstp->rq_seqno);
lock_kernel(); status = rpc_call_xdrproc(encode, rqstp, p, obj);
status = encode(rqstp, p, obj);
unlock_kernel();
if (status) if (status)
return status; return status;
...@@ -1157,16 +1152,12 @@ gss_wrap_req(struct rpc_task *task, ...@@ -1157,16 +1152,12 @@ gss_wrap_req(struct rpc_task *task,
/* The spec seems a little ambiguous here, but I think that not /* The spec seems a little ambiguous here, but I think that not
* wrapping context destruction requests makes the most sense. * wrapping context destruction requests makes the most sense.
*/ */
lock_kernel(); status = rpc_call_xdrproc(encode, rqstp, p, obj);
status = encode(rqstp, p, obj);
unlock_kernel();
goto out; goto out;
} }
switch (gss_cred->gc_service) { switch (gss_cred->gc_service) {
case RPC_GSS_SVC_NONE: case RPC_GSS_SVC_NONE:
lock_kernel(); status = rpc_call_xdrproc(encode, rqstp, p, obj);
status = encode(rqstp, p, obj);
unlock_kernel();
break; break;
case RPC_GSS_SVC_INTEGRITY: case RPC_GSS_SVC_INTEGRITY:
status = gss_wrap_req_integ(cred, ctx, encode, status = gss_wrap_req_integ(cred, ctx, encode,
...@@ -1282,9 +1273,7 @@ gss_unwrap_resp(struct rpc_task *task, ...@@ -1282,9 +1273,7 @@ gss_unwrap_resp(struct rpc_task *task,
cred->cr_auth->au_rslack = cred->cr_auth->au_verfsize + (p - savedp) cred->cr_auth->au_rslack = cred->cr_auth->au_verfsize + (p - savedp)
+ (savedlen - head->iov_len); + (savedlen - head->iov_len);
out_decode: out_decode:
lock_kernel(); status = rpc_call_xdrproc(decode, rqstp, p, obj);
status = decode(rqstp, p, obj);
unlock_kernel();
out: out:
gss_put_ctx(ctx); gss_put_ctx(ctx);
dprintk("RPC: %5u gss_unwrap_resp returning %d\n", task->tk_pid, dprintk("RPC: %5u gss_unwrap_resp returning %d\n", task->tk_pid,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment