mirror of
https://github.com/torvalds/linux.git
synced 2026-01-25 15:03:52 +08:00
Merge tag 'nfs-for-4.11-3' of git://git.linux-nfs.org/projects/anna/linux-nfs
Pull NFS client fixes from Anna Schumaker: "Here are a few more bugfixes that came in over the last couple of weeks. Most of these fix various hangs and loops that people found, but we also had a few error handling fixes. Stable Bugfixes: - fix infinite loop on BAD_STATEID error Other Bugfixes: - fix old dentry rehash after move - fix pnfs GETDEVINFO hangs - fix pnfs fallback to MDS on commit errors - fix flexfiles kernel oops" * tag 'nfs-for-4.11-3' of git://git.linux-nfs.org/projects/anna/linux-nfs: nfs: flexfiles: fix kernel OOPS if MDS returns unsupported DS type NFSv4.1 fix infinite loop on IO BAD_STATEID error PNFS fix fallback to MDS if got error on commit to DS NFS filelayout:call GETDEVICEINFO after pnfs_layout_process completes NFS store nfs4_deviceid in struct nfs4_filelayout_segment NFS cleanup struct nfs4_filelayout_segment NFS: Fix old dentry rehash after move
This commit is contained in:
@@ -2055,7 +2055,7 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
{
|
||||
struct inode *old_inode = d_inode(old_dentry);
|
||||
struct inode *new_inode = d_inode(new_dentry);
|
||||
struct dentry *dentry = NULL, *rehash = NULL;
|
||||
struct dentry *dentry = NULL;
|
||||
struct rpc_task *task;
|
||||
int error = -EBUSY;
|
||||
|
||||
@@ -2078,10 +2078,8 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
* To prevent any new references to the target during the
|
||||
* rename, we unhash the dentry in advance.
|
||||
*/
|
||||
if (!d_unhashed(new_dentry)) {
|
||||
if (!d_unhashed(new_dentry))
|
||||
d_drop(new_dentry);
|
||||
rehash = new_dentry;
|
||||
}
|
||||
|
||||
if (d_count(new_dentry) > 2) {
|
||||
int err;
|
||||
@@ -2098,7 +2096,6 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
goto out;
|
||||
|
||||
new_dentry = dentry;
|
||||
rehash = NULL;
|
||||
new_inode = NULL;
|
||||
}
|
||||
}
|
||||
@@ -2119,8 +2116,6 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
error = task->tk_status;
|
||||
rpc_put_task(task);
|
||||
out:
|
||||
if (rehash)
|
||||
d_rehash(rehash);
|
||||
trace_nfs_rename_exit(old_dir, old_dentry,
|
||||
new_dir, new_dentry, error);
|
||||
/* new dentry created? */
|
||||
|
||||
@@ -202,10 +202,10 @@ static int filelayout_async_handle_error(struct rpc_task *task,
|
||||
task->tk_status);
|
||||
nfs4_mark_deviceid_unavailable(devid);
|
||||
pnfs_error_mark_layout_for_return(inode, lseg);
|
||||
pnfs_set_lo_fail(lseg);
|
||||
rpc_wake_up(&tbl->slot_tbl_waitq);
|
||||
/* fall through */
|
||||
default:
|
||||
pnfs_set_lo_fail(lseg);
|
||||
reset:
|
||||
dprintk("%s Retry through MDS. Error %d\n", __func__,
|
||||
task->tk_status);
|
||||
@@ -560,49 +560,17 @@ filelayout_write_pagelist(struct nfs_pgio_header *hdr, int sync)
|
||||
return PNFS_ATTEMPTED;
|
||||
}
|
||||
|
||||
/*
|
||||
* filelayout_check_layout()
|
||||
*
|
||||
* Make sure layout segment parameters are sane WRT the device.
|
||||
* At this point no generic layer initialization of the lseg has occurred,
|
||||
* and nothing has been added to the layout_hdr cache.
|
||||
*
|
||||
*/
|
||||
static int
|
||||
filelayout_check_layout(struct pnfs_layout_hdr *lo,
|
||||
struct nfs4_filelayout_segment *fl,
|
||||
struct nfs4_layoutget_res *lgr,
|
||||
struct nfs4_deviceid *id,
|
||||
gfp_t gfp_flags)
|
||||
filelayout_check_deviceid(struct pnfs_layout_hdr *lo,
|
||||
struct nfs4_filelayout_segment *fl,
|
||||
gfp_t gfp_flags)
|
||||
{
|
||||
struct nfs4_deviceid_node *d;
|
||||
struct nfs4_file_layout_dsaddr *dsaddr;
|
||||
int status = -EINVAL;
|
||||
|
||||
dprintk("--> %s\n", __func__);
|
||||
|
||||
/* FIXME: remove this check when layout segment support is added */
|
||||
if (lgr->range.offset != 0 ||
|
||||
lgr->range.length != NFS4_MAX_UINT64) {
|
||||
dprintk("%s Only whole file layouts supported. Use MDS i/o\n",
|
||||
__func__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (fl->pattern_offset > lgr->range.offset) {
|
||||
dprintk("%s pattern_offset %lld too large\n",
|
||||
__func__, fl->pattern_offset);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!fl->stripe_unit) {
|
||||
dprintk("%s Invalid stripe unit (%u)\n",
|
||||
__func__, fl->stripe_unit);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* find and reference the deviceid */
|
||||
d = nfs4_find_get_deviceid(NFS_SERVER(lo->plh_inode), id,
|
||||
d = nfs4_find_get_deviceid(NFS_SERVER(lo->plh_inode), &fl->deviceid,
|
||||
lo->plh_lc_cred, gfp_flags);
|
||||
if (d == NULL)
|
||||
goto out;
|
||||
@@ -628,14 +596,56 @@ filelayout_check_layout(struct pnfs_layout_hdr *lo,
|
||||
__func__, fl->num_fh);
|
||||
goto out_put;
|
||||
}
|
||||
status = 0;
|
||||
out:
|
||||
return status;
|
||||
out_put:
|
||||
nfs4_fl_put_deviceid(dsaddr);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* filelayout_check_layout()
|
||||
*
|
||||
* Make sure layout segment parameters are sane WRT the device.
|
||||
* At this point no generic layer initialization of the lseg has occurred,
|
||||
* and nothing has been added to the layout_hdr cache.
|
||||
*
|
||||
*/
|
||||
static int
|
||||
filelayout_check_layout(struct pnfs_layout_hdr *lo,
|
||||
struct nfs4_filelayout_segment *fl,
|
||||
struct nfs4_layoutget_res *lgr,
|
||||
gfp_t gfp_flags)
|
||||
{
|
||||
int status = -EINVAL;
|
||||
|
||||
dprintk("--> %s\n", __func__);
|
||||
|
||||
/* FIXME: remove this check when layout segment support is added */
|
||||
if (lgr->range.offset != 0 ||
|
||||
lgr->range.length != NFS4_MAX_UINT64) {
|
||||
dprintk("%s Only whole file layouts supported. Use MDS i/o\n",
|
||||
__func__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (fl->pattern_offset > lgr->range.offset) {
|
||||
dprintk("%s pattern_offset %lld too large\n",
|
||||
__func__, fl->pattern_offset);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!fl->stripe_unit) {
|
||||
dprintk("%s Invalid stripe unit (%u)\n",
|
||||
__func__, fl->stripe_unit);
|
||||
goto out;
|
||||
}
|
||||
|
||||
status = 0;
|
||||
out:
|
||||
dprintk("--> %s returns %d\n", __func__, status);
|
||||
return status;
|
||||
out_put:
|
||||
nfs4_fl_put_deviceid(dsaddr);
|
||||
goto out;
|
||||
}
|
||||
|
||||
static void _filelayout_free_lseg(struct nfs4_filelayout_segment *fl)
|
||||
@@ -657,7 +667,6 @@ static int
|
||||
filelayout_decode_layout(struct pnfs_layout_hdr *flo,
|
||||
struct nfs4_filelayout_segment *fl,
|
||||
struct nfs4_layoutget_res *lgr,
|
||||
struct nfs4_deviceid *id,
|
||||
gfp_t gfp_flags)
|
||||
{
|
||||
struct xdr_stream stream;
|
||||
@@ -682,9 +691,9 @@ filelayout_decode_layout(struct pnfs_layout_hdr *flo,
|
||||
if (unlikely(!p))
|
||||
goto out_err;
|
||||
|
||||
memcpy(id, p, sizeof(*id));
|
||||
memcpy(&fl->deviceid, p, sizeof(fl->deviceid));
|
||||
p += XDR_QUADLEN(NFS4_DEVICEID4_SIZE);
|
||||
nfs4_print_deviceid(id);
|
||||
nfs4_print_deviceid(&fl->deviceid);
|
||||
|
||||
nfl_util = be32_to_cpup(p++);
|
||||
if (nfl_util & NFL4_UFLG_COMMIT_THRU_MDS)
|
||||
@@ -831,15 +840,14 @@ filelayout_alloc_lseg(struct pnfs_layout_hdr *layoutid,
|
||||
{
|
||||
struct nfs4_filelayout_segment *fl;
|
||||
int rc;
|
||||
struct nfs4_deviceid id;
|
||||
|
||||
dprintk("--> %s\n", __func__);
|
||||
fl = kzalloc(sizeof(*fl), gfp_flags);
|
||||
if (!fl)
|
||||
return NULL;
|
||||
|
||||
rc = filelayout_decode_layout(layoutid, fl, lgr, &id, gfp_flags);
|
||||
if (rc != 0 || filelayout_check_layout(layoutid, fl, lgr, &id, gfp_flags)) {
|
||||
rc = filelayout_decode_layout(layoutid, fl, lgr, gfp_flags);
|
||||
if (rc != 0 || filelayout_check_layout(layoutid, fl, lgr, gfp_flags)) {
|
||||
_filelayout_free_lseg(fl);
|
||||
return NULL;
|
||||
}
|
||||
@@ -888,18 +896,51 @@ filelayout_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev,
|
||||
return min(stripe_unit - (unsigned int)stripe_offset, size);
|
||||
}
|
||||
|
||||
static struct pnfs_layout_segment *
|
||||
fl_pnfs_update_layout(struct inode *ino,
|
||||
struct nfs_open_context *ctx,
|
||||
loff_t pos,
|
||||
u64 count,
|
||||
enum pnfs_iomode iomode,
|
||||
bool strict_iomode,
|
||||
gfp_t gfp_flags)
|
||||
{
|
||||
struct pnfs_layout_segment *lseg = NULL;
|
||||
struct pnfs_layout_hdr *lo;
|
||||
struct nfs4_filelayout_segment *fl;
|
||||
int status;
|
||||
|
||||
lseg = pnfs_update_layout(ino, ctx, pos, count, iomode, strict_iomode,
|
||||
gfp_flags);
|
||||
if (!lseg)
|
||||
lseg = ERR_PTR(-ENOMEM);
|
||||
if (IS_ERR(lseg))
|
||||
goto out;
|
||||
|
||||
lo = NFS_I(ino)->layout;
|
||||
fl = FILELAYOUT_LSEG(lseg);
|
||||
|
||||
status = filelayout_check_deviceid(lo, fl, gfp_flags);
|
||||
if (status)
|
||||
lseg = ERR_PTR(status);
|
||||
out:
|
||||
if (IS_ERR(lseg))
|
||||
pnfs_put_lseg(lseg);
|
||||
return lseg;
|
||||
}
|
||||
|
||||
static void
|
||||
filelayout_pg_init_read(struct nfs_pageio_descriptor *pgio,
|
||||
struct nfs_page *req)
|
||||
{
|
||||
if (!pgio->pg_lseg) {
|
||||
pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
|
||||
req->wb_context,
|
||||
0,
|
||||
NFS4_MAX_UINT64,
|
||||
IOMODE_READ,
|
||||
false,
|
||||
GFP_KERNEL);
|
||||
pgio->pg_lseg = fl_pnfs_update_layout(pgio->pg_inode,
|
||||
req->wb_context,
|
||||
0,
|
||||
NFS4_MAX_UINT64,
|
||||
IOMODE_READ,
|
||||
false,
|
||||
GFP_KERNEL);
|
||||
if (IS_ERR(pgio->pg_lseg)) {
|
||||
pgio->pg_error = PTR_ERR(pgio->pg_lseg);
|
||||
pgio->pg_lseg = NULL;
|
||||
@@ -919,13 +960,13 @@ filelayout_pg_init_write(struct nfs_pageio_descriptor *pgio,
|
||||
int status;
|
||||
|
||||
if (!pgio->pg_lseg) {
|
||||
pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
|
||||
req->wb_context,
|
||||
0,
|
||||
NFS4_MAX_UINT64,
|
||||
IOMODE_RW,
|
||||
false,
|
||||
GFP_NOFS);
|
||||
pgio->pg_lseg = fl_pnfs_update_layout(pgio->pg_inode,
|
||||
req->wb_context,
|
||||
0,
|
||||
NFS4_MAX_UINT64,
|
||||
IOMODE_RW,
|
||||
false,
|
||||
GFP_NOFS);
|
||||
if (IS_ERR(pgio->pg_lseg)) {
|
||||
pgio->pg_error = PTR_ERR(pgio->pg_lseg);
|
||||
pgio->pg_lseg = NULL;
|
||||
|
||||
@@ -55,15 +55,16 @@ struct nfs4_file_layout_dsaddr {
|
||||
};
|
||||
|
||||
struct nfs4_filelayout_segment {
|
||||
struct pnfs_layout_segment generic_hdr;
|
||||
u32 stripe_type;
|
||||
u32 commit_through_mds;
|
||||
u32 stripe_unit;
|
||||
u32 first_stripe_index;
|
||||
u64 pattern_offset;
|
||||
struct nfs4_file_layout_dsaddr *dsaddr; /* Point to GETDEVINFO data */
|
||||
unsigned int num_fh;
|
||||
struct nfs_fh **fh_array;
|
||||
struct pnfs_layout_segment generic_hdr;
|
||||
u32 stripe_type;
|
||||
u32 commit_through_mds;
|
||||
u32 stripe_unit;
|
||||
u32 first_stripe_index;
|
||||
u64 pattern_offset;
|
||||
struct nfs4_deviceid deviceid;
|
||||
struct nfs4_file_layout_dsaddr *dsaddr; /* Point to GETDEVINFO data */
|
||||
unsigned int num_fh;
|
||||
struct nfs_fh **fh_array;
|
||||
};
|
||||
|
||||
struct nfs4_filelayout {
|
||||
|
||||
@@ -208,6 +208,10 @@ static bool ff_layout_mirror_valid(struct pnfs_layout_segment *lseg,
|
||||
} else
|
||||
goto outerr;
|
||||
}
|
||||
|
||||
if (IS_ERR(mirror->mirror_ds))
|
||||
goto outerr;
|
||||
|
||||
if (mirror->mirror_ds->ds == NULL) {
|
||||
struct nfs4_deviceid_node *devid;
|
||||
devid = &mirror->mirror_ds->id_node;
|
||||
|
||||
@@ -2442,17 +2442,14 @@ static void nfs41_check_delegation_stateid(struct nfs4_state *state)
|
||||
}
|
||||
|
||||
nfs4_stateid_copy(&stateid, &delegation->stateid);
|
||||
if (test_bit(NFS_DELEGATION_REVOKED, &delegation->flags)) {
|
||||
if (test_bit(NFS_DELEGATION_REVOKED, &delegation->flags) ||
|
||||
!test_and_clear_bit(NFS_DELEGATION_TEST_EXPIRED,
|
||||
&delegation->flags)) {
|
||||
rcu_read_unlock();
|
||||
nfs_finish_clear_delegation_stateid(state, &stateid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!test_and_clear_bit(NFS_DELEGATION_TEST_EXPIRED, &delegation->flags)) {
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
cred = get_rpccred(delegation->cred);
|
||||
rcu_read_unlock();
|
||||
status = nfs41_test_and_free_expired_stateid(server, &stateid, cred);
|
||||
|
||||
Reference in New Issue
Block a user