Commit 1afcb6ed authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'nfs-for-3.18-3' of git://git.linux-nfs.org/projects/trondmy/linux-nfs

Pull NFS client bugfixes from Trond Myklebust:
 "Highlights include:

   - stable patches to fix NFSv4.x delegation reclaim error paths
   - fix a bug whereby we were advertising NFSv4.1 but using NFSv4.2
     features
   - fix a use-after-free problem with pNFS block layouts
   - fix a memory leak in the pNFS files O_DIRECT code
   - replace an intrusive and Oops-prone performance fix in the NFSv4
     atomic open code with a safer one-line version and revert the two
     original patches"

* tag 'nfs-for-3.18-3' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
  sunrpc: fix sleeping under rcu_read_lock in gss_stringify_acceptor
  NFS: Don't try to reclaim delegation open state if recovery failed
  NFSv4: Ensure that we call FREE_STATEID when NFSv4.x stateids are revoked
  NFSv4: Fix races between nfs_remove_bad_delegation() and delegation return
  NFSv4.1: nfs41_clear_delegation_stateid shouldn't trust NFS_DELEGATED_STATE
  NFSv4: Ensure that we remove NFSv4.0 delegations when state has expired
  NFS: SEEK is an NFS v4.2 feature
  nfs: Fix use of uninitialized variable in nfs_getattr()
  nfs: Remove bogus assignment
  nfs: remove spurious WARN_ON_ONCE in write path
  pnfs/blocklayout: serialize GETDEVICEINFO calls
  nfs: fix pnfs direct write memory leak
  Revert "NFS: nfs4_do_open should add negative results to the dcache."
  Revert "NFS: remove BUG possibility in nfs4_open_and_get_state"
  NFSv4: Ensure nfs_atomic_open set the dentry verifier on ENOENT
parents 56c381f9 b3ecba09
...@@ -378,7 +378,7 @@ bl_write_pagelist(struct nfs_pgio_header *header, int sync) ...@@ -378,7 +378,7 @@ bl_write_pagelist(struct nfs_pgio_header *header, int sync)
loff_t offset = header->args.offset; loff_t offset = header->args.offset;
size_t count = header->args.count; size_t count = header->args.count;
struct page **pages = header->args.pages; struct page **pages = header->args.pages;
int pg_index = pg_index = header->args.pgbase >> PAGE_CACHE_SHIFT; int pg_index = header->args.pgbase >> PAGE_CACHE_SHIFT;
unsigned int pg_len; unsigned int pg_len;
struct blk_plug plug; struct blk_plug plug;
int i; int i;
......
...@@ -65,17 +65,18 @@ bl_resolve_deviceid(struct nfs_server *server, struct pnfs_block_volume *b, ...@@ -65,17 +65,18 @@ bl_resolve_deviceid(struct nfs_server *server, struct pnfs_block_volume *b,
dprintk("%s CREATING PIPEFS MESSAGE\n", __func__); dprintk("%s CREATING PIPEFS MESSAGE\n", __func__);
mutex_lock(&nn->bl_mutex);
bl_pipe_msg.bl_wq = &nn->bl_wq; bl_pipe_msg.bl_wq = &nn->bl_wq;
b->simple.len += 4; /* single volume */ b->simple.len += 4; /* single volume */
if (b->simple.len > PAGE_SIZE) if (b->simple.len > PAGE_SIZE)
return -EIO; goto out_unlock;
memset(msg, 0, sizeof(*msg)); memset(msg, 0, sizeof(*msg));
msg->len = sizeof(*bl_msg) + b->simple.len; msg->len = sizeof(*bl_msg) + b->simple.len;
msg->data = kzalloc(msg->len, gfp_mask); msg->data = kzalloc(msg->len, gfp_mask);
if (!msg->data) if (!msg->data)
goto out; goto out_free_data;
bl_msg = msg->data; bl_msg = msg->data;
bl_msg->type = BL_DEVICE_MOUNT, bl_msg->type = BL_DEVICE_MOUNT,
...@@ -87,7 +88,7 @@ bl_resolve_deviceid(struct nfs_server *server, struct pnfs_block_volume *b, ...@@ -87,7 +88,7 @@ bl_resolve_deviceid(struct nfs_server *server, struct pnfs_block_volume *b,
rc = rpc_queue_upcall(nn->bl_device_pipe, msg); rc = rpc_queue_upcall(nn->bl_device_pipe, msg);
if (rc < 0) { if (rc < 0) {
remove_wait_queue(&nn->bl_wq, &wq); remove_wait_queue(&nn->bl_wq, &wq);
goto out; goto out_free_data;
} }
set_current_state(TASK_UNINTERRUPTIBLE); set_current_state(TASK_UNINTERRUPTIBLE);
...@@ -97,12 +98,14 @@ bl_resolve_deviceid(struct nfs_server *server, struct pnfs_block_volume *b, ...@@ -97,12 +98,14 @@ bl_resolve_deviceid(struct nfs_server *server, struct pnfs_block_volume *b,
if (reply->status != BL_DEVICE_REQUEST_PROC) { if (reply->status != BL_DEVICE_REQUEST_PROC) {
printk(KERN_WARNING "%s failed to decode device: %d\n", printk(KERN_WARNING "%s failed to decode device: %d\n",
__func__, reply->status); __func__, reply->status);
goto out; goto out_free_data;
} }
dev = MKDEV(reply->major, reply->minor); dev = MKDEV(reply->major, reply->minor);
out: out_free_data:
kfree(msg->data); kfree(msg->data);
out_unlock:
mutex_unlock(&nn->bl_mutex);
return dev; return dev;
} }
...@@ -232,6 +235,7 @@ static int nfs4blocklayout_net_init(struct net *net) ...@@ -232,6 +235,7 @@ static int nfs4blocklayout_net_init(struct net *net)
struct nfs_net *nn = net_generic(net, nfs_net_id); struct nfs_net *nn = net_generic(net, nfs_net_id);
struct dentry *dentry; struct dentry *dentry;
mutex_init(&nn->bl_mutex);
init_waitqueue_head(&nn->bl_wq); init_waitqueue_head(&nn->bl_wq);
nn->bl_device_pipe = rpc_mkpipe_data(&bl_upcall_ops, 0); nn->bl_device_pipe = rpc_mkpipe_data(&bl_upcall_ops, 0);
if (IS_ERR(nn->bl_device_pipe)) if (IS_ERR(nn->bl_device_pipe))
......
...@@ -125,6 +125,8 @@ static int nfs_delegation_claim_opens(struct inode *inode, const nfs4_stateid *s ...@@ -125,6 +125,8 @@ static int nfs_delegation_claim_opens(struct inode *inode, const nfs4_stateid *s
continue; continue;
if (!test_bit(NFS_DELEGATED_STATE, &state->flags)) if (!test_bit(NFS_DELEGATED_STATE, &state->flags))
continue; continue;
if (!nfs4_valid_open_stateid(state))
continue;
if (!nfs4_stateid_match(&state->stateid, stateid)) if (!nfs4_stateid_match(&state->stateid, stateid))
continue; continue;
get_nfs_open_context(ctx); get_nfs_open_context(ctx);
...@@ -193,7 +195,11 @@ static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation * ...@@ -193,7 +195,11 @@ static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation *
{ {
int res = 0; int res = 0;
res = nfs4_proc_delegreturn(inode, delegation->cred, &delegation->stateid, issync); if (!test_bit(NFS_DELEGATION_REVOKED, &delegation->flags))
res = nfs4_proc_delegreturn(inode,
delegation->cred,
&delegation->stateid,
issync);
nfs_free_delegation(delegation); nfs_free_delegation(delegation);
return res; return res;
} }
...@@ -380,11 +386,13 @@ static int nfs_end_delegation_return(struct inode *inode, struct nfs_delegation ...@@ -380,11 +386,13 @@ static int nfs_end_delegation_return(struct inode *inode, struct nfs_delegation
{ {
struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
struct nfs_inode *nfsi = NFS_I(inode); struct nfs_inode *nfsi = NFS_I(inode);
int err; int err = 0;
if (delegation == NULL) if (delegation == NULL)
return 0; return 0;
do { do {
if (test_bit(NFS_DELEGATION_REVOKED, &delegation->flags))
break;
err = nfs_delegation_claim_opens(inode, &delegation->stateid); err = nfs_delegation_claim_opens(inode, &delegation->stateid);
if (!issync || err != -EAGAIN) if (!issync || err != -EAGAIN)
break; break;
...@@ -605,10 +613,23 @@ static void nfs_client_mark_return_unused_delegation_types(struct nfs_client *cl ...@@ -605,10 +613,23 @@ static void nfs_client_mark_return_unused_delegation_types(struct nfs_client *cl
rcu_read_unlock(); rcu_read_unlock();
} }
static void nfs_revoke_delegation(struct inode *inode)
{
struct nfs_delegation *delegation;
rcu_read_lock();
delegation = rcu_dereference(NFS_I(inode)->delegation);
if (delegation != NULL) {
set_bit(NFS_DELEGATION_REVOKED, &delegation->flags);
nfs_mark_return_delegation(NFS_SERVER(inode), delegation);
}
rcu_read_unlock();
}
void nfs_remove_bad_delegation(struct inode *inode) void nfs_remove_bad_delegation(struct inode *inode)
{ {
struct nfs_delegation *delegation; struct nfs_delegation *delegation;
nfs_revoke_delegation(inode);
delegation = nfs_inode_detach_delegation(inode); delegation = nfs_inode_detach_delegation(inode);
if (delegation) { if (delegation) {
nfs_inode_find_state_and_recover(inode, &delegation->stateid); nfs_inode_find_state_and_recover(inode, &delegation->stateid);
......
...@@ -31,6 +31,7 @@ enum { ...@@ -31,6 +31,7 @@ enum {
NFS_DELEGATION_RETURN_IF_CLOSED, NFS_DELEGATION_RETURN_IF_CLOSED,
NFS_DELEGATION_REFERENCED, NFS_DELEGATION_REFERENCED,
NFS_DELEGATION_RETURNING, NFS_DELEGATION_RETURNING,
NFS_DELEGATION_REVOKED,
}; };
int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res);
......
...@@ -1527,6 +1527,7 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry, ...@@ -1527,6 +1527,7 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry,
case -ENOENT: case -ENOENT:
d_drop(dentry); d_drop(dentry);
d_add(dentry, NULL); d_add(dentry, NULL);
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
break; break;
case -EISDIR: case -EISDIR:
case -ENOTDIR: case -ENOTDIR:
......
...@@ -266,6 +266,7 @@ static void nfs_direct_req_free(struct kref *kref) ...@@ -266,6 +266,7 @@ static void nfs_direct_req_free(struct kref *kref)
{ {
struct nfs_direct_req *dreq = container_of(kref, struct nfs_direct_req, kref); struct nfs_direct_req *dreq = container_of(kref, struct nfs_direct_req, kref);
nfs_free_pnfs_ds_cinfo(&dreq->ds_cinfo);
if (dreq->l_ctx != NULL) if (dreq->l_ctx != NULL)
nfs_put_lock_context(dreq->l_ctx); nfs_put_lock_context(dreq->l_ctx);
if (dreq->ctx != NULL) if (dreq->ctx != NULL)
......
...@@ -145,9 +145,6 @@ static int filelayout_async_handle_error(struct rpc_task *task, ...@@ -145,9 +145,6 @@ static int filelayout_async_handle_error(struct rpc_task *task,
case -NFS4ERR_DELEG_REVOKED: case -NFS4ERR_DELEG_REVOKED:
case -NFS4ERR_ADMIN_REVOKED: case -NFS4ERR_ADMIN_REVOKED:
case -NFS4ERR_BAD_STATEID: case -NFS4ERR_BAD_STATEID:
if (state == NULL)
break;
nfs_remove_bad_delegation(state->inode);
case -NFS4ERR_OPENMODE: case -NFS4ERR_OPENMODE:
if (state == NULL) if (state == NULL)
break; break;
......
...@@ -626,7 +626,7 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) ...@@ -626,7 +626,7 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
{ {
struct inode *inode = dentry->d_inode; struct inode *inode = dentry->d_inode;
int need_atime = NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATIME; int need_atime = NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATIME;
int err; int err = 0;
trace_nfs_getattr_enter(inode); trace_nfs_getattr_enter(inode);
/* Flush out writes to the server in order to update c/mtime. */ /* Flush out writes to the server in order to update c/mtime. */
......
...@@ -19,6 +19,7 @@ struct nfs_net { ...@@ -19,6 +19,7 @@ struct nfs_net {
struct rpc_pipe *bl_device_pipe; struct rpc_pipe *bl_device_pipe;
struct bl_dev_msg bl_mount_reply; struct bl_dev_msg bl_mount_reply;
wait_queue_head_t bl_wq; wait_queue_head_t bl_wq;
struct mutex bl_mutex;
struct list_head nfs_client_list; struct list_head nfs_client_list;
struct list_head nfs_volume_list; struct list_head nfs_volume_list;
#if IS_ENABLED(CONFIG_NFS_V4) #if IS_ENABLED(CONFIG_NFS_V4)
......
...@@ -370,11 +370,6 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc ...@@ -370,11 +370,6 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc
case -NFS4ERR_DELEG_REVOKED: case -NFS4ERR_DELEG_REVOKED:
case -NFS4ERR_ADMIN_REVOKED: case -NFS4ERR_ADMIN_REVOKED:
case -NFS4ERR_BAD_STATEID: case -NFS4ERR_BAD_STATEID:
if (inode != NULL && nfs4_have_delegation(inode, FMODE_READ)) {
nfs_remove_bad_delegation(inode);
exception->retry = 1;
break;
}
if (state == NULL) if (state == NULL)
break; break;
ret = nfs4_schedule_stateid_recovery(server, state); ret = nfs4_schedule_stateid_recovery(server, state);
...@@ -1654,7 +1649,7 @@ static int nfs4_handle_delegation_recall_error(struct nfs_server *server, struct ...@@ -1654,7 +1649,7 @@ static int nfs4_handle_delegation_recall_error(struct nfs_server *server, struct
nfs_inode_find_state_and_recover(state->inode, nfs_inode_find_state_and_recover(state->inode,
stateid); stateid);
nfs4_schedule_stateid_recovery(server, state); nfs4_schedule_stateid_recovery(server, state);
return 0; return -EAGAIN;
case -NFS4ERR_DELAY: case -NFS4ERR_DELAY:
case -NFS4ERR_GRACE: case -NFS4ERR_GRACE:
set_bit(NFS_DELEGATED_STATE, &state->flags); set_bit(NFS_DELEGATED_STATE, &state->flags);
...@@ -2109,45 +2104,59 @@ static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *sta ...@@ -2109,45 +2104,59 @@ static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *sta
return ret; return ret;
} }
static void nfs_finish_clear_delegation_stateid(struct nfs4_state *state)
{
nfs_remove_bad_delegation(state->inode);
write_seqlock(&state->seqlock);
nfs4_stateid_copy(&state->stateid, &state->open_stateid);
write_sequnlock(&state->seqlock);
clear_bit(NFS_DELEGATED_STATE, &state->flags);
}
static void nfs40_clear_delegation_stateid(struct nfs4_state *state)
{
if (rcu_access_pointer(NFS_I(state->inode)->delegation) != NULL)
nfs_finish_clear_delegation_stateid(state);
}
static int nfs40_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state)
{
/* NFSv4.0 doesn't allow for delegation recovery on open expire */
nfs40_clear_delegation_stateid(state);
return nfs4_open_expired(sp, state);
}
#if defined(CONFIG_NFS_V4_1) #if defined(CONFIG_NFS_V4_1)
static void nfs41_clear_delegation_stateid(struct nfs4_state *state) static void nfs41_check_delegation_stateid(struct nfs4_state *state)
{ {
struct nfs_server *server = NFS_SERVER(state->inode); struct nfs_server *server = NFS_SERVER(state->inode);
nfs4_stateid *stateid = &state->stateid; nfs4_stateid stateid;
struct nfs_delegation *delegation; struct nfs_delegation *delegation;
struct rpc_cred *cred = NULL; struct rpc_cred *cred;
int status = -NFS4ERR_BAD_STATEID; int status;
/* If a state reset has been done, test_stateid is unneeded */
if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0)
return;
/* Get the delegation credential for use by test/free_stateid */ /* Get the delegation credential for use by test/free_stateid */
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 && if (delegation == NULL) {
nfs4_stateid_match(&delegation->stateid, stateid)) { rcu_read_unlock();
return;
}
nfs4_stateid_copy(&stateid, &delegation->stateid);
cred = get_rpccred(delegation->cred); cred = get_rpccred(delegation->cred);
rcu_read_unlock(); rcu_read_unlock();
status = nfs41_test_stateid(server, stateid, cred); status = nfs41_test_stateid(server, &stateid, cred);
trace_nfs4_test_delegation_stateid(state, NULL, status); trace_nfs4_test_delegation_stateid(state, NULL, status);
} else
rcu_read_unlock();
if (status != NFS_OK) { if (status != NFS_OK) {
/* Free the stateid unless the server explicitly /* Free the stateid unless the server explicitly
* informs us the stateid is unrecognized. */ * informs us the stateid is unrecognized. */
if (status != -NFS4ERR_BAD_STATEID) if (status != -NFS4ERR_BAD_STATEID)
nfs41_free_stateid(server, stateid, cred); nfs41_free_stateid(server, &stateid, cred);
nfs_remove_bad_delegation(state->inode); nfs_finish_clear_delegation_stateid(state);
write_seqlock(&state->seqlock);
nfs4_stateid_copy(&state->stateid, &state->open_stateid);
write_sequnlock(&state->seqlock);
clear_bit(NFS_DELEGATED_STATE, &state->flags);
} }
if (cred != NULL)
put_rpccred(cred); put_rpccred(cred);
} }
...@@ -2192,7 +2201,7 @@ static int nfs41_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *st ...@@ -2192,7 +2201,7 @@ static int nfs41_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *st
{ {
int status; int status;
nfs41_clear_delegation_stateid(state); nfs41_check_delegation_stateid(state);
status = nfs41_check_open_stateid(state); status = nfs41_check_open_stateid(state);
if (status != NFS_OK) if (status != NFS_OK)
status = nfs4_open_expired(sp, state); status = nfs4_open_expired(sp, state);
...@@ -2231,19 +2240,8 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata, ...@@ -2231,19 +2240,8 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata,
seq = raw_seqcount_begin(&sp->so_reclaim_seqcount); seq = raw_seqcount_begin(&sp->so_reclaim_seqcount);
ret = _nfs4_proc_open(opendata); ret = _nfs4_proc_open(opendata);
if (ret != 0) { if (ret != 0)
if (ret == -ENOENT) {
dentry = opendata->dentry;
if (dentry->d_inode)
d_delete(dentry);
else if (d_unhashed(dentry))
d_add(dentry, NULL);
nfs_set_verifier(dentry,
nfs_save_change_attribute(opendata->dir->d_inode));
}
goto out; goto out;
}
state = nfs4_opendata_to_nfs4_state(opendata); state = nfs4_opendata_to_nfs4_state(opendata);
ret = PTR_ERR(state); ret = PTR_ERR(state);
...@@ -4841,9 +4839,6 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, ...@@ -4841,9 +4839,6 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server,
case -NFS4ERR_DELEG_REVOKED: case -NFS4ERR_DELEG_REVOKED:
case -NFS4ERR_ADMIN_REVOKED: case -NFS4ERR_ADMIN_REVOKED:
case -NFS4ERR_BAD_STATEID: case -NFS4ERR_BAD_STATEID:
if (state == NULL)
break;
nfs_remove_bad_delegation(state->inode);
case -NFS4ERR_OPENMODE: case -NFS4ERR_OPENMODE:
if (state == NULL) if (state == NULL)
break; break;
...@@ -8341,7 +8336,7 @@ static const struct nfs4_state_recovery_ops nfs41_reboot_recovery_ops = { ...@@ -8341,7 +8336,7 @@ static const struct nfs4_state_recovery_ops nfs41_reboot_recovery_ops = {
static const struct nfs4_state_recovery_ops nfs40_nograce_recovery_ops = { static const struct nfs4_state_recovery_ops nfs40_nograce_recovery_ops = {
.owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE, .owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE,
.state_flag_bit = NFS_STATE_RECLAIM_NOGRACE, .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE,
.recover_open = nfs4_open_expired, .recover_open = nfs40_open_expired,
.recover_lock = nfs4_lock_expired, .recover_lock = nfs4_lock_expired,
.establish_clid = nfs4_init_clientid, .establish_clid = nfs4_init_clientid,
}; };
...@@ -8408,8 +8403,7 @@ static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = { ...@@ -8408,8 +8403,7 @@ static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = {
| NFS_CAP_CHANGE_ATTR | NFS_CAP_CHANGE_ATTR
| NFS_CAP_POSIX_LOCK | NFS_CAP_POSIX_LOCK
| NFS_CAP_STATEID_NFSV41 | NFS_CAP_STATEID_NFSV41
| NFS_CAP_ATOMIC_OPEN_V1 | NFS_CAP_ATOMIC_OPEN_V1,
| NFS_CAP_SEEK,
.init_client = nfs41_init_client, .init_client = nfs41_init_client,
.shutdown_client = nfs41_shutdown_client, .shutdown_client = nfs41_shutdown_client,
.match_stateid = nfs41_match_stateid, .match_stateid = nfs41_match_stateid,
...@@ -8431,7 +8425,8 @@ static const struct nfs4_minor_version_ops nfs_v4_2_minor_ops = { ...@@ -8431,7 +8425,8 @@ static const struct nfs4_minor_version_ops nfs_v4_2_minor_ops = {
| NFS_CAP_CHANGE_ATTR | NFS_CAP_CHANGE_ATTR
| NFS_CAP_POSIX_LOCK | NFS_CAP_POSIX_LOCK
| NFS_CAP_STATEID_NFSV41 | NFS_CAP_STATEID_NFSV41
| NFS_CAP_ATOMIC_OPEN_V1, | NFS_CAP_ATOMIC_OPEN_V1
| NFS_CAP_SEEK,
.init_client = nfs41_init_client, .init_client = nfs41_init_client,
.shutdown_client = nfs41_shutdown_client, .shutdown_client = nfs41_shutdown_client,
.match_stateid = nfs41_match_stateid, .match_stateid = nfs41_match_stateid,
......
...@@ -715,8 +715,6 @@ static void nfs_inode_remove_request(struct nfs_page *req) ...@@ -715,8 +715,6 @@ static void nfs_inode_remove_request(struct nfs_page *req)
if (test_and_clear_bit(PG_INODE_REF, &req->wb_flags)) if (test_and_clear_bit(PG_INODE_REF, &req->wb_flags))
nfs_release_request(req); nfs_release_request(req);
else
WARN_ON_ONCE(1);
} }
static void static void
......
...@@ -1224,11 +1224,22 @@ struct nfs41_free_stateid_res { ...@@ -1224,11 +1224,22 @@ struct nfs41_free_stateid_res {
unsigned int status; unsigned int status;
}; };
static inline void
nfs_free_pnfs_ds_cinfo(struct pnfs_ds_commit_info *cinfo)
{
kfree(cinfo->buckets);
}
#else #else
struct pnfs_ds_commit_info { struct pnfs_ds_commit_info {
}; };
static inline void
nfs_free_pnfs_ds_cinfo(struct pnfs_ds_commit_info *cinfo)
{
}
#endif /* CONFIG_NFS_V4_1 */ #endif /* CONFIG_NFS_V4_1 */
#ifdef CONFIG_NFS_V4_2 #ifdef CONFIG_NFS_V4_2
......
...@@ -1353,6 +1353,7 @@ gss_stringify_acceptor(struct rpc_cred *cred) ...@@ -1353,6 +1353,7 @@ gss_stringify_acceptor(struct rpc_cred *cred)
char *string = NULL; char *string = NULL;
struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base);
struct gss_cl_ctx *ctx; struct gss_cl_ctx *ctx;
unsigned int len;
struct xdr_netobj *acceptor; struct xdr_netobj *acceptor;
rcu_read_lock(); rcu_read_lock();
...@@ -1360,15 +1361,39 @@ gss_stringify_acceptor(struct rpc_cred *cred) ...@@ -1360,15 +1361,39 @@ gss_stringify_acceptor(struct rpc_cred *cred)
if (!ctx) if (!ctx)
goto out; goto out;
acceptor = &ctx->gc_acceptor; len = ctx->gc_acceptor.len;
rcu_read_unlock();
/* no point if there's no string */ /* no point if there's no string */
if (!acceptor->len) if (!len)
goto out; return NULL;
realloc:
string = kmalloc(acceptor->len + 1, GFP_KERNEL); string = kmalloc(len + 1, GFP_KERNEL);
if (!string) if (!string)
return NULL;
rcu_read_lock();
ctx = rcu_dereference(gss_cred->gc_ctx);
/* did the ctx disappear or was it replaced by one with no acceptor? */
if (!ctx || !ctx->gc_acceptor.len) {
kfree(string);
string = NULL;
goto out; goto out;
}
acceptor = &ctx->gc_acceptor;
/*
* Did we find a new acceptor that's longer than the original? Allocate
* a longer buffer and try again.
*/
if (len < acceptor->len) {
len = acceptor->len;
rcu_read_unlock();
kfree(string);
goto realloc;
}
memcpy(string, acceptor->data, acceptor->len); memcpy(string, acceptor->data, acceptor->len);
string[acceptor->len] = '\0'; string[acceptor->len] = '\0';
......
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