Merge tag 'nfs-for-6.15-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS client bugfixes from Trond Myklebust: - NFS: Fix a couple of missed handlers for the ENETDOWN and ENETUNREACH transport errors - NFS: Handle Oopsable failure of nfs_get_lock_context in the unlock path - NFSv4: Fix a race in nfs_local_open_fh() - NFSv4/pNFS: Fix a couple of layout segment leaks in layoutreturn - NFSv4/pNFS Avoid sharing pNFS DS connections between net namespaces since IP addresses are not guaranteed to refer to the same nodes - NFS: Don't flush file data while holding multiple directory locks in nfs_rename() * tag 'nfs-for-6.15-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: NFS: Avoid flushing data while holding directory locks in nfs_rename() NFS/pnfs: Fix the error path in pnfs_layoutreturn_retry_later_locked() NFSv4/pnfs: Reset the layout state after a layoutreturn NFS/localio: Fix a race in nfs_local_open_fh() nfs: nfs3acl: drop useless assignment in nfs3_get_acl() nfs: direct: drop useless initializer in nfs_direct_write_completion() nfs: move the nfs4_data_server_cache into struct nfs_net nfs: don't share pNFS DS connections between net namespaces nfs: handle failure of nfs_get_lock_context in unlock path pNFS/flexfiles: Record the RPC errors in the I/O tracepoints NFSv4/pnfs: Layoutreturn on close must handle fatal networking errors NFSv4: Handle fatal ENETDOWN and ENETUNREACH errors
This commit is contained in:
@@ -1105,6 +1105,8 @@ struct nfs_server *nfs_create_server(struct fs_context *fc)
|
||||
if (server->namelen == 0 || server->namelen > NFS2_MAXNAMLEN)
|
||||
server->namelen = NFS2_MAXNAMLEN;
|
||||
}
|
||||
/* Linux 'subtree_check' borkenness mandates this setting */
|
||||
server->fh_expire_type = NFS_FH_VOL_RENAME;
|
||||
|
||||
if (!(fattr->valid & NFS_ATTR_FATTR)) {
|
||||
error = ctx->nfs_mod->rpc_ops->getattr(server, ctx->mntfh,
|
||||
@@ -1199,6 +1201,10 @@ void nfs_clients_init(struct net *net)
|
||||
INIT_LIST_HEAD(&nn->nfs_volume_list);
|
||||
#if IS_ENABLED(CONFIG_NFS_V4)
|
||||
idr_init(&nn->cb_ident_idr);
|
||||
#endif
|
||||
#if IS_ENABLED(CONFIG_NFS_V4_1)
|
||||
INIT_LIST_HEAD(&nn->nfs4_data_server_cache);
|
||||
spin_lock_init(&nn->nfs4_data_server_lock);
|
||||
#endif
|
||||
spin_lock_init(&nn->nfs_client_lock);
|
||||
nn->boot_time = ktime_get_real();
|
||||
@@ -1216,6 +1222,9 @@ void nfs_clients_exit(struct net *net)
|
||||
nfs_cleanup_cb_ident_idr(net);
|
||||
WARN_ON_ONCE(!list_empty(&nn->nfs_client_list));
|
||||
WARN_ON_ONCE(!list_empty(&nn->nfs_volume_list));
|
||||
#if IS_ENABLED(CONFIG_NFS_V4_1)
|
||||
WARN_ON_ONCE(!list_empty(&nn->nfs4_data_server_cache));
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
|
||||
+14
-1
@@ -2676,6 +2676,18 @@ nfs_unblock_rename(struct rpc_task *task, struct nfs_renamedata *data)
|
||||
unblock_revalidate(new_dentry);
|
||||
}
|
||||
|
||||
static bool nfs_rename_is_unsafe_cross_dir(struct dentry *old_dentry,
|
||||
struct dentry *new_dentry)
|
||||
{
|
||||
struct nfs_server *server = NFS_SB(old_dentry->d_sb);
|
||||
|
||||
if (old_dentry->d_parent != new_dentry->d_parent)
|
||||
return false;
|
||||
if (server->fh_expire_type & NFS_FH_RENAME_UNSAFE)
|
||||
return !(server->fh_expire_type & NFS_FH_NOEXPIRE_WITH_OPEN);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* RENAME
|
||||
* FIXME: Some nfsds, like the Linux user space nfsd, may generate a
|
||||
@@ -2763,7 +2775,8 @@ int nfs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
|
||||
|
||||
}
|
||||
|
||||
if (S_ISREG(old_inode->i_mode))
|
||||
if (S_ISREG(old_inode->i_mode) &&
|
||||
nfs_rename_is_unsafe_cross_dir(old_dentry, new_dentry))
|
||||
nfs_sync_inode(old_inode);
|
||||
task = nfs_async_rename(old_dir, new_dir, old_dentry, new_dentry,
|
||||
must_unblock ? nfs_unblock_rename : NULL);
|
||||
|
||||
+1
-1
@@ -757,7 +757,6 @@ static void nfs_direct_write_completion(struct nfs_pgio_header *hdr)
|
||||
{
|
||||
struct nfs_direct_req *dreq = hdr->dreq;
|
||||
struct nfs_commit_info cinfo;
|
||||
struct nfs_page *req = nfs_list_entry(hdr->pages.next);
|
||||
struct inode *inode = dreq->inode;
|
||||
int flags = NFS_ODIRECT_DONE;
|
||||
|
||||
@@ -786,6 +785,7 @@ static void nfs_direct_write_completion(struct nfs_pgio_header *hdr)
|
||||
spin_unlock(&inode->i_lock);
|
||||
|
||||
while (!list_empty(&hdr->pages)) {
|
||||
struct nfs_page *req;
|
||||
|
||||
req = nfs_list_entry(hdr->pages.next);
|
||||
nfs_list_remove_request(req);
|
||||
|
||||
@@ -76,6 +76,7 @@ nfs4_fl_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev,
|
||||
struct page *scratch;
|
||||
struct list_head dsaddrs;
|
||||
struct nfs4_pnfs_ds_addr *da;
|
||||
struct net *net = server->nfs_client->cl_net;
|
||||
|
||||
/* set up xdr stream */
|
||||
scratch = alloc_page(gfp_flags);
|
||||
@@ -159,8 +160,7 @@ nfs4_fl_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev,
|
||||
|
||||
mp_count = be32_to_cpup(p); /* multipath count */
|
||||
for (j = 0; j < mp_count; j++) {
|
||||
da = nfs4_decode_mp_ds_addr(server->nfs_client->cl_net,
|
||||
&stream, gfp_flags);
|
||||
da = nfs4_decode_mp_ds_addr(net, &stream, gfp_flags);
|
||||
if (da)
|
||||
list_add_tail(&da->da_node, &dsaddrs);
|
||||
}
|
||||
@@ -170,7 +170,7 @@ nfs4_fl_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev,
|
||||
goto out_err_free_deviceid;
|
||||
}
|
||||
|
||||
dsaddr->ds_list[i] = nfs4_pnfs_ds_add(&dsaddrs, gfp_flags);
|
||||
dsaddr->ds_list[i] = nfs4_pnfs_ds_add(net, &dsaddrs, gfp_flags);
|
||||
if (!dsaddr->ds_list[i])
|
||||
goto out_err_drain_dsaddrs;
|
||||
trace_fl_getdevinfo(server, &pdev->dev_id, dsaddr->ds_list[i]->ds_remotestr);
|
||||
|
||||
@@ -1329,7 +1329,7 @@ static int ff_layout_read_done_cb(struct rpc_task *task,
|
||||
hdr->args.offset, hdr->args.count,
|
||||
&hdr->res.op_status, OP_READ,
|
||||
task->tk_status);
|
||||
trace_ff_layout_read_error(hdr);
|
||||
trace_ff_layout_read_error(hdr, task->tk_status);
|
||||
}
|
||||
|
||||
err = ff_layout_async_handle_error(task, hdr->args.context->state,
|
||||
@@ -1502,7 +1502,7 @@ static int ff_layout_write_done_cb(struct rpc_task *task,
|
||||
hdr->args.offset, hdr->args.count,
|
||||
&hdr->res.op_status, OP_WRITE,
|
||||
task->tk_status);
|
||||
trace_ff_layout_write_error(hdr);
|
||||
trace_ff_layout_write_error(hdr, task->tk_status);
|
||||
}
|
||||
|
||||
err = ff_layout_async_handle_error(task, hdr->args.context->state,
|
||||
@@ -1551,7 +1551,7 @@ static int ff_layout_commit_done_cb(struct rpc_task *task,
|
||||
data->args.offset, data->args.count,
|
||||
&data->res.op_status, OP_COMMIT,
|
||||
task->tk_status);
|
||||
trace_ff_layout_commit_error(data);
|
||||
trace_ff_layout_commit_error(data, task->tk_status);
|
||||
}
|
||||
|
||||
err = ff_layout_async_handle_error(task, NULL, data->ds_clp,
|
||||
|
||||
@@ -49,6 +49,7 @@ nfs4_ff_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev,
|
||||
struct nfs4_pnfs_ds_addr *da;
|
||||
struct nfs4_ff_layout_ds *new_ds = NULL;
|
||||
struct nfs4_ff_ds_version *ds_versions = NULL;
|
||||
struct net *net = server->nfs_client->cl_net;
|
||||
u32 mp_count;
|
||||
u32 version_count;
|
||||
__be32 *p;
|
||||
@@ -80,8 +81,7 @@ nfs4_ff_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev,
|
||||
|
||||
for (i = 0; i < mp_count; i++) {
|
||||
/* multipath ds */
|
||||
da = nfs4_decode_mp_ds_addr(server->nfs_client->cl_net,
|
||||
&stream, gfp_flags);
|
||||
da = nfs4_decode_mp_ds_addr(net, &stream, gfp_flags);
|
||||
if (da)
|
||||
list_add_tail(&da->da_node, &dsaddrs);
|
||||
}
|
||||
@@ -149,7 +149,7 @@ nfs4_ff_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev,
|
||||
new_ds->ds_versions = ds_versions;
|
||||
new_ds->ds_versions_cnt = version_count;
|
||||
|
||||
new_ds->ds = nfs4_pnfs_ds_add(&dsaddrs, gfp_flags);
|
||||
new_ds->ds = nfs4_pnfs_ds_add(net, &dsaddrs, gfp_flags);
|
||||
if (!new_ds->ds)
|
||||
goto out_err_drain_dsaddrs;
|
||||
|
||||
|
||||
+1
-1
@@ -278,6 +278,7 @@ nfs_local_open_fh(struct nfs_client *clp, const struct cred *cred,
|
||||
new = __nfs_local_open_fh(clp, cred, fh, nfl, mode);
|
||||
if (IS_ERR(new))
|
||||
return NULL;
|
||||
rcu_read_lock();
|
||||
/* try to swap in the pointer */
|
||||
spin_lock(&clp->cl_uuid.lock);
|
||||
nf = rcu_dereference_protected(*pnf, 1);
|
||||
@@ -287,7 +288,6 @@ nfs_local_open_fh(struct nfs_client *clp, const struct cred *cred,
|
||||
rcu_assign_pointer(*pnf, nf);
|
||||
}
|
||||
spin_unlock(&clp->cl_uuid.lock);
|
||||
rcu_read_lock();
|
||||
}
|
||||
nf = nfs_local_file_get(nf);
|
||||
rcu_read_unlock();
|
||||
|
||||
+5
-1
@@ -31,7 +31,11 @@ struct nfs_net {
|
||||
unsigned short nfs_callback_tcpport;
|
||||
unsigned short nfs_callback_tcpport6;
|
||||
int cb_users[NFS4_MAX_MINOR_VERSION + 1];
|
||||
#endif
|
||||
#endif /* CONFIG_NFS_V4 */
|
||||
#if IS_ENABLED(CONFIG_NFS_V4_1)
|
||||
struct list_head nfs4_data_server_cache;
|
||||
spinlock_t nfs4_data_server_lock;
|
||||
#endif /* CONFIG_NFS_V4_1 */
|
||||
struct nfs_netns_client *nfs_client;
|
||||
spinlock_t nfs_client_lock;
|
||||
ktime_t boot_time;
|
||||
|
||||
+1
-1
@@ -104,7 +104,7 @@ struct posix_acl *nfs3_get_acl(struct inode *inode, int type, bool rcu)
|
||||
|
||||
switch (status) {
|
||||
case 0:
|
||||
status = nfs_refresh_inode(inode, res.fattr);
|
||||
nfs_refresh_inode(inode, res.fattr);
|
||||
break;
|
||||
case -EPFNOSUPPORT:
|
||||
case -EPROTONOSUPPORT:
|
||||
|
||||
+17
-1
@@ -671,6 +671,15 @@ nfs4_async_handle_exception(struct rpc_task *task, struct nfs_server *server,
|
||||
struct nfs_client *clp = server->nfs_client;
|
||||
int ret;
|
||||
|
||||
if ((task->tk_rpc_status == -ENETDOWN ||
|
||||
task->tk_rpc_status == -ENETUNREACH) &&
|
||||
task->tk_flags & RPC_TASK_NETUNREACH_FATAL) {
|
||||
exception->delay = 0;
|
||||
exception->recovering = 0;
|
||||
exception->retry = 0;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ret = nfs4_do_handle_exception(server, errorcode, exception);
|
||||
if (exception->delay) {
|
||||
int ret2 = nfs4_exception_should_retrans(server, exception);
|
||||
@@ -7074,10 +7083,18 @@ static struct nfs4_unlockdata *nfs4_alloc_unlockdata(struct file_lock *fl,
|
||||
struct nfs4_unlockdata *p;
|
||||
struct nfs4_state *state = lsp->ls_state;
|
||||
struct inode *inode = state->inode;
|
||||
struct nfs_lock_context *l_ctx;
|
||||
|
||||
p = kzalloc(sizeof(*p), GFP_KERNEL);
|
||||
if (p == NULL)
|
||||
return NULL;
|
||||
l_ctx = nfs_get_lock_context(ctx);
|
||||
if (!IS_ERR(l_ctx)) {
|
||||
p->l_ctx = l_ctx;
|
||||
} else {
|
||||
kfree(p);
|
||||
return NULL;
|
||||
}
|
||||
p->arg.fh = NFS_FH(inode);
|
||||
p->arg.fl = &p->fl;
|
||||
p->arg.seqid = seqid;
|
||||
@@ -7085,7 +7102,6 @@ static struct nfs4_unlockdata *nfs4_alloc_unlockdata(struct file_lock *fl,
|
||||
p->lsp = lsp;
|
||||
/* Ensure we don't close file until we're done freeing locks! */
|
||||
p->ctx = get_nfs_open_context(ctx);
|
||||
p->l_ctx = nfs_get_lock_context(ctx);
|
||||
locks_init_lock(&p->fl);
|
||||
locks_copy_lock(&p->fl, fl);
|
||||
p->server = NFS_SERVER(inode);
|
||||
|
||||
+22
-12
@@ -2051,13 +2051,15 @@ TRACE_EVENT(fl_getdevinfo,
|
||||
|
||||
DECLARE_EVENT_CLASS(nfs4_flexfiles_io_event,
|
||||
TP_PROTO(
|
||||
const struct nfs_pgio_header *hdr
|
||||
const struct nfs_pgio_header *hdr,
|
||||
int error
|
||||
),
|
||||
|
||||
TP_ARGS(hdr),
|
||||
TP_ARGS(hdr, error),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field(unsigned long, error)
|
||||
__field(unsigned long, nfs_error)
|
||||
__field(dev_t, dev)
|
||||
__field(u32, fhandle)
|
||||
__field(u64, fileid)
|
||||
@@ -2073,7 +2075,8 @@ DECLARE_EVENT_CLASS(nfs4_flexfiles_io_event,
|
||||
TP_fast_assign(
|
||||
const struct inode *inode = hdr->inode;
|
||||
|
||||
__entry->error = hdr->res.op_status;
|
||||
__entry->error = -error;
|
||||
__entry->nfs_error = hdr->res.op_status;
|
||||
__entry->fhandle = nfs_fhandle_hash(hdr->args.fh);
|
||||
__entry->fileid = NFS_FILEID(inode);
|
||||
__entry->dev = inode->i_sb->s_dev;
|
||||
@@ -2088,7 +2091,8 @@ DECLARE_EVENT_CLASS(nfs4_flexfiles_io_event,
|
||||
|
||||
TP_printk(
|
||||
"error=%ld (%s) fileid=%02x:%02x:%llu fhandle=0x%08x "
|
||||
"offset=%llu count=%u stateid=%d:0x%08x dstaddr=%s",
|
||||
"offset=%llu count=%u stateid=%d:0x%08x dstaddr=%s "
|
||||
"nfs_error=%lu (%s)",
|
||||
-__entry->error,
|
||||
show_nfs4_status(__entry->error),
|
||||
MAJOR(__entry->dev), MINOR(__entry->dev),
|
||||
@@ -2096,28 +2100,32 @@ DECLARE_EVENT_CLASS(nfs4_flexfiles_io_event,
|
||||
__entry->fhandle,
|
||||
__entry->offset, __entry->count,
|
||||
__entry->stateid_seq, __entry->stateid_hash,
|
||||
__get_str(dstaddr)
|
||||
__get_str(dstaddr), __entry->nfs_error,
|
||||
show_nfs4_status(__entry->nfs_error)
|
||||
)
|
||||
);
|
||||
|
||||
#define DEFINE_NFS4_FLEXFILES_IO_EVENT(name) \
|
||||
DEFINE_EVENT(nfs4_flexfiles_io_event, name, \
|
||||
TP_PROTO( \
|
||||
const struct nfs_pgio_header *hdr \
|
||||
const struct nfs_pgio_header *hdr, \
|
||||
int error \
|
||||
), \
|
||||
TP_ARGS(hdr))
|
||||
TP_ARGS(hdr, error))
|
||||
DEFINE_NFS4_FLEXFILES_IO_EVENT(ff_layout_read_error);
|
||||
DEFINE_NFS4_FLEXFILES_IO_EVENT(ff_layout_write_error);
|
||||
|
||||
TRACE_EVENT(ff_layout_commit_error,
|
||||
TP_PROTO(
|
||||
const struct nfs_commit_data *data
|
||||
const struct nfs_commit_data *data,
|
||||
int error
|
||||
),
|
||||
|
||||
TP_ARGS(data),
|
||||
TP_ARGS(data, error),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field(unsigned long, error)
|
||||
__field(unsigned long, nfs_error)
|
||||
__field(dev_t, dev)
|
||||
__field(u32, fhandle)
|
||||
__field(u64, fileid)
|
||||
@@ -2131,7 +2139,8 @@ TRACE_EVENT(ff_layout_commit_error,
|
||||
TP_fast_assign(
|
||||
const struct inode *inode = data->inode;
|
||||
|
||||
__entry->error = data->res.op_status;
|
||||
__entry->error = -error;
|
||||
__entry->nfs_error = data->res.op_status;
|
||||
__entry->fhandle = nfs_fhandle_hash(data->args.fh);
|
||||
__entry->fileid = NFS_FILEID(inode);
|
||||
__entry->dev = inode->i_sb->s_dev;
|
||||
@@ -2142,14 +2151,15 @@ TRACE_EVENT(ff_layout_commit_error,
|
||||
|
||||
TP_printk(
|
||||
"error=%ld (%s) fileid=%02x:%02x:%llu fhandle=0x%08x "
|
||||
"offset=%llu count=%u dstaddr=%s",
|
||||
"offset=%llu count=%u dstaddr=%s nfs_error=%lu (%s)",
|
||||
-__entry->error,
|
||||
show_nfs4_status(__entry->error),
|
||||
MAJOR(__entry->dev), MINOR(__entry->dev),
|
||||
(unsigned long long)__entry->fileid,
|
||||
__entry->fhandle,
|
||||
__entry->offset, __entry->count,
|
||||
__get_str(dstaddr)
|
||||
__get_str(dstaddr), __entry->nfs_error,
|
||||
show_nfs4_status(__entry->nfs_error)
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
+34
-17
@@ -745,6 +745,14 @@ pnfs_mark_matching_lsegs_invalid(struct pnfs_layout_hdr *lo,
|
||||
return remaining;
|
||||
}
|
||||
|
||||
static void pnfs_reset_return_info(struct pnfs_layout_hdr *lo)
|
||||
{
|
||||
struct pnfs_layout_segment *lseg;
|
||||
|
||||
list_for_each_entry(lseg, &lo->plh_return_segs, pls_list)
|
||||
pnfs_set_plh_return_info(lo, lseg->pls_range.iomode, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
pnfs_free_returned_lsegs(struct pnfs_layout_hdr *lo,
|
||||
struct list_head *free_me,
|
||||
@@ -1246,21 +1254,15 @@ static void pnfs_clear_layoutcommit(struct inode *inode,
|
||||
static void
|
||||
pnfs_layoutreturn_retry_later_locked(struct pnfs_layout_hdr *lo,
|
||||
const nfs4_stateid *arg_stateid,
|
||||
const struct pnfs_layout_range *range)
|
||||
const struct pnfs_layout_range *range,
|
||||
struct list_head *freeme)
|
||||
{
|
||||
const struct pnfs_layout_segment *lseg;
|
||||
u32 seq = be32_to_cpu(arg_stateid->seqid);
|
||||
|
||||
if (pnfs_layout_is_valid(lo) &&
|
||||
nfs4_stateid_match_other(&lo->plh_stateid, arg_stateid)) {
|
||||
list_for_each_entry(lseg, &lo->plh_return_segs, pls_list) {
|
||||
if (pnfs_seqid_is_newer(lseg->pls_seq, seq) ||
|
||||
!pnfs_should_free_range(&lseg->pls_range, range))
|
||||
continue;
|
||||
pnfs_set_plh_return_info(lo, range->iomode, seq);
|
||||
break;
|
||||
}
|
||||
}
|
||||
nfs4_stateid_match_other(&lo->plh_stateid, arg_stateid))
|
||||
pnfs_reset_return_info(lo);
|
||||
else
|
||||
pnfs_mark_layout_stateid_invalid(lo, freeme);
|
||||
pnfs_clear_layoutreturn_waitbit(lo);
|
||||
}
|
||||
|
||||
void pnfs_layoutreturn_retry_later(struct pnfs_layout_hdr *lo,
|
||||
@@ -1268,11 +1270,12 @@ void pnfs_layoutreturn_retry_later(struct pnfs_layout_hdr *lo,
|
||||
const struct pnfs_layout_range *range)
|
||||
{
|
||||
struct inode *inode = lo->plh_inode;
|
||||
LIST_HEAD(freeme);
|
||||
|
||||
spin_lock(&inode->i_lock);
|
||||
pnfs_layoutreturn_retry_later_locked(lo, arg_stateid, range);
|
||||
pnfs_clear_layoutreturn_waitbit(lo);
|
||||
pnfs_layoutreturn_retry_later_locked(lo, arg_stateid, range, &freeme);
|
||||
spin_unlock(&inode->i_lock);
|
||||
pnfs_free_lseg_list(&freeme);
|
||||
}
|
||||
|
||||
void pnfs_layoutreturn_free_lsegs(struct pnfs_layout_hdr *lo,
|
||||
@@ -1292,6 +1295,7 @@ void pnfs_layoutreturn_free_lsegs(struct pnfs_layout_hdr *lo,
|
||||
pnfs_mark_matching_lsegs_invalid(lo, &freeme, range, seq);
|
||||
pnfs_free_returned_lsegs(lo, &freeme, range, seq);
|
||||
pnfs_set_layout_stateid(lo, stateid, NULL, true);
|
||||
pnfs_reset_return_info(lo);
|
||||
} else
|
||||
pnfs_mark_layout_stateid_invalid(lo, &freeme);
|
||||
out_unlock:
|
||||
@@ -1661,6 +1665,18 @@ int pnfs_roc_done(struct rpc_task *task, struct nfs4_layoutreturn_args **argpp,
|
||||
/* Was there an RPC level error? If not, retry */
|
||||
if (task->tk_rpc_status == 0)
|
||||
break;
|
||||
/*
|
||||
* Is there a fatal network level error?
|
||||
* If so release the layout, but flag the error.
|
||||
*/
|
||||
if ((task->tk_rpc_status == -ENETDOWN ||
|
||||
task->tk_rpc_status == -ENETUNREACH) &&
|
||||
task->tk_flags & RPC_TASK_NETUNREACH_FATAL) {
|
||||
*ret = 0;
|
||||
(*respp)->lrs_present = 0;
|
||||
retval = -EIO;
|
||||
break;
|
||||
}
|
||||
/* If the call was not sent, let caller handle it */
|
||||
if (!RPC_WAS_SENT(task))
|
||||
return 0;
|
||||
@@ -1695,6 +1711,7 @@ void pnfs_roc_release(struct nfs4_layoutreturn_args *args,
|
||||
struct inode *inode = args->inode;
|
||||
const nfs4_stateid *res_stateid = NULL;
|
||||
struct nfs4_xdr_opaque_data *ld_private = args->ld_private;
|
||||
LIST_HEAD(freeme);
|
||||
|
||||
switch (ret) {
|
||||
case -NFS4ERR_BADSESSION:
|
||||
@@ -1703,9 +1720,9 @@ void pnfs_roc_release(struct nfs4_layoutreturn_args *args,
|
||||
case -NFS4ERR_NOMATCHING_LAYOUT:
|
||||
spin_lock(&inode->i_lock);
|
||||
pnfs_layoutreturn_retry_later_locked(lo, &args->stateid,
|
||||
&args->range);
|
||||
pnfs_clear_layoutreturn_waitbit(lo);
|
||||
&args->range, &freeme);
|
||||
spin_unlock(&inode->i_lock);
|
||||
pnfs_free_lseg_list(&freeme);
|
||||
break;
|
||||
case 0:
|
||||
if (res->lrs_present)
|
||||
|
||||
+3
-1
@@ -60,6 +60,7 @@ struct nfs4_pnfs_ds {
|
||||
struct list_head ds_node; /* nfs4_pnfs_dev_hlist dev_dslist */
|
||||
char *ds_remotestr; /* comma sep list of addrs */
|
||||
struct list_head ds_addrs;
|
||||
const struct net *ds_net;
|
||||
struct nfs_client *ds_clp;
|
||||
refcount_t ds_count;
|
||||
unsigned long ds_state;
|
||||
@@ -415,7 +416,8 @@ int pnfs_generic_commit_pagelist(struct inode *inode,
|
||||
int pnfs_generic_scan_commit_lists(struct nfs_commit_info *cinfo, int max);
|
||||
void pnfs_generic_write_commit_done(struct rpc_task *task, void *data);
|
||||
void nfs4_pnfs_ds_put(struct nfs4_pnfs_ds *ds);
|
||||
struct nfs4_pnfs_ds *nfs4_pnfs_ds_add(struct list_head *dsaddrs,
|
||||
struct nfs4_pnfs_ds *nfs4_pnfs_ds_add(const struct net *net,
|
||||
struct list_head *dsaddrs,
|
||||
gfp_t gfp_flags);
|
||||
void nfs4_pnfs_v3_ds_connect_unload(void);
|
||||
int nfs4_pnfs_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds,
|
||||
|
||||
+18
-14
@@ -16,6 +16,7 @@
|
||||
#include "nfs4session.h"
|
||||
#include "internal.h"
|
||||
#include "pnfs.h"
|
||||
#include "netns.h"
|
||||
|
||||
#define NFSDBG_FACILITY NFSDBG_PNFS
|
||||
|
||||
@@ -504,14 +505,14 @@ EXPORT_SYMBOL_GPL(pnfs_generic_commit_pagelist);
|
||||
/*
|
||||
* Data server cache
|
||||
*
|
||||
* Data servers can be mapped to different device ids.
|
||||
* nfs4_pnfs_ds reference counting
|
||||
* Data servers can be mapped to different device ids, but should
|
||||
* never be shared between net namespaces.
|
||||
*
|
||||
* nfs4_pnfs_ds reference counting:
|
||||
* - set to 1 on allocation
|
||||
* - incremented when a device id maps a data server already in the cache.
|
||||
* - decremented when deviceid is removed from the cache.
|
||||
*/
|
||||
static DEFINE_SPINLOCK(nfs4_ds_cache_lock);
|
||||
static LIST_HEAD(nfs4_data_server_cache);
|
||||
|
||||
/* Debug routines */
|
||||
static void
|
||||
@@ -604,11 +605,11 @@ _same_data_server_addrs_locked(const struct list_head *dsaddrs1,
|
||||
* Lookup DS by addresses. nfs4_ds_cache_lock is held
|
||||
*/
|
||||
static struct nfs4_pnfs_ds *
|
||||
_data_server_lookup_locked(const struct list_head *dsaddrs)
|
||||
_data_server_lookup_locked(const struct nfs_net *nn, const struct list_head *dsaddrs)
|
||||
{
|
||||
struct nfs4_pnfs_ds *ds;
|
||||
|
||||
list_for_each_entry(ds, &nfs4_data_server_cache, ds_node)
|
||||
list_for_each_entry(ds, &nn->nfs4_data_server_cache, ds_node)
|
||||
if (_same_data_server_addrs_locked(&ds->ds_addrs, dsaddrs))
|
||||
return ds;
|
||||
return NULL;
|
||||
@@ -653,10 +654,11 @@ static void destroy_ds(struct nfs4_pnfs_ds *ds)
|
||||
|
||||
void nfs4_pnfs_ds_put(struct nfs4_pnfs_ds *ds)
|
||||
{
|
||||
if (refcount_dec_and_lock(&ds->ds_count,
|
||||
&nfs4_ds_cache_lock)) {
|
||||
struct nfs_net *nn = net_generic(ds->ds_net, nfs_net_id);
|
||||
|
||||
if (refcount_dec_and_lock(&ds->ds_count, &nn->nfs4_data_server_lock)) {
|
||||
list_del_init(&ds->ds_node);
|
||||
spin_unlock(&nfs4_ds_cache_lock);
|
||||
spin_unlock(&nn->nfs4_data_server_lock);
|
||||
destroy_ds(ds);
|
||||
}
|
||||
}
|
||||
@@ -716,8 +718,9 @@ out_err:
|
||||
* uncached and return cached struct nfs4_pnfs_ds.
|
||||
*/
|
||||
struct nfs4_pnfs_ds *
|
||||
nfs4_pnfs_ds_add(struct list_head *dsaddrs, gfp_t gfp_flags)
|
||||
nfs4_pnfs_ds_add(const struct net *net, struct list_head *dsaddrs, gfp_t gfp_flags)
|
||||
{
|
||||
struct nfs_net *nn = net_generic(net, nfs_net_id);
|
||||
struct nfs4_pnfs_ds *tmp_ds, *ds = NULL;
|
||||
char *remotestr;
|
||||
|
||||
@@ -733,16 +736,17 @@ nfs4_pnfs_ds_add(struct list_head *dsaddrs, gfp_t gfp_flags)
|
||||
/* this is only used for debugging, so it's ok if its NULL */
|
||||
remotestr = nfs4_pnfs_remotestr(dsaddrs, gfp_flags);
|
||||
|
||||
spin_lock(&nfs4_ds_cache_lock);
|
||||
tmp_ds = _data_server_lookup_locked(dsaddrs);
|
||||
spin_lock(&nn->nfs4_data_server_lock);
|
||||
tmp_ds = _data_server_lookup_locked(nn, dsaddrs);
|
||||
if (tmp_ds == NULL) {
|
||||
INIT_LIST_HEAD(&ds->ds_addrs);
|
||||
list_splice_init(dsaddrs, &ds->ds_addrs);
|
||||
ds->ds_remotestr = remotestr;
|
||||
refcount_set(&ds->ds_count, 1);
|
||||
INIT_LIST_HEAD(&ds->ds_node);
|
||||
ds->ds_net = net;
|
||||
ds->ds_clp = NULL;
|
||||
list_add(&ds->ds_node, &nfs4_data_server_cache);
|
||||
list_add(&ds->ds_node, &nn->nfs4_data_server_cache);
|
||||
dprintk("%s add new data server %s\n", __func__,
|
||||
ds->ds_remotestr);
|
||||
} else {
|
||||
@@ -754,7 +758,7 @@ nfs4_pnfs_ds_add(struct list_head *dsaddrs, gfp_t gfp_flags)
|
||||
refcount_read(&tmp_ds->ds_count));
|
||||
ds = tmp_ds;
|
||||
}
|
||||
spin_unlock(&nfs4_ds_cache_lock);
|
||||
spin_unlock(&nn->nfs4_data_server_lock);
|
||||
out:
|
||||
return ds;
|
||||
}
|
||||
|
||||
@@ -213,6 +213,15 @@ struct nfs_server {
|
||||
char *fscache_uniq; /* Uniquifier (or NULL) */
|
||||
#endif
|
||||
|
||||
/* The following #defines numerically match the NFSv4 equivalents */
|
||||
#define NFS_FH_NOEXPIRE_WITH_OPEN (0x1)
|
||||
#define NFS_FH_VOLATILE_ANY (0x2)
|
||||
#define NFS_FH_VOL_MIGRATION (0x4)
|
||||
#define NFS_FH_VOL_RENAME (0x8)
|
||||
#define NFS_FH_RENAME_UNSAFE (NFS_FH_VOLATILE_ANY | NFS_FH_VOL_RENAME)
|
||||
u32 fh_expire_type; /* V4 bitmask representing file
|
||||
handle volatility type for
|
||||
this filesystem */
|
||||
u32 pnfs_blksize; /* layout_blksize attr */
|
||||
#if IS_ENABLED(CONFIG_NFS_V4)
|
||||
u32 attr_bitmask[3];/* V4 bitmask representing the set
|
||||
@@ -236,9 +245,6 @@ struct nfs_server {
|
||||
u32 acl_bitmask; /* V4 bitmask representing the ACEs
|
||||
that are supported on this
|
||||
filesystem */
|
||||
u32 fh_expire_type; /* V4 bitmask representing file
|
||||
handle volatility type for
|
||||
this filesystem */
|
||||
struct pnfs_layoutdriver_type *pnfs_curr_ld; /* Active layout driver */
|
||||
struct rpc_wait_queue roc_rpcwaitq;
|
||||
void *pnfs_ld_data; /* per mount point data */
|
||||
|
||||
Reference in New Issue
Block a user