NFS client bugfixes for Linux 3.18
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. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJUZol9AAoJEGcL54qWCgDyNQQQALnngvpPR51BoO/iTz9ruXol fGZy0SRIlTUKm1ArsQsQ+HGbV5K0hgP3Tg+z2AtEEZ8u/2Fi2Bqdl6+eNY12tKHd uUctDdM5TXLrETAn1UULrnd2eX1cvPMBfOlXlAdNHHsGEgC7w7YQ+rzGwnls+HDy LYXzY7Y3jYGdTMaRgZc5YRdtd8JBpCxciRvPEQLDIobwP0JnZC1afTLe1XInqB2I TZ4NTHT+DEWA+Ou1P2deL7+RuJNEAeWWBvULJy76n4BqKvN/HNedOO5HyBYXrwSd 3UX3wbx9CWRxN1F0EqNKxjxZ/597JwqBeNoTDRcofLsqumUfAOtlbym1EahcD3Ls pykopNfgUhGuhxolStmuHdS6CnyQPERpR5lFZcDp7XtcwSq4FcwD8DRzLJMZW5dg N1lkfFlwQN3rqdk/NEHL+IxS41Hlk4HXjMoP6MNbRtqzIN6tW9tvC4MtAWd1aYxO YuUW281pbWxXQ731s0kTIrMUdQ9vGSRBMcbnO9rL3o+xkh8y5SPVkx9lhdhJN0UD VbQ5Ws/xZ54bD1PfyYb+Yx659lI8MSFOsDuMuLmDtfYnVicHwCA3H63StvQ3ihf/ q0gu8Iex9YbNNjf7IfYGuWPmPn3gwPBoURPC0bcZvMPdY6DXodU6Oj4BRTQ5VCie 9N0pt2wp2eRjaSzD7r5A =8YN6 -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
1afcb6ed0d
|
@ -378,7 +378,7 @@ bl_write_pagelist(struct nfs_pgio_header *header, int sync)
|
|||
loff_t offset = header->args.offset;
|
||||
size_t count = header->args.count;
|
||||
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;
|
||||
struct blk_plug plug;
|
||||
int i;
|
||||
|
|
|
@ -65,17 +65,18 @@ bl_resolve_deviceid(struct nfs_server *server, struct pnfs_block_volume *b,
|
|||
|
||||
dprintk("%s CREATING PIPEFS MESSAGE\n", __func__);
|
||||
|
||||
mutex_lock(&nn->bl_mutex);
|
||||
bl_pipe_msg.bl_wq = &nn->bl_wq;
|
||||
|
||||
b->simple.len += 4; /* single volume */
|
||||
if (b->simple.len > PAGE_SIZE)
|
||||
return -EIO;
|
||||
goto out_unlock;
|
||||
|
||||
memset(msg, 0, sizeof(*msg));
|
||||
msg->len = sizeof(*bl_msg) + b->simple.len;
|
||||
msg->data = kzalloc(msg->len, gfp_mask);
|
||||
if (!msg->data)
|
||||
goto out;
|
||||
goto out_free_data;
|
||||
|
||||
bl_msg = msg->data;
|
||||
bl_msg->type = BL_DEVICE_MOUNT,
|
||||
|
@ -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);
|
||||
if (rc < 0) {
|
||||
remove_wait_queue(&nn->bl_wq, &wq);
|
||||
goto out;
|
||||
goto out_free_data;
|
||||
}
|
||||
|
||||
set_current_state(TASK_UNINTERRUPTIBLE);
|
||||
|
@ -97,12 +98,14 @@ bl_resolve_deviceid(struct nfs_server *server, struct pnfs_block_volume *b,
|
|||
if (reply->status != BL_DEVICE_REQUEST_PROC) {
|
||||
printk(KERN_WARNING "%s failed to decode device: %d\n",
|
||||
__func__, reply->status);
|
||||
goto out;
|
||||
goto out_free_data;
|
||||
}
|
||||
|
||||
dev = MKDEV(reply->major, reply->minor);
|
||||
out:
|
||||
out_free_data:
|
||||
kfree(msg->data);
|
||||
out_unlock:
|
||||
mutex_unlock(&nn->bl_mutex);
|
||||
return dev;
|
||||
}
|
||||
|
||||
|
@ -232,6 +235,7 @@ static int nfs4blocklayout_net_init(struct net *net)
|
|||
struct nfs_net *nn = net_generic(net, nfs_net_id);
|
||||
struct dentry *dentry;
|
||||
|
||||
mutex_init(&nn->bl_mutex);
|
||||
init_waitqueue_head(&nn->bl_wq);
|
||||
nn->bl_device_pipe = rpc_mkpipe_data(&bl_upcall_ops, 0);
|
||||
if (IS_ERR(nn->bl_device_pipe))
|
||||
|
|
|
@ -125,6 +125,8 @@ again:
|
|||
continue;
|
||||
if (!test_bit(NFS_DELEGATED_STATE, &state->flags))
|
||||
continue;
|
||||
if (!nfs4_valid_open_stateid(state))
|
||||
continue;
|
||||
if (!nfs4_stateid_match(&state->stateid, stateid))
|
||||
continue;
|
||||
get_nfs_open_context(ctx);
|
||||
|
@ -193,7 +195,11 @@ static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation *
|
|||
{
|
||||
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);
|
||||
return res;
|
||||
}
|
||||
|
@ -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_inode *nfsi = NFS_I(inode);
|
||||
int err;
|
||||
int err = 0;
|
||||
|
||||
if (delegation == NULL)
|
||||
return 0;
|
||||
do {
|
||||
if (test_bit(NFS_DELEGATION_REVOKED, &delegation->flags))
|
||||
break;
|
||||
err = nfs_delegation_claim_opens(inode, &delegation->stateid);
|
||||
if (!issync || err != -EAGAIN)
|
||||
break;
|
||||
|
@ -605,10 +613,23 @@ static void nfs_client_mark_return_unused_delegation_types(struct nfs_client *cl
|
|||
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)
|
||||
{
|
||||
struct nfs_delegation *delegation;
|
||||
|
||||
nfs_revoke_delegation(inode);
|
||||
delegation = nfs_inode_detach_delegation(inode);
|
||||
if (delegation) {
|
||||
nfs_inode_find_state_and_recover(inode, &delegation->stateid);
|
||||
|
|
|
@ -31,6 +31,7 @@ enum {
|
|||
NFS_DELEGATION_RETURN_IF_CLOSED,
|
||||
NFS_DELEGATION_REFERENCED,
|
||||
NFS_DELEGATION_RETURNING,
|
||||
NFS_DELEGATION_REVOKED,
|
||||
};
|
||||
|
||||
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,
|
|||
case -ENOENT:
|
||||
d_drop(dentry);
|
||||
d_add(dentry, NULL);
|
||||
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
|
||||
break;
|
||||
case -EISDIR:
|
||||
case -ENOTDIR:
|
||||
|
|
|
@ -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);
|
||||
|
||||
nfs_free_pnfs_ds_cinfo(&dreq->ds_cinfo);
|
||||
if (dreq->l_ctx != NULL)
|
||||
nfs_put_lock_context(dreq->l_ctx);
|
||||
if (dreq->ctx != NULL)
|
||||
|
|
|
@ -145,9 +145,6 @@ static int filelayout_async_handle_error(struct rpc_task *task,
|
|||
case -NFS4ERR_DELEG_REVOKED:
|
||||
case -NFS4ERR_ADMIN_REVOKED:
|
||||
case -NFS4ERR_BAD_STATEID:
|
||||
if (state == NULL)
|
||||
break;
|
||||
nfs_remove_bad_delegation(state->inode);
|
||||
case -NFS4ERR_OPENMODE:
|
||||
if (state == NULL)
|
||||
break;
|
||||
|
|
|
@ -626,7 +626,7 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
|
|||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
int need_atime = NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATIME;
|
||||
int err;
|
||||
int err = 0;
|
||||
|
||||
trace_nfs_getattr_enter(inode);
|
||||
/* Flush out writes to the server in order to update c/mtime. */
|
||||
|
|
|
@ -19,6 +19,7 @@ struct nfs_net {
|
|||
struct rpc_pipe *bl_device_pipe;
|
||||
struct bl_dev_msg bl_mount_reply;
|
||||
wait_queue_head_t bl_wq;
|
||||
struct mutex bl_mutex;
|
||||
struct list_head nfs_client_list;
|
||||
struct list_head nfs_volume_list;
|
||||
#if IS_ENABLED(CONFIG_NFS_V4)
|
||||
|
|
|
@ -370,11 +370,6 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc
|
|||
case -NFS4ERR_DELEG_REVOKED:
|
||||
case -NFS4ERR_ADMIN_REVOKED:
|
||||
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)
|
||||
break;
|
||||
ret = nfs4_schedule_stateid_recovery(server, state);
|
||||
|
@ -1654,7 +1649,7 @@ static int nfs4_handle_delegation_recall_error(struct nfs_server *server, struct
|
|||
nfs_inode_find_state_and_recover(state->inode,
|
||||
stateid);
|
||||
nfs4_schedule_stateid_recovery(server, state);
|
||||
return 0;
|
||||
return -EAGAIN;
|
||||
case -NFS4ERR_DELAY:
|
||||
case -NFS4ERR_GRACE:
|
||||
set_bit(NFS_DELEGATED_STATE, &state->flags);
|
||||
|
@ -2109,46 +2104,60 @@ static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *sta
|
|||
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)
|
||||
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);
|
||||
nfs4_stateid *stateid = &state->stateid;
|
||||
nfs4_stateid stateid;
|
||||
struct nfs_delegation *delegation;
|
||||
struct rpc_cred *cred = NULL;
|
||||
int status = -NFS4ERR_BAD_STATEID;
|
||||
|
||||
/* If a state reset has been done, test_stateid is unneeded */
|
||||
if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0)
|
||||
return;
|
||||
struct rpc_cred *cred;
|
||||
int status;
|
||||
|
||||
/* Get the delegation credential for use by test/free_stateid */
|
||||
rcu_read_lock();
|
||||
delegation = rcu_dereference(NFS_I(state->inode)->delegation);
|
||||
if (delegation != NULL &&
|
||||
nfs4_stateid_match(&delegation->stateid, stateid)) {
|
||||
cred = get_rpccred(delegation->cred);
|
||||
rcu_read_unlock();
|
||||
status = nfs41_test_stateid(server, stateid, cred);
|
||||
trace_nfs4_test_delegation_stateid(state, NULL, status);
|
||||
} else
|
||||
if (delegation == NULL) {
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
nfs4_stateid_copy(&stateid, &delegation->stateid);
|
||||
cred = get_rpccred(delegation->cred);
|
||||
rcu_read_unlock();
|
||||
status = nfs41_test_stateid(server, &stateid, cred);
|
||||
trace_nfs4_test_delegation_stateid(state, NULL, status);
|
||||
|
||||
if (status != NFS_OK) {
|
||||
/* Free the stateid unless the server explicitly
|
||||
* informs us the stateid is unrecognized. */
|
||||
if (status != -NFS4ERR_BAD_STATEID)
|
||||
nfs41_free_stateid(server, stateid, cred);
|
||||
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);
|
||||
nfs41_free_stateid(server, &stateid, cred);
|
||||
nfs_finish_clear_delegation_stateid(state);
|
||||
}
|
||||
|
||||
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
|
|||
{
|
||||
int status;
|
||||
|
||||
nfs41_clear_delegation_stateid(state);
|
||||
nfs41_check_delegation_stateid(state);
|
||||
status = nfs41_check_open_stateid(state);
|
||||
if (status != NFS_OK)
|
||||
status = nfs4_open_expired(sp, state);
|
||||
|
@ -2231,19 +2240,8 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata,
|
|||
seq = raw_seqcount_begin(&sp->so_reclaim_seqcount);
|
||||
|
||||
ret = _nfs4_proc_open(opendata);
|
||||
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));
|
||||
}
|
||||
if (ret != 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
state = nfs4_opendata_to_nfs4_state(opendata);
|
||||
ret = PTR_ERR(state);
|
||||
|
@ -4841,9 +4839,6 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server,
|
|||
case -NFS4ERR_DELEG_REVOKED:
|
||||
case -NFS4ERR_ADMIN_REVOKED:
|
||||
case -NFS4ERR_BAD_STATEID:
|
||||
if (state == NULL)
|
||||
break;
|
||||
nfs_remove_bad_delegation(state->inode);
|
||||
case -NFS4ERR_OPENMODE:
|
||||
if (state == NULL)
|
||||
break;
|
||||
|
@ -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 = {
|
||||
.owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE,
|
||||
.state_flag_bit = NFS_STATE_RECLAIM_NOGRACE,
|
||||
.recover_open = nfs4_open_expired,
|
||||
.recover_open = nfs40_open_expired,
|
||||
.recover_lock = nfs4_lock_expired,
|
||||
.establish_clid = nfs4_init_clientid,
|
||||
};
|
||||
|
@ -8408,8 +8403,7 @@ static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = {
|
|||
| NFS_CAP_CHANGE_ATTR
|
||||
| NFS_CAP_POSIX_LOCK
|
||||
| NFS_CAP_STATEID_NFSV41
|
||||
| NFS_CAP_ATOMIC_OPEN_V1
|
||||
| NFS_CAP_SEEK,
|
||||
| NFS_CAP_ATOMIC_OPEN_V1,
|
||||
.init_client = nfs41_init_client,
|
||||
.shutdown_client = nfs41_shutdown_client,
|
||||
.match_stateid = nfs41_match_stateid,
|
||||
|
@ -8431,7 +8425,8 @@ static const struct nfs4_minor_version_ops nfs_v4_2_minor_ops = {
|
|||
| NFS_CAP_CHANGE_ATTR
|
||||
| NFS_CAP_POSIX_LOCK
|
||||
| NFS_CAP_STATEID_NFSV41
|
||||
| NFS_CAP_ATOMIC_OPEN_V1,
|
||||
| NFS_CAP_ATOMIC_OPEN_V1
|
||||
| NFS_CAP_SEEK,
|
||||
.init_client = nfs41_init_client,
|
||||
.shutdown_client = nfs41_shutdown_client,
|
||||
.match_stateid = nfs41_match_stateid,
|
||||
|
|
|
@ -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))
|
||||
nfs_release_request(req);
|
||||
else
|
||||
WARN_ON_ONCE(1);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -1224,11 +1224,22 @@ struct nfs41_free_stateid_res {
|
|||
unsigned int status;
|
||||
};
|
||||
|
||||
static inline void
|
||||
nfs_free_pnfs_ds_cinfo(struct pnfs_ds_commit_info *cinfo)
|
||||
{
|
||||
kfree(cinfo->buckets);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
struct pnfs_ds_commit_info {
|
||||
};
|
||||
|
||||
static inline void
|
||||
nfs_free_pnfs_ds_cinfo(struct pnfs_ds_commit_info *cinfo)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* CONFIG_NFS_V4_1 */
|
||||
|
||||
#ifdef CONFIG_NFS_V4_2
|
||||
|
|
|
@ -1353,6 +1353,7 @@ gss_stringify_acceptor(struct rpc_cred *cred)
|
|||
char *string = NULL;
|
||||
struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base);
|
||||
struct gss_cl_ctx *ctx;
|
||||
unsigned int len;
|
||||
struct xdr_netobj *acceptor;
|
||||
|
||||
rcu_read_lock();
|
||||
|
@ -1360,15 +1361,39 @@ gss_stringify_acceptor(struct rpc_cred *cred)
|
|||
if (!ctx)
|
||||
goto out;
|
||||
|
||||
acceptor = &ctx->gc_acceptor;
|
||||
len = ctx->gc_acceptor.len;
|
||||
rcu_read_unlock();
|
||||
|
||||
/* no point if there's no string */
|
||||
if (!acceptor->len)
|
||||
goto out;
|
||||
|
||||
string = kmalloc(acceptor->len + 1, GFP_KERNEL);
|
||||
if (!len)
|
||||
return NULL;
|
||||
realloc:
|
||||
string = kmalloc(len + 1, GFP_KERNEL);
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
string[acceptor->len] = '\0';
|
||||
|
|
Loading…
Reference in a new issue