Commit 44ea8dfc authored by Trond Myklebust's avatar Trond Myklebust

NFS/pnfs: Reference the layout cred in pnfs_prepare_layoutreturn()

When we're sending a layoutreturn, ensure that we reference the
layout cred atomically with the copy of the stateid.
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@hammerspace.com>
parent 97a728f5
...@@ -9297,6 +9297,7 @@ static void nfs4_layoutreturn_release(void *calldata) ...@@ -9297,6 +9297,7 @@ static void nfs4_layoutreturn_release(void *calldata)
lrp->ld_private.ops->free(&lrp->ld_private); lrp->ld_private.ops->free(&lrp->ld_private);
pnfs_put_layout_hdr(lrp->args.layout); pnfs_put_layout_hdr(lrp->args.layout);
nfs_iput_and_deactive(lrp->inode); nfs_iput_and_deactive(lrp->inode);
put_cred(lrp->cred);
kfree(calldata); kfree(calldata);
dprintk("<-- %s\n", __func__); dprintk("<-- %s\n", __func__);
} }
......
...@@ -1144,6 +1144,7 @@ void pnfs_layoutreturn_free_lsegs(struct pnfs_layout_hdr *lo, ...@@ -1144,6 +1144,7 @@ void pnfs_layoutreturn_free_lsegs(struct pnfs_layout_hdr *lo,
static bool static bool
pnfs_prepare_layoutreturn(struct pnfs_layout_hdr *lo, pnfs_prepare_layoutreturn(struct pnfs_layout_hdr *lo,
nfs4_stateid *stateid, nfs4_stateid *stateid,
const struct cred **cred,
enum pnfs_iomode *iomode) enum pnfs_iomode *iomode)
{ {
/* Serialise LAYOUTGET/LAYOUTRETURN */ /* Serialise LAYOUTGET/LAYOUTRETURN */
...@@ -1154,18 +1155,17 @@ pnfs_prepare_layoutreturn(struct pnfs_layout_hdr *lo, ...@@ -1154,18 +1155,17 @@ pnfs_prepare_layoutreturn(struct pnfs_layout_hdr *lo,
set_bit(NFS_LAYOUT_RETURN, &lo->plh_flags); set_bit(NFS_LAYOUT_RETURN, &lo->plh_flags);
pnfs_get_layout_hdr(lo); pnfs_get_layout_hdr(lo);
if (test_bit(NFS_LAYOUT_RETURN_REQUESTED, &lo->plh_flags)) { if (test_bit(NFS_LAYOUT_RETURN_REQUESTED, &lo->plh_flags)) {
if (stateid != NULL) { nfs4_stateid_copy(stateid, &lo->plh_stateid);
nfs4_stateid_copy(stateid, &lo->plh_stateid); *cred = get_cred(lo->plh_lc_cred);
if (lo->plh_return_seq != 0) if (lo->plh_return_seq != 0)
stateid->seqid = cpu_to_be32(lo->plh_return_seq); stateid->seqid = cpu_to_be32(lo->plh_return_seq);
}
if (iomode != NULL) if (iomode != NULL)
*iomode = lo->plh_return_iomode; *iomode = lo->plh_return_iomode;
pnfs_clear_layoutreturn_info(lo); pnfs_clear_layoutreturn_info(lo);
return true; return true;
} }
if (stateid != NULL) nfs4_stateid_copy(stateid, &lo->plh_stateid);
nfs4_stateid_copy(stateid, &lo->plh_stateid); *cred = get_cred(lo->plh_lc_cred);
if (iomode != NULL) if (iomode != NULL)
*iomode = IOMODE_ANY; *iomode = IOMODE_ANY;
return true; return true;
...@@ -1189,20 +1189,26 @@ pnfs_init_layoutreturn_args(struct nfs4_layoutreturn_args *args, ...@@ -1189,20 +1189,26 @@ pnfs_init_layoutreturn_args(struct nfs4_layoutreturn_args *args,
} }
static int static int
pnfs_send_layoutreturn(struct pnfs_layout_hdr *lo, const nfs4_stateid *stateid, pnfs_send_layoutreturn(struct pnfs_layout_hdr *lo,
enum pnfs_iomode iomode, bool sync) const nfs4_stateid *stateid,
const struct cred **pcred,
enum pnfs_iomode iomode,
bool sync)
{ {
struct inode *ino = lo->plh_inode; struct inode *ino = lo->plh_inode;
struct pnfs_layoutdriver_type *ld = NFS_SERVER(ino)->pnfs_curr_ld; struct pnfs_layoutdriver_type *ld = NFS_SERVER(ino)->pnfs_curr_ld;
struct nfs4_layoutreturn *lrp; struct nfs4_layoutreturn *lrp;
const struct cred *cred = *pcred;
int status = 0; int status = 0;
*pcred = NULL;
lrp = kzalloc(sizeof(*lrp), GFP_NOFS); lrp = kzalloc(sizeof(*lrp), GFP_NOFS);
if (unlikely(lrp == NULL)) { if (unlikely(lrp == NULL)) {
status = -ENOMEM; status = -ENOMEM;
spin_lock(&ino->i_lock); spin_lock(&ino->i_lock);
pnfs_clear_layoutreturn_waitbit(lo); pnfs_clear_layoutreturn_waitbit(lo);
spin_unlock(&ino->i_lock); spin_unlock(&ino->i_lock);
put_cred(cred);
pnfs_put_layout_hdr(lo); pnfs_put_layout_hdr(lo);
goto out; goto out;
} }
...@@ -1210,7 +1216,7 @@ pnfs_send_layoutreturn(struct pnfs_layout_hdr *lo, const nfs4_stateid *stateid, ...@@ -1210,7 +1216,7 @@ pnfs_send_layoutreturn(struct pnfs_layout_hdr *lo, const nfs4_stateid *stateid,
pnfs_init_layoutreturn_args(&lrp->args, lo, stateid, iomode); pnfs_init_layoutreturn_args(&lrp->args, lo, stateid, iomode);
lrp->args.ld_private = &lrp->ld_private; lrp->args.ld_private = &lrp->ld_private;
lrp->clp = NFS_SERVER(ino)->nfs_client; lrp->clp = NFS_SERVER(ino)->nfs_client;
lrp->cred = lo->plh_lc_cred; lrp->cred = cred;
if (ld->prepare_layoutreturn) if (ld->prepare_layoutreturn)
ld->prepare_layoutreturn(&lrp->args); ld->prepare_layoutreturn(&lrp->args);
...@@ -1255,15 +1261,16 @@ static void pnfs_layoutreturn_before_put_layout_hdr(struct pnfs_layout_hdr *lo) ...@@ -1255,15 +1261,16 @@ static void pnfs_layoutreturn_before_put_layout_hdr(struct pnfs_layout_hdr *lo)
return; return;
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
if (pnfs_layout_need_return(lo)) { if (pnfs_layout_need_return(lo)) {
const struct cred *cred;
nfs4_stateid stateid; nfs4_stateid stateid;
enum pnfs_iomode iomode; enum pnfs_iomode iomode;
bool send; bool send;
send = pnfs_prepare_layoutreturn(lo, &stateid, &iomode); send = pnfs_prepare_layoutreturn(lo, &stateid, &cred, &iomode);
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
if (send) { if (send) {
/* Send an async layoutreturn so we dont deadlock */ /* Send an async layoutreturn so we dont deadlock */
pnfs_send_layoutreturn(lo, &stateid, iomode, false); pnfs_send_layoutreturn(lo, &stateid, &cred, iomode, false);
} }
} else } else
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
...@@ -1283,6 +1290,7 @@ _pnfs_return_layout(struct inode *ino) ...@@ -1283,6 +1290,7 @@ _pnfs_return_layout(struct inode *ino)
struct pnfs_layout_hdr *lo = NULL; struct pnfs_layout_hdr *lo = NULL;
struct nfs_inode *nfsi = NFS_I(ino); struct nfs_inode *nfsi = NFS_I(ino);
LIST_HEAD(tmp_list); LIST_HEAD(tmp_list);
const struct cred *cred;
nfs4_stateid stateid; nfs4_stateid stateid;
int status = 0; int status = 0;
bool send, valid_layout; bool send, valid_layout;
...@@ -1327,10 +1335,10 @@ _pnfs_return_layout(struct inode *ino) ...@@ -1327,10 +1335,10 @@ _pnfs_return_layout(struct inode *ino)
goto out_put_layout_hdr; goto out_put_layout_hdr;
} }
send = pnfs_prepare_layoutreturn(lo, &stateid, NULL); send = pnfs_prepare_layoutreturn(lo, &stateid, &cred, NULL);
spin_unlock(&ino->i_lock); spin_unlock(&ino->i_lock);
if (send) if (send)
status = pnfs_send_layoutreturn(lo, &stateid, IOMODE_ANY, true); status = pnfs_send_layoutreturn(lo, &stateid, &cred, IOMODE_ANY, true);
out_put_layout_hdr: out_put_layout_hdr:
pnfs_free_lseg_list(&tmp_list); pnfs_free_lseg_list(&tmp_list);
pnfs_put_layout_hdr(lo); pnfs_put_layout_hdr(lo);
...@@ -1376,6 +1384,7 @@ bool pnfs_roc(struct inode *ino, ...@@ -1376,6 +1384,7 @@ bool pnfs_roc(struct inode *ino,
struct nfs4_state *state; struct nfs4_state *state;
struct pnfs_layout_hdr *lo; struct pnfs_layout_hdr *lo;
struct pnfs_layout_segment *lseg, *next; struct pnfs_layout_segment *lseg, *next;
const struct cred *lc_cred;
nfs4_stateid stateid; nfs4_stateid stateid;
enum pnfs_iomode iomode = 0; enum pnfs_iomode iomode = 0;
bool layoutreturn = false, roc = false; bool layoutreturn = false, roc = false;
...@@ -1445,16 +1454,20 @@ bool pnfs_roc(struct inode *ino, ...@@ -1445,16 +1454,20 @@ bool pnfs_roc(struct inode *ino,
* 2. we don't send layoutreturn * 2. we don't send layoutreturn
*/ */
/* lo ref dropped in pnfs_roc_release() */ /* lo ref dropped in pnfs_roc_release() */
layoutreturn = pnfs_prepare_layoutreturn(lo, &stateid, &iomode); layoutreturn = pnfs_prepare_layoutreturn(lo, &stateid, &lc_cred, &iomode);
/* If the creds don't match, we can't compound the layoutreturn */ /* If the creds don't match, we can't compound the layoutreturn */
if (!layoutreturn || cred_fscmp(cred, lo->plh_lc_cred) != 0) if (!layoutreturn)
goto out_noroc; goto out_noroc;
if (cred_fscmp(cred, lc_cred) != 0)
goto out_noroc_put_cred;
roc = layoutreturn; roc = layoutreturn;
pnfs_init_layoutreturn_args(args, lo, &stateid, iomode); pnfs_init_layoutreturn_args(args, lo, &stateid, iomode);
res->lrs_present = 0; res->lrs_present = 0;
layoutreturn = false; layoutreturn = false;
out_noroc_put_cred:
put_cred(lc_cred);
out_noroc: out_noroc:
spin_unlock(&ino->i_lock); spin_unlock(&ino->i_lock);
rcu_read_unlock(); rcu_read_unlock();
...@@ -1467,7 +1480,7 @@ bool pnfs_roc(struct inode *ino, ...@@ -1467,7 +1480,7 @@ bool pnfs_roc(struct inode *ino,
return true; return true;
} }
if (layoutreturn) if (layoutreturn)
pnfs_send_layoutreturn(lo, &stateid, iomode, true); pnfs_send_layoutreturn(lo, &stateid, &lc_cred, iomode, true);
pnfs_put_layout_hdr(lo); pnfs_put_layout_hdr(lo);
return false; return false;
} }
...@@ -2464,13 +2477,14 @@ pnfs_mark_layout_for_return(struct inode *inode, ...@@ -2464,13 +2477,14 @@ pnfs_mark_layout_for_return(struct inode *inode,
* for how it works. * for how it works.
*/ */
if (pnfs_mark_matching_lsegs_return(lo, &lo->plh_return_segs, range, 0) != -EBUSY) { if (pnfs_mark_matching_lsegs_return(lo, &lo->plh_return_segs, range, 0) != -EBUSY) {
const struct cred *cred;
nfs4_stateid stateid; nfs4_stateid stateid;
enum pnfs_iomode iomode; enum pnfs_iomode iomode;
return_now = pnfs_prepare_layoutreturn(lo, &stateid, &iomode); return_now = pnfs_prepare_layoutreturn(lo, &stateid, &cred, &iomode);
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
if (return_now) if (return_now)
pnfs_send_layoutreturn(lo, &stateid, iomode, false); pnfs_send_layoutreturn(lo, &stateid, &cred, iomode, false);
} else { } else {
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
nfs_commit_inode(inode, 0); nfs_commit_inode(inode, 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