mirror of
https://github.com/torvalds/linux.git
synced 2026-09-13 15:40:03 +02:00
NFS client updates for Linux 7.3
Highlights include:
Stable fixes:
- SunRPC: Use-after-free fixes for the sunrpc client code
- NFSv4: Delegation hash table leak
- lockd: NULL dereference on lockowner allocation failure
- SunRPC: Fix a handshake completion race in the TLS code
- NFSv4.1/pNFS: Fix an error sign checking issue when deciding whether
the layout is still in use, or can be returned.
- NFSv4.1: Fix a layout segment leak in pnfs_layout_process()
Other bugfixes:
- SunRPC: Fix a missing NULL check in the rpcbind client
- SunRPC: annotate shared socket callbacks with READ_ONCE/WRITE_ONCE
- NFSv4: nfs_inode_set_delegation() error paths should return the delegation
- NFSv4: Use clear_and_wake_up_bit() in nfs_clear_invalid_mapping() and
the pNFS code.
- NFSv4: Fix the nfs4_alloc_client() error paths to free the IDR
allocation
- NFS: fix folio dereference before NULL check in nfs_inode_remove_request()
- NFS: Fix delayed delegation return
- NFSv4: Fix another state manager race with umount
- pNFS/blocklayout: Fix device leaks on parse failure
- pNFS: Avoid cancelling in-flight I/O during a layout recall if the
server doesn't require it
- NFSv4/flexfiles: report cancelled I/O as a layout error
- NFSv4/flexfiles: fix NULL dereference for NFSv4.0 data servers
- NFSv4: Fix incorrect argument passed to nfs4_delete_lease()
- NFSv3: Fix several symlink issues resulting from nfs_atomic_open_v23()
- NFSv4.1: Fix an uninitialised variable issue in the callback code
- NFSv4.2: fix LAYOUTSTATS send buffer exhaustion
Features and cleanups:
- NFSv4.2: Allow the server to specify that file data may not be cached
- NFS/localio: optimise I/O submission when when not doing memory reclaim
- NFS/localio: Remove duplicate wait code in nfs_local_commit
- NFSv4/flexfiles: support loosely coupled NFSv4.x data servers
- NFSv4/pnfs: key the data server cache on the NFS version
-----BEGIN PGP SIGNATURE-----
iHUEABYKAB0WIQR8xgHcVzJNfOYElJo6EXfx2a6V0QUCao9SMwAKCRA6EXfx2a6V
0VxpAP9KSFbBnHU/DTq6zJ0xNeatZLBssrdkD1aPbHGsJPXukgEAgmo9tk0AgdJo
gxPeuVJIepg9PEIxI6jd6TxwpUV8NQI=
=k59o
-----END PGP SIGNATURE-----
Merge tag 'nfs-for-7.3-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS client updates from Trond Myklebust:
"Highlights include:
Stable fixes:
- Use-after-free fixes for the sunrpc client code
- Delegation hash table leak
- NULL dereference on lockowner allocation failure
- Fix a handshake completion race in the TLS code
- Fix an error sign checking issue when deciding whether the pNFS
layout is still in use, or can be returned
- Fix a layout segment leak in pnfs_layout_process()
Other bugfixes:
- Fix a missing NULL check in the rpcbind client
- annotate shared socket callbacks with READ_ONCE/WRITE_ONCE
- nfs_inode_set_delegation() error paths should return the delegation
- Use clear_and_wake_up_bit() in nfs_clear_invalid_mapping() and the
pNFS code.
- Fix the nfs4_alloc_client() error paths to free the IDR allocation
- fix folio dereference before NULL check in
nfs_inode_remove_request()
- Fix delayed delegation return
- Fix another state manager race with umount
- Fix device leaks on parse failure
- Avoid cancelling in-flight I/O during a layout recall if the server
doesn't require it
- flexfiles: report cancelled I/O as a layout error
- flexfiles: fix NULL dereference for NFSv4.0 data servers
- Fix incorrect argument passed to nfs4_delete_lease()
- Fix several symlink issues resulting from nfs_atomic_open_v23()
- Fix an uninitialised variable issue in the NFSv4.1 callback code
- fix LAYOUTSTATS send buffer exhaustion
Features and cleanups:
- NFSv4.2: Allow the server to specify that file data may not be cached
- localio: optimise I/O submission when when not doing memory reclaim
- localio: Remove duplicate wait code in nfs_local_commit
- flexfiles: support loosely coupled NFSv4.x data servers
- pNFS: key the data server cache on the NFS version"
* tag 'nfs-for-7.3-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: (33 commits)
NFSv4.1: fix layout segment leak on the pnfs_layout_process() forget path
NFSv4/pnfs: key the data server cache on the NFS version
NFSv4.2: fix LAYOUTSTATS send buffer exhaustion
pNFS: Fix EBUSY check in pnfs_layout_need_return
NFSv4.1: zero referring call lists before decoding
nfs: fix ENXIO on O_CREAT open of existing symlink over NFSv3
SUNRPC: wait for in-flight client TLS handshake callback
NFSv4: Fix incorrect argument passed to nfs4_delete_lease() in nfs4_add_lease()
lockd: fix NULL dereference on lockowner allocation failure
NFS: fix delegation_hash_table leak when nfs4_server_common_setup() fails
NFSv4/flexfiles: support loosely coupled data servers
NFSv4/flexfiles: fix NULL dereference for NFSv4.0 data servers
NFSv4: pin the superblock for active state owners
sunrpc: fix use-after-free in __rpc_clnt_handle_event and __rpc_clnt_remove_pipedir
NFS/localio: issue commit inline when not in a memory-reclaim context
NFS/localio: remove dead FLUSH_SYNC handling from nfs_local_commit
NFS/localio: issue IO inline when not in a memory-reclaim context
NFS: Fix delayed delegation return list handling
NFS: Verify symlink inode before caching target
NFS: fix folio dereference before NULL check in nfs_inode_remove_request()
...
This commit is contained in:
commit
73e3f07100
|
|
@ -487,9 +487,12 @@ static const struct file_lock_operations nlmclnt_lock_ops = {
|
|||
static void nlmclnt_locks_init_private(struct file_lock *fl, struct nlm_host *host)
|
||||
{
|
||||
fl->fl_u.nfs_fl.state = 0;
|
||||
fl->fl_ops = NULL;
|
||||
fl->fl_u.nfs_fl.owner = nlmclnt_find_lockowner(host,
|
||||
fl->c.flc_owner);
|
||||
INIT_LIST_HEAD(&fl->fl_u.nfs_fl.list);
|
||||
if (!fl->fl_u.nfs_fl.owner)
|
||||
return;
|
||||
fl->fl_ops = &nlmclnt_lock_ops;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -86,15 +86,17 @@ bl_free_device(struct pnfs_block_dev *dev)
|
|||
{
|
||||
bl_unregister_dev(dev);
|
||||
|
||||
if (dev->nr_children) {
|
||||
if (dev->children) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < dev->nr_children; i++)
|
||||
bl_free_device(&dev->children[i]);
|
||||
kfree(dev->children);
|
||||
} else {
|
||||
if (dev->bdev_file)
|
||||
fput(dev->bdev_file);
|
||||
dev->children = NULL;
|
||||
dev->nr_children = 0;
|
||||
} else if (dev->bdev_file) {
|
||||
fput(dev->bdev_file);
|
||||
dev->bdev_file = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -444,6 +446,7 @@ bl_parse_scsi(struct nfs_server *server, struct pnfs_block_dev *d,
|
|||
|
||||
out_blkdev_put:
|
||||
fput(d->bdev_file);
|
||||
d->bdev_file = NULL;
|
||||
return error;
|
||||
}
|
||||
|
||||
|
|
@ -479,8 +482,11 @@ bl_parse_concat(struct nfs_server *server, struct pnfs_block_dev *d,
|
|||
for (i = 0; i < v->concat.volumes_count; i++) {
|
||||
ret = bl_parse_deviceid(server, &d->children[i],
|
||||
volumes, v->concat.volumes[i], gfp_mask);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
bl_free_device(&d->children[i]);
|
||||
bl_free_device(d);
|
||||
return ret;
|
||||
}
|
||||
|
||||
d->nr_children++;
|
||||
d->children[i].start += len;
|
||||
|
|
@ -508,8 +514,11 @@ bl_parse_stripe(struct nfs_server *server, struct pnfs_block_dev *d,
|
|||
for (i = 0; i < v->stripe.volumes_count; i++) {
|
||||
ret = bl_parse_deviceid(server, &d->children[i],
|
||||
volumes, v->stripe.volumes[i], gfp_mask);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
bl_free_device(&d->children[i]);
|
||||
bl_free_device(d);
|
||||
return ret;
|
||||
}
|
||||
|
||||
d->nr_children++;
|
||||
len += d->children[i].len;
|
||||
|
|
|
|||
|
|
@ -291,7 +291,8 @@ static u32 initiate_file_draining(struct nfs_client *clp,
|
|||
pnfs_set_layout_stateid(lo, &args->cbl_stateid, NULL, true);
|
||||
switch (pnfs_mark_matching_lsegs_return(lo, &free_me_list,
|
||||
&args->cbl_range,
|
||||
be32_to_cpu(args->cbl_stateid.seqid))) {
|
||||
be32_to_cpu(args->cbl_stateid.seqid),
|
||||
args->cbl_layoutchanged)) {
|
||||
case 0:
|
||||
case -EBUSY:
|
||||
/* There are layout segments that need to be returned */
|
||||
|
|
@ -317,7 +318,7 @@ static u32 initiate_file_draining(struct nfs_client *clp,
|
|||
nfs_iput_and_deactive(ino);
|
||||
out_noput:
|
||||
trace_nfs4_cb_layoutrecall_file(clp, &args->cbl_fh, ino,
|
||||
&args->cbl_stateid, -rv);
|
||||
&args->cbl_stateid, args->cbl_layoutchanged, -rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -417,7 +417,7 @@ static __be32 decode_cb_sequence_args(struct svc_rqst *rqstp,
|
|||
args->csa_nrclists = ntohl(*p++);
|
||||
args->csa_rclists = NULL;
|
||||
if (args->csa_nrclists) {
|
||||
args->csa_rclists = kmalloc_objs(*args->csa_rclists,
|
||||
args->csa_rclists = kzalloc_objs(*args->csa_rclists,
|
||||
args->csa_nrclists);
|
||||
if (unlikely(args->csa_rclists == NULL))
|
||||
return htonl(NFS4ERR_RESOURCE);
|
||||
|
|
|
|||
|
|
@ -215,10 +215,22 @@ static void nfs_cb_idr_remove_locked(struct nfs_client *clp)
|
|||
{
|
||||
struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id);
|
||||
|
||||
if (clp->cl_cb_ident)
|
||||
if (clp->cl_cb_ident) {
|
||||
idr_remove(&nn->cb_ident_idr, clp->cl_cb_ident);
|
||||
clp->cl_cb_ident = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void nfs_cb_idr_remove(struct nfs_client *clp)
|
||||
{
|
||||
struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id);
|
||||
|
||||
spin_lock(&nn->nfs_client_lock);
|
||||
nfs_cb_idr_remove_locked(clp);
|
||||
spin_unlock(&nn->nfs_client_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nfs_cb_idr_remove);
|
||||
|
||||
static void pnfs_init_server(struct nfs_server *server)
|
||||
{
|
||||
rpc_init_wait_queue(&server->roc_rpcwaitq, "pNFS ROC");
|
||||
|
|
|
|||
|
|
@ -447,11 +447,14 @@ int nfs_inode_set_delegation(struct inode *inode, const struct cred *cred,
|
|||
struct nfs_inode *nfsi = NFS_I(inode);
|
||||
struct nfs_delegation *delegation, *old_delegation;
|
||||
struct nfs_delegation *freeme = NULL;
|
||||
bool orphaned = false;
|
||||
int status = 0;
|
||||
|
||||
delegation = kmalloc_obj(*delegation, GFP_KERNEL_ACCOUNT);
|
||||
if (delegation == NULL)
|
||||
if (delegation == NULL) {
|
||||
nfs4_proc_delegreturn(inode, cred, stateid, NULL, 0);
|
||||
return -ENOMEM;
|
||||
}
|
||||
nfs4_stateid_copy(&delegation->stateid, stateid);
|
||||
refcount_set(&delegation->refcount, 1);
|
||||
delegation->type = type;
|
||||
|
|
@ -500,11 +503,15 @@ int nfs_inode_set_delegation(struct inode *inode, const struct cred *cred,
|
|||
goto out;
|
||||
}
|
||||
if (test_and_set_bit(NFS_DELEGATION_RETURNING,
|
||||
&old_delegation->flags))
|
||||
&old_delegation->flags)) {
|
||||
orphaned = true;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
if (!nfs_detach_delegations_locked(nfsi, old_delegation, clp))
|
||||
if (!nfs_detach_delegations_locked(nfsi, old_delegation, clp)) {
|
||||
orphaned = true;
|
||||
goto out;
|
||||
}
|
||||
freeme = old_delegation;
|
||||
add_new:
|
||||
/*
|
||||
|
|
@ -539,8 +546,11 @@ int nfs_inode_set_delegation(struct inode *inode, const struct cred *cred,
|
|||
nfs_update_delegated_mtime(inode);
|
||||
out:
|
||||
spin_unlock(&clp->cl_lock);
|
||||
if (delegation != NULL)
|
||||
if (delegation != NULL) {
|
||||
if (orphaned)
|
||||
nfs_do_return_delegation(inode, delegation, 0);
|
||||
__nfs_free_delegation(delegation);
|
||||
}
|
||||
if (freeme != NULL) {
|
||||
nfs_do_return_delegation(inode, freeme, 0);
|
||||
nfs_mark_delegation_revoked(server, freeme);
|
||||
|
|
@ -594,7 +604,7 @@ static int nfs_end_delegation_return(struct inode *inode,
|
|||
spin_lock(&server->delegations_lock);
|
||||
if (list_empty(&delegation->entry))
|
||||
refcount_inc(&delegation->refcount);
|
||||
list_move_tail(&delegation->entry, &server->delegations_return);
|
||||
list_move_tail(&delegation->entry, &server->delegations_delayed);
|
||||
spin_unlock(&server->delegations_lock);
|
||||
set_bit(NFS4CLNT_DELEGRETURN_DELAYED, &server->nfs_client->cl_state);
|
||||
abort:
|
||||
|
|
|
|||
17
fs/nfs/dir.c
17
fs/nfs/dir.c
|
|
@ -2208,6 +2208,10 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry,
|
|||
goto out;
|
||||
}
|
||||
file->f_mode |= FMODE_CAN_ODIRECT;
|
||||
if (test_bit(NFS_CONTEXT_O_DIRECT, &ctx->flags)) {
|
||||
file->f_flags |= O_DIRECT;
|
||||
open_flags |= O_DIRECT;
|
||||
}
|
||||
|
||||
err = nfs_finish_open(ctx, ctx->dentry, file, open_flags);
|
||||
trace_nfs_atomic_open_exit(dir, ctx, open_flags, err);
|
||||
|
|
@ -2319,6 +2323,13 @@ int nfs_atomic_open_v23(struct inode *dir, struct dentry *dentry,
|
|||
if (open_flags & O_CREAT) {
|
||||
error = nfs_do_create(dir, dentry, mode, open_flags);
|
||||
if (!error) {
|
||||
/* With UNCHECKED mode, a server may return NFS3_OK for
|
||||
* a pre-existing non-regular file (e.g. a symlink).
|
||||
* Let the VFS handle it; calling finish_open() would
|
||||
* hit no_open() and return -ENXIO.
|
||||
*/
|
||||
if (!d_is_reg(dentry))
|
||||
return finish_no_open(file, NULL);
|
||||
file->f_mode |= FMODE_CREATED;
|
||||
return finish_open(file, dentry, NULL);
|
||||
} else if (error != -EEXIST || open_flags & O_EXCL)
|
||||
|
|
@ -2669,6 +2680,12 @@ int nfs_symlink(struct mnt_idmap *idmap, struct inode *dir,
|
|||
return error;
|
||||
}
|
||||
|
||||
if (unlikely(!d_is_symlink(dentry))) {
|
||||
d_drop(dentry);
|
||||
folio_put(folio);
|
||||
return 0;
|
||||
}
|
||||
|
||||
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -170,7 +170,8 @@ 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(net, &dsaddrs, gfp_flags);
|
||||
dsaddr->ds_list[i] = nfs4_pnfs_ds_add(net, &dsaddrs, 4,
|
||||
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);
|
||||
|
|
@ -280,7 +281,7 @@ nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx)
|
|||
|
||||
status = nfs4_pnfs_ds_connect(s, ds, devid, dataserver_timeo,
|
||||
dataserver_retrans, 4,
|
||||
s->nfs_client->cl_minorversion);
|
||||
s->nfs_client->cl_minorversion, true);
|
||||
if (status) {
|
||||
nfs4_mark_deviceid_unavailable(devid);
|
||||
ret = NULL;
|
||||
|
|
|
|||
|
|
@ -1322,7 +1322,8 @@ static int ff_layout_async_handle_error_v4(struct rpc_task *task,
|
|||
struct pnfs_layout_hdr *lo = lseg->pls_layout;
|
||||
struct inode *inode = lo->plh_inode;
|
||||
struct nfs4_deviceid_node *devid = FF_LAYOUT_DEVID_NODE(lseg, idx, dss_id);
|
||||
struct nfs4_slot_table *tbl = &clp->cl_session->fc_slot_table;
|
||||
struct nfs4_slot_table *tbl = nfs4_has_session(clp) ?
|
||||
&clp->cl_session->fc_slot_table : clp->cl_slot_tbl;
|
||||
|
||||
switch (op_status) {
|
||||
case NFS4_OK:
|
||||
|
|
@ -1543,6 +1544,17 @@ static void ff_layout_io_track_ds_error(struct pnfs_layout_segment *lseg,
|
|||
case -EACCES:
|
||||
*op_status = status = NFS4ERR_ACCESS;
|
||||
break;
|
||||
case -ECANCELED:
|
||||
/*
|
||||
* In-flight I/O we cancelled to return a recalled or
|
||||
* revoked layout. Report it as a failure to reach the
|
||||
* device (NFS4ERR_NXIO), like the transport errors
|
||||
* above, so the server can reconcile the affected mirror
|
||||
* instance. We aborted the I/O ourselves rather than
|
||||
* observe the device fail, so don't condemn it below.
|
||||
*/
|
||||
*op_status = status = NFS4ERR_NXIO;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
|
@ -1553,6 +1565,15 @@ static void ff_layout_io_track_ds_error(struct pnfs_layout_segment *lseg,
|
|||
mirror, dss_id, offset, length, status, opnum,
|
||||
nfs_io_gfp_mask());
|
||||
|
||||
/*
|
||||
* I/O we cancelled ourselves to return a recalled or revoked layout
|
||||
* is reported above so the server can reconcile the mirror, but we
|
||||
* have no evidence the device is at fault: don't mark it unreachable
|
||||
* or force a return.
|
||||
*/
|
||||
if (error == -ECANCELED)
|
||||
goto out;
|
||||
|
||||
switch (status) {
|
||||
case NFS4ERR_DELAY:
|
||||
case NFS4ERR_GRACE:
|
||||
|
|
@ -1572,6 +1593,7 @@ static void ff_layout_io_track_ds_error(struct pnfs_layout_segment *lseg,
|
|||
lseg);
|
||||
}
|
||||
|
||||
out:
|
||||
dprintk("%s: err %d op %d status %u\n", __func__, err, opnum, status);
|
||||
}
|
||||
|
||||
|
|
@ -2462,7 +2484,7 @@ static void ff_layout_cancel_io(struct pnfs_layout_segment *lseg)
|
|||
clnt = ds_clp->cl_rpcclient;
|
||||
if (!clnt)
|
||||
continue;
|
||||
if (!rpc_cancel_tasks(clnt, -EAGAIN,
|
||||
if (!rpc_cancel_tasks(clnt, -ECANCELED,
|
||||
ff_layout_match_io, lseg))
|
||||
continue;
|
||||
rpc_clnt_disconnect(clnt);
|
||||
|
|
|
|||
|
|
@ -153,7 +153,8 @@ 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(net, &dsaddrs, gfp_flags);
|
||||
new_ds->ds = nfs4_pnfs_ds_add(net, &dsaddrs, ds_versions[0].version,
|
||||
gfp_flags);
|
||||
if (!new_ds->ds)
|
||||
goto out_err_drain_dsaddrs;
|
||||
|
||||
|
|
@ -399,7 +400,8 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg,
|
|||
status = nfs4_pnfs_ds_connect(s, ds, &mirror->dss[dss_id].mirror_ds->id_node,
|
||||
dataserver_timeo, dataserver_retrans,
|
||||
mirror->dss[dss_id].mirror_ds->ds_versions[0].version,
|
||||
mirror->dss[dss_id].mirror_ds->ds_versions[0].minor_version);
|
||||
mirror->dss[dss_id].mirror_ds->ds_versions[0].minor_version,
|
||||
mirror->dss[dss_id].mirror_ds->ds_versions[0].tightly_coupled);
|
||||
|
||||
/* connect success, check rsize/wsize limit */
|
||||
if (!status) {
|
||||
|
|
|
|||
|
|
@ -507,6 +507,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
|
|||
inode->i_blocks = 0;
|
||||
nfsi->write_io = 0;
|
||||
nfsi->read_io = 0;
|
||||
nfsi->uncacheable_file_data = false;
|
||||
|
||||
nfsi->read_cache_jiffies = fattr->time_start;
|
||||
nfsi->attr_gencount = fattr->gencount;
|
||||
|
|
@ -561,6 +562,12 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
|
|||
} else if (fattr_supported & NFS_ATTR_FATTR_SPACE_USED &&
|
||||
fattr->size != 0)
|
||||
nfs_set_cache_invalid(inode, NFS_INO_INVALID_BLOCKS);
|
||||
if (fattr->valid & NFS_ATTR_FATTR_UNCACHEABLE_FILE_DATA)
|
||||
nfsi->uncacheable_file_data =
|
||||
fattr->aux_flags & NFS_AUX_UNCACHEABLE_FILE_DATA;
|
||||
else if (S_ISREG(inode->i_mode) &&
|
||||
(fattr_supported & NFS_ATTR_FATTR_UNCACHEABLE_FILE_DATA))
|
||||
nfs_set_cache_invalid(inode, NFS_INO_INVALID_UNCACHEABLE_FILE_DATA);
|
||||
|
||||
nfs_setsecurity(inode, fattr);
|
||||
|
||||
|
|
@ -1531,9 +1538,7 @@ int nfs_clear_invalid_mapping(struct address_space *mapping)
|
|||
ret = nfs_invalidate_mapping(inode, mapping);
|
||||
trace_nfs_invalidate_mapping_exit(inode, ret);
|
||||
|
||||
clear_bit_unlock(NFS_INO_INVALIDATING, bitlock);
|
||||
smp_mb__after_atomic();
|
||||
wake_up_bit(bitlock, NFS_INO_INVALIDATING);
|
||||
clear_and_wake_up_bit(NFS_INO_INVALIDATING, bitlock);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1975,7 +1980,8 @@ static int nfs_inode_finish_partial_attr_update(const struct nfs_fattr *fattr,
|
|||
NFS_INO_INVALID_ATIME | NFS_INO_INVALID_CTIME |
|
||||
NFS_INO_INVALID_MTIME | NFS_INO_INVALID_SIZE |
|
||||
NFS_INO_INVALID_BLOCKS | NFS_INO_INVALID_OTHER |
|
||||
NFS_INO_INVALID_NLINK | NFS_INO_INVALID_BTIME;
|
||||
NFS_INO_INVALID_NLINK | NFS_INO_INVALID_BTIME |
|
||||
NFS_INO_INVALID_UNCACHEABLE_FILE_DATA;
|
||||
unsigned long cache_validity = NFS_I(inode)->cache_validity;
|
||||
enum nfs4_change_attr_type ctype = NFS_SERVER(inode)->change_attr_type;
|
||||
|
||||
|
|
@ -2297,7 +2303,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
|
|||
nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR
|
||||
| NFS_INO_INVALID_ATIME
|
||||
| NFS_INO_REVAL_FORCED
|
||||
| NFS_INO_INVALID_BLOCKS);
|
||||
| NFS_INO_INVALID_BLOCKS
|
||||
| NFS_INO_INVALID_UNCACHEABLE_FILE_DATA);
|
||||
|
||||
/* Do atomic weak cache consistency updates */
|
||||
nfs_wcc_update_inode(inode, fattr);
|
||||
|
|
@ -2337,7 +2344,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
|
|||
| NFS_INO_INVALID_NLINK
|
||||
| NFS_INO_INVALID_MODE
|
||||
| NFS_INO_INVALID_OTHER
|
||||
| NFS_INO_INVALID_BTIME;
|
||||
| NFS_INO_INVALID_BTIME
|
||||
| NFS_INO_INVALID_UNCACHEABLE_FILE_DATA;
|
||||
if (S_ISDIR(inode->i_mode))
|
||||
nfs_force_lookup_revalidate(inode);
|
||||
attr_changed = true;
|
||||
|
|
@ -2461,6 +2469,14 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
|
|||
nfsi->cache_validity |=
|
||||
save_cache_validity & NFS_INO_INVALID_BLOCKS;
|
||||
|
||||
if (fattr->valid & NFS_ATTR_FATTR_UNCACHEABLE_FILE_DATA)
|
||||
nfsi->uncacheable_file_data =
|
||||
fattr->aux_flags & NFS_AUX_UNCACHEABLE_FILE_DATA;
|
||||
else if (S_ISREG(inode->i_mode) &&
|
||||
(fattr_supported & NFS_ATTR_FATTR_UNCACHEABLE_FILE_DATA))
|
||||
nfsi->cache_validity |=
|
||||
save_cache_validity & NFS_INO_INVALID_UNCACHEABLE_FILE_DATA;
|
||||
|
||||
/* Update attrtimeo value if we're out of the unstable period */
|
||||
if (attr_changed) {
|
||||
nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE);
|
||||
|
|
|
|||
|
|
@ -225,6 +225,7 @@ void nfs_server_copy_userdata(struct nfs_server *, struct nfs_server *);
|
|||
|
||||
extern void nfs_put_client(struct nfs_client *);
|
||||
extern void nfs_free_client(struct nfs_client *);
|
||||
void nfs_cb_idr_remove(struct nfs_client *clp);
|
||||
extern struct nfs_client *nfs4_find_client_ident(struct net *, int);
|
||||
extern struct nfs_client *
|
||||
nfs4_find_client_sessionid(struct net *, const struct sockaddr *,
|
||||
|
|
@ -250,7 +251,8 @@ extern struct nfs_client *nfs4_set_ds_client(struct nfs_server *mds_srv,
|
|||
int ds_addrlen, int ds_proto,
|
||||
unsigned int ds_timeo,
|
||||
unsigned int ds_retrans,
|
||||
u32 minor_version);
|
||||
u32 minor_version,
|
||||
bool tightly_coupled);
|
||||
extern struct rpc_clnt *nfs4_find_or_create_ds_client(struct nfs_client *,
|
||||
struct inode *);
|
||||
extern void nfs4_session_limit_rwsize(struct nfs_server *server);
|
||||
|
|
@ -479,7 +481,7 @@ extern int nfs_local_doio(struct nfs_client *,
|
|||
const struct rpc_call_ops *);
|
||||
extern int nfs_local_commit(struct nfsd_file *,
|
||||
struct nfs_commit_data *,
|
||||
const struct rpc_call_ops *, int);
|
||||
const struct rpc_call_ops *);
|
||||
extern bool nfs_server_is_local(const struct nfs_client *clp);
|
||||
|
||||
#else /* CONFIG_NFS_LOCALIO */
|
||||
|
|
@ -501,7 +503,7 @@ static inline int nfs_local_doio(struct nfs_client *clp,
|
|||
}
|
||||
static inline int nfs_local_commit(struct nfsd_file *localio,
|
||||
struct nfs_commit_data *data,
|
||||
const struct rpc_call_ops *call_ops, int how)
|
||||
const struct rpc_call_ops *call_ops)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,7 +52,6 @@ struct nfs_local_fsync_ctx {
|
|||
struct nfsd_file *localio;
|
||||
struct nfs_commit_data *data;
|
||||
struct work_struct work;
|
||||
struct completion *done;
|
||||
};
|
||||
|
||||
static bool localio_enabled __read_mostly = true;
|
||||
|
|
@ -699,6 +698,29 @@ static void nfs_local_call_read(struct work_struct *work)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Decide whether LOCALIO must defer submission to the dedicated
|
||||
* !WQ_MEM_RECLAIM nfslocaliod_workqueue rather than issue the IO inline.
|
||||
*
|
||||
* LOCALIO issues IO directly into a stacked local filesystem (e.g. XFS),
|
||||
* which may in turn flush its own !WQ_MEM_RECLAIM workqueue. Doing so from a
|
||||
* memory-reclaim context -- either a WQ_MEM_RECLAIM worker (most importantly
|
||||
* writeback's wb_workfn running on bdi_wq) or an explicit reclaim task
|
||||
* (PF_MEMALLOC) -- would trip check_flush_dependency() and risks a
|
||||
* forward-progress deadlock; see commit b9f5dd57f4a5 ("nfs/localio: use
|
||||
* dedicated workqueues for filesystem read and write"). In that case defer
|
||||
* to nfslocaliod_workqueue.
|
||||
*
|
||||
* Otherwise (ordinary application/task context, e.g. O_DIRECT or fsync-driven
|
||||
* submission) issue the IO inline: this preserves the NFS client's inherent
|
||||
* application-context parallelism and avoids the per-IO workqueue hop.
|
||||
*/
|
||||
static inline bool nfs_local_defer_io(void)
|
||||
{
|
||||
return (current->flags & PF_MEMALLOC) ||
|
||||
current_is_workqueue_mem_reclaim();
|
||||
}
|
||||
|
||||
static void nfs_local_do_read(struct nfs_local_kiocb *iocb,
|
||||
const struct rpc_call_ops *call_ops)
|
||||
{
|
||||
|
|
@ -711,7 +733,10 @@ static void nfs_local_do_read(struct nfs_local_kiocb *iocb,
|
|||
hdr->res.eof = false;
|
||||
|
||||
INIT_WORK(&iocb->work, nfs_local_call_read);
|
||||
queue_work(nfslocaliod_workqueue, &iocb->work);
|
||||
if (nfs_local_defer_io())
|
||||
queue_work(nfslocaliod_workqueue, &iocb->work);
|
||||
else
|
||||
nfs_local_call_read(&iocb->work);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -929,7 +954,10 @@ static void nfs_local_do_write(struct nfs_local_kiocb *iocb,
|
|||
nfs_set_local_verifier(hdr->inode, hdr->res.verf, hdr->args.stable);
|
||||
|
||||
INIT_WORK(&iocb->work, nfs_local_call_write);
|
||||
queue_work(nfslocaliod_workqueue, &iocb->work);
|
||||
if (nfs_local_defer_io())
|
||||
queue_work(nfslocaliod_workqueue, &iocb->work);
|
||||
else
|
||||
nfs_local_call_write(&iocb->work);
|
||||
}
|
||||
|
||||
static struct nfs_local_kiocb *
|
||||
|
|
@ -1071,8 +1099,6 @@ nfs_local_fsync_work(struct work_struct *work)
|
|||
status = nfs_local_run_commit(nfs_to->nfsd_file_file(ctx->localio),
|
||||
ctx->data);
|
||||
nfs_local_commit_done(ctx->data, status);
|
||||
if (ctx->done != NULL)
|
||||
complete(ctx->done);
|
||||
nfs_local_fsync_ctx_free(ctx);
|
||||
|
||||
current->flags = old_flags;
|
||||
|
|
@ -1088,14 +1114,13 @@ nfs_local_fsync_ctx_alloc(struct nfs_commit_data *data,
|
|||
ctx->localio = localio;
|
||||
ctx->data = data;
|
||||
INIT_WORK(&ctx->work, nfs_local_fsync_work);
|
||||
ctx->done = NULL;
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
int nfs_local_commit(struct nfsd_file *localio,
|
||||
struct nfs_commit_data *data,
|
||||
const struct rpc_call_ops *call_ops, int how)
|
||||
const struct rpc_call_ops *call_ops)
|
||||
{
|
||||
struct nfs_local_fsync_ctx *ctx;
|
||||
|
||||
|
|
@ -1108,13 +1133,18 @@ int nfs_local_commit(struct nfsd_file *localio,
|
|||
|
||||
nfs_local_init_commit(data, call_ops);
|
||||
|
||||
if (how & FLUSH_SYNC) {
|
||||
DECLARE_COMPLETION_ONSTACK(done);
|
||||
ctx->done = &done;
|
||||
queue_work(nfslocaliod_workqueue, &ctx->work);
|
||||
wait_for_completion(&done);
|
||||
} else
|
||||
/*
|
||||
* Run the commit (fsync) inline when not in a memory-reclaim context,
|
||||
* rather than bouncing through nfslocaliod_workqueue; see
|
||||
* nfs_local_defer_io(). Completion (nfs_commit_release_pages ->
|
||||
* nfs_commit_end) then runs synchronously, which higher layers cope
|
||||
* with: __nfs_commit_inode() dispatches async and waits via
|
||||
* wait_on_commit().
|
||||
*/
|
||||
if (nfs_local_defer_io())
|
||||
queue_work(nfslocaliod_workqueue, &ctx->work);
|
||||
else
|
||||
nfs_local_fsync_work(&ctx->work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -261,6 +261,7 @@ struct nfs_client *nfs4_alloc_client(const struct nfs_client_initdata *cl_init)
|
|||
return clp;
|
||||
|
||||
error:
|
||||
nfs_cb_idr_remove(clp);
|
||||
nfs_free_client(clp);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
|
@ -791,7 +792,7 @@ static int nfs4_set_client(struct nfs_server *server,
|
|||
struct nfs_client *nfs4_set_ds_client(struct nfs_server *mds_srv,
|
||||
const struct sockaddr_storage *ds_addr, int ds_addrlen,
|
||||
int ds_proto, unsigned int ds_timeo, unsigned int ds_retrans,
|
||||
u32 minor_version)
|
||||
u32 minor_version, bool tightly_coupled)
|
||||
{
|
||||
struct rpc_timeout ds_timeout;
|
||||
struct nfs_client *mds_clp = mds_srv->nfs_client;
|
||||
|
|
@ -838,7 +839,8 @@ struct nfs_client *nfs4_set_ds_client(struct nfs_server *mds_srv,
|
|||
if (test_bit(NFS_CS_NETUNREACH_FATAL, &mds_clp->cl_flags))
|
||||
__set_bit(NFS_CS_NETUNREACH_FATAL, &cl_init.init_flags);
|
||||
|
||||
__set_bit(NFS_CS_PNFS, &cl_init.init_flags);
|
||||
if (tightly_coupled)
|
||||
__set_bit(NFS_CS_PNFS, &cl_init.init_flags);
|
||||
cl_init.max_connect = NFS_MAX_TRANSPORTS;
|
||||
/*
|
||||
* Set an authflavor equual to the MDS value. Use the MDS nfs_client
|
||||
|
|
@ -915,20 +917,22 @@ static int nfs4_server_common_setup(struct nfs_server *server,
|
|||
return error;
|
||||
|
||||
/* data servers support only a subset of NFSv4.1 */
|
||||
if (is_ds_only_client(server->nfs_client))
|
||||
return -EPROTONOSUPPORT;
|
||||
if (is_ds_only_client(server->nfs_client)) {
|
||||
error = -EPROTONOSUPPORT;
|
||||
goto out_free_delegation_hash;
|
||||
}
|
||||
|
||||
/* We must ensure the session is initialised first */
|
||||
error = nfs4_init_session(server->nfs_client);
|
||||
if (error < 0)
|
||||
return error;
|
||||
goto out_free_delegation_hash;
|
||||
|
||||
nfs_server_set_init_caps(server);
|
||||
|
||||
/* Probe the root fh to retrieve its FSID and filehandle */
|
||||
error = nfs4_get_rootfh(server, mntfh, auth_probe);
|
||||
if (error < 0)
|
||||
return error;
|
||||
goto out_free_delegation_hash;
|
||||
|
||||
dprintk("Server FSID: %llx:%llx\n",
|
||||
(unsigned long long) server->fsid.major,
|
||||
|
|
@ -937,7 +941,7 @@ static int nfs4_server_common_setup(struct nfs_server *server,
|
|||
|
||||
error = nfs_probe_server(server, mntfh);
|
||||
if (error < 0)
|
||||
return error;
|
||||
goto out_free_delegation_hash;
|
||||
|
||||
nfs4_session_limit_rwsize(server);
|
||||
nfs4_session_limit_xasize(server);
|
||||
|
|
@ -949,6 +953,11 @@ static int nfs4_server_common_setup(struct nfs_server *server,
|
|||
server->mount_time = jiffies;
|
||||
server->destroy = nfs4_destroy_server;
|
||||
return 0;
|
||||
|
||||
out_free_delegation_hash:
|
||||
kfree(server->delegation_hash_table);
|
||||
server->delegation_hash_table = NULL;
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -91,6 +91,8 @@ nfs4_file_open(struct inode *inode, struct file *filp)
|
|||
nfs_fscache_open_file(inode, filp);
|
||||
err = 0;
|
||||
filp->f_mode |= FMODE_CAN_ODIRECT;
|
||||
if (test_bit(NFS_CONTEXT_O_DIRECT, &ctx->flags))
|
||||
filp->f_flags |= O_DIRECT;
|
||||
|
||||
out_put_ctx:
|
||||
put_nfs_open_context(ctx);
|
||||
|
|
|
|||
|
|
@ -225,8 +225,9 @@ const u32 nfs4_fattr_bitmap[3] = {
|
|||
| FATTR4_WORD1_TIME_METADATA
|
||||
| FATTR4_WORD1_TIME_MODIFY
|
||||
| FATTR4_WORD1_MOUNTED_ON_FILEID,
|
||||
FATTR4_WORD2_UNCACHEABLE_FILE_DATA
|
||||
#ifdef CONFIG_NFS_V4_SECURITY_LABEL
|
||||
FATTR4_WORD2_SECURITY_LABEL
|
||||
| FATTR4_WORD2_SECURITY_LABEL
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
@ -250,6 +251,7 @@ static const u32 nfs4_pnfs_open_bitmap[3] = {
|
|||
#ifdef CONFIG_NFS_V4_SECURITY_LABEL
|
||||
| FATTR4_WORD2_SECURITY_LABEL
|
||||
#endif
|
||||
| FATTR4_WORD2_UNCACHEABLE_FILE_DATA
|
||||
};
|
||||
|
||||
static const u32 nfs4_open_noattr_bitmap[3] = {
|
||||
|
|
@ -306,6 +308,15 @@ static void nfs4_bitmap_copy_adjust(__u32 *dst, const __u32 *src,
|
|||
unsigned long cache_validity;
|
||||
|
||||
memcpy(dst, src, NFS4_BITMASK_SZ*sizeof(*dst));
|
||||
/*
|
||||
* The uncacheable_file_data attribute applies only to regular files
|
||||
* (NF4REG); a server must reject a query of it on any other object
|
||||
* type with NFS4ERR_INVAL. Never request it unless the target is
|
||||
* known to be a regular file (callers with an unknown object type,
|
||||
* e.g. LOOKUP, pass a NULL inode).
|
||||
*/
|
||||
if (!inode || !S_ISREG(inode->i_mode))
|
||||
dst[2] &= ~FATTR4_WORD2_UNCACHEABLE_FILE_DATA;
|
||||
if (!inode || !nfs_have_read_or_write_delegation(inode))
|
||||
return;
|
||||
|
||||
|
|
@ -327,6 +338,9 @@ static void nfs4_bitmap_copy_adjust(__u32 *dst, const __u32 *src,
|
|||
if (!(cache_validity & NFS_INO_INVALID_BTIME))
|
||||
dst[1] &= ~FATTR4_WORD1_TIME_CREATE;
|
||||
|
||||
if (!(cache_validity & NFS_INO_INVALID_UNCACHEABLE_FILE_DATA))
|
||||
dst[2] &= ~FATTR4_WORD2_UNCACHEABLE_FILE_DATA;
|
||||
|
||||
if (nfs_have_delegated_mtime(inode)) {
|
||||
if (!(cache_validity & NFS_INO_INVALID_ATIME))
|
||||
dst[1] &= ~(FATTR4_WORD1_TIME_ACCESS|FATTR4_WORD1_TIME_ACCESS_SET);
|
||||
|
|
@ -3839,6 +3853,16 @@ nfs4_atomic_open(struct inode *dir, struct nfs_open_context *ctx,
|
|||
|
||||
if (IS_ERR(state))
|
||||
return ERR_CAST(state);
|
||||
|
||||
/*
|
||||
* Use O_DIRECT if file was marked as Uncacheable, see:
|
||||
* https://datatracker.ietf.org/doc/draft-ietf-nfsv4-uncacheable-files/
|
||||
*/
|
||||
if (!(open_flags & O_DIRECT) && NFS_I(state->inode)->uncacheable_file_data) {
|
||||
if (!(open_flags & O_APPEND))
|
||||
set_bit(NFS_CONTEXT_O_DIRECT, &ctx->flags);
|
||||
}
|
||||
|
||||
return state->inode;
|
||||
}
|
||||
|
||||
|
|
@ -3857,7 +3881,7 @@ static void nfs4_close_context(struct nfs_open_context *ctx, int is_sync)
|
|||
|
||||
#define FATTR4_WORD1_NFS40_MASK (2*FATTR4_WORD1_MOUNTED_ON_FILEID - 1UL)
|
||||
#define FATTR4_WORD2_NFS41_MASK (2*FATTR4_WORD2_SUPPATTR_EXCLCREAT - 1UL)
|
||||
#define FATTR4_WORD2_NFS42_MASK (2*FATTR4_WORD2_OPEN_ARGUMENTS - 1UL)
|
||||
#define FATTR4_WORD2_NFS42_MASK (2*FATTR4_WORD2_UNCACHEABLE_FILE_DATA - 1UL)
|
||||
|
||||
#define FATTR4_WORD2_NFS42_TIME_DELEG_MASK \
|
||||
(FATTR4_WORD2_TIME_DELEG_MODIFY|FATTR4_WORD2_TIME_DELEG_ACCESS)
|
||||
|
|
@ -3981,6 +4005,8 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
|
|||
memcpy(server->attr_bitmask_nl, res.attr_bitmask,
|
||||
sizeof(server->attr_bitmask));
|
||||
server->attr_bitmask_nl[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
|
||||
if (!(res.attr_bitmask[2] & FATTR4_WORD2_UNCACHEABLE_FILE_DATA))
|
||||
server->fattr_valid &= ~NFS_ATTR_FATTR_UNCACHEABLE_FILE_DATA;
|
||||
|
||||
if (res.open_caps.oa_share_access_want[0] &
|
||||
NFS4_SHARE_WANT_OPEN_XOR_DELEGATION)
|
||||
|
|
@ -4591,6 +4617,7 @@ static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir,
|
|||
.rpc_resp = &res,
|
||||
};
|
||||
unsigned short task_flags = 0;
|
||||
__u32 bitmask[NFS4_BITMASK_SZ];
|
||||
|
||||
if (nfs_server_capable(dir, NFS_CAP_MOVEABLE))
|
||||
task_flags = RPC_TASK_MOVEABLE;
|
||||
|
|
@ -4599,7 +4626,13 @@ static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir,
|
|||
if (nfs_lookup_is_soft_revalidate(dentry))
|
||||
task_flags |= RPC_TASK_TIMEOUT;
|
||||
|
||||
args.bitmask = nfs4_bitmask(server, fattr->label);
|
||||
/*
|
||||
* The looked-up object's type is unknown here, so gate out the
|
||||
* regular-file-only uncacheable_file_data attribute (NULL inode).
|
||||
*/
|
||||
nfs4_bitmap_copy_adjust(bitmask, nfs4_bitmask(server, fattr->label),
|
||||
NULL, 0);
|
||||
args.bitmask = bitmask;
|
||||
|
||||
nfs_fattr_init(fattr);
|
||||
|
||||
|
|
@ -4713,13 +4746,20 @@ static int _nfs4_proc_lookupp(struct inode *inode,
|
|||
.rpc_resp = &res,
|
||||
};
|
||||
unsigned short task_flags = 0;
|
||||
__u32 bitmask[NFS4_BITMASK_SZ];
|
||||
|
||||
if (server->flags & NFS_MOUNT_SOFTREVAL)
|
||||
task_flags |= RPC_TASK_TIMEOUT;
|
||||
if (server->caps & NFS_CAP_MOVEABLE)
|
||||
task_flags |= RPC_TASK_MOVEABLE;
|
||||
|
||||
args.bitmask = nfs4_bitmask(server, fattr->label);
|
||||
/*
|
||||
* The looked-up object's type is unknown here, so gate out the
|
||||
* regular-file-only uncacheable_file_data attribute (NULL inode).
|
||||
*/
|
||||
nfs4_bitmap_copy_adjust(bitmask, nfs4_bitmask(server, fattr->label),
|
||||
NULL, 0);
|
||||
args.bitmask = bitmask;
|
||||
|
||||
nfs_fattr_init(fattr);
|
||||
nfs4_init_sequence(server->nfs_client, &args.seq_args, &res.seq_res, 0, 0);
|
||||
|
|
@ -5134,6 +5174,7 @@ struct nfs4_createdata {
|
|||
struct nfs4_create_res res;
|
||||
struct nfs_fh fh;
|
||||
struct nfs_fattr fattr;
|
||||
u32 bitmask[NFS4_BITMASK_SZ];
|
||||
};
|
||||
|
||||
static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir,
|
||||
|
|
@ -5157,7 +5198,14 @@ static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir,
|
|||
data->arg.name = name;
|
||||
data->arg.attrs = sattr;
|
||||
data->arg.ftype = ftype;
|
||||
data->arg.bitmask = nfs4_bitmask(server, data->fattr.label);
|
||||
/*
|
||||
* CREATE only makes non-regular objects, so gate out the
|
||||
* regular-file-only uncacheable_file_data attribute (NULL inode).
|
||||
*/
|
||||
nfs4_bitmap_copy_adjust(data->bitmask,
|
||||
nfs4_bitmask(server, data->fattr.label),
|
||||
NULL, 0);
|
||||
data->arg.bitmask = data->bitmask;
|
||||
data->arg.umask = current_umask();
|
||||
data->res.server = server;
|
||||
data->res.fh = &data->fh;
|
||||
|
|
@ -5809,6 +5857,13 @@ void nfs4_bitmask_set(__u32 bitmask[], const __u32 src[],
|
|||
bitmask[1] |= FATTR4_WORD1_SPACE_USED;
|
||||
if (cache_validity & NFS_INO_INVALID_BTIME)
|
||||
bitmask[1] |= FATTR4_WORD1_TIME_CREATE;
|
||||
/*
|
||||
* uncacheable_file_data (attr 87) applies only to regular files; a
|
||||
* directory can reach here via DELEGRETURN of a directory delegation.
|
||||
*/
|
||||
if ((cache_validity & NFS_INO_INVALID_UNCACHEABLE_FILE_DATA) &&
|
||||
S_ISREG(inode->i_mode))
|
||||
bitmask[2] |= FATTR4_WORD2_UNCACHEABLE_FILE_DATA;
|
||||
|
||||
if (cache_validity & NFS_INO_INVALID_SIZE)
|
||||
bitmask[0] |= FATTR4_WORD0_SIZE;
|
||||
|
|
@ -7762,6 +7817,7 @@ static int nfs4_add_lease(struct file *file, int arg, struct file_lease **lease,
|
|||
{
|
||||
struct inode *inode = file_inode(file);
|
||||
fmode_t type = arg == F_RDLCK ? FMODE_READ : FMODE_WRITE;
|
||||
fl_owner_t owner = (*lease)->c.flc_owner;
|
||||
int ret;
|
||||
|
||||
/* No delegation, no lease */
|
||||
|
|
@ -7771,7 +7827,8 @@ static int nfs4_add_lease(struct file *file, int arg, struct file_lease **lease,
|
|||
if (ret || nfs4_have_delegation(inode, type, 0))
|
||||
return ret;
|
||||
/* We raced with a delegation return */
|
||||
nfs4_delete_lease(file, priv);
|
||||
dprintk("%s: raced with a delegation return\n", __func__);
|
||||
nfs4_delete_lease(file, &owner);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -626,27 +626,34 @@ int nfs4_init_session(struct nfs_client *clp)
|
|||
return nfs41_check_session_ready(clp);
|
||||
}
|
||||
|
||||
int nfs4_init_ds_session(struct nfs_client *clp, unsigned long lease_time)
|
||||
int nfs4_init_ds_session(struct nfs_client *clp, unsigned long lease_time,
|
||||
bool tightly_coupled)
|
||||
{
|
||||
struct nfs4_session *session = clp->cl_session;
|
||||
int ret;
|
||||
|
||||
spin_lock(&clp->cl_lock);
|
||||
if (test_and_clear_bit(NFS4_SESSION_INITING, &session->session_state)) {
|
||||
/*
|
||||
* Do not set NFS_CS_CHECK_LEASE_TIME instead set the
|
||||
* DS lease to be equal to the MDS lease.
|
||||
*/
|
||||
/*
|
||||
* Do not set NFS_CS_CHECK_LEASE_TIME instead set the
|
||||
* DS lease to be equal to the MDS lease.
|
||||
*
|
||||
* A v4.0 DS has no session, so seed the lease every time.
|
||||
*/
|
||||
if (!session ||
|
||||
test_and_clear_bit(NFS4_SESSION_INITING, &session->session_state)) {
|
||||
clp->cl_lease_time = lease_time;
|
||||
clp->cl_last_renewal = jiffies;
|
||||
}
|
||||
spin_unlock(&clp->cl_lock);
|
||||
|
||||
if (!session)
|
||||
return 0;
|
||||
|
||||
ret = nfs41_check_session_ready(clp);
|
||||
if (ret)
|
||||
return ret;
|
||||
/* Test for the DS role */
|
||||
if (!is_ds_client(clp))
|
||||
if (tightly_coupled && !is_ds_client(clp))
|
||||
return -ENODEV;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,7 +122,8 @@ extern int nfs4_setup_session_slot_tables(struct nfs4_session *ses);
|
|||
extern struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp);
|
||||
extern void nfs4_destroy_session(struct nfs4_session *session);
|
||||
extern int nfs4_init_session(struct nfs_client *clp);
|
||||
extern int nfs4_init_ds_session(struct nfs_client *, unsigned long);
|
||||
extern int nfs4_init_ds_session(struct nfs_client *clp, unsigned long lease_time,
|
||||
bool tightly_coupled);
|
||||
|
||||
/*
|
||||
* Determine if sessions are in use.
|
||||
|
|
|
|||
|
|
@ -351,6 +351,26 @@ const struct cred *nfs4_get_clid_cred(struct nfs_client *clp)
|
|||
return cred;
|
||||
}
|
||||
|
||||
static bool
|
||||
nfs4_get_state_owner_active_locked(struct nfs4_state_owner *sp)
|
||||
{
|
||||
struct nfs_server *server = sp->so_server;
|
||||
|
||||
/*
|
||||
* A counted state owner may dereference so_server until the final
|
||||
* nfs4_put_state_owner(). Pin the superblock when reviving an idle
|
||||
* owner so umount cannot free the server underneath it.
|
||||
*/
|
||||
if (atomic_read(&sp->so_count) == 0) {
|
||||
if (!nfs_sb_active(server->super))
|
||||
return false;
|
||||
if (!list_empty(&sp->so_lru))
|
||||
list_del_init(&sp->so_lru);
|
||||
}
|
||||
atomic_inc(&sp->so_count);
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct nfs4_state_owner *
|
||||
nfs4_find_state_owner_locked(struct nfs_server *server, const struct cred *cred)
|
||||
{
|
||||
|
|
@ -369,9 +389,8 @@ nfs4_find_state_owner_locked(struct nfs_server *server, const struct cred *cred)
|
|||
else if (cmp > 0)
|
||||
p = &parent->rb_right;
|
||||
else {
|
||||
if (!list_empty(&sp->so_lru))
|
||||
list_del_init(&sp->so_lru);
|
||||
atomic_inc(&sp->so_count);
|
||||
if (!nfs4_get_state_owner_active_locked(sp))
|
||||
return NULL;
|
||||
return sp;
|
||||
}
|
||||
}
|
||||
|
|
@ -397,9 +416,8 @@ nfs4_insert_state_owner_locked(struct nfs4_state_owner *new)
|
|||
else if (cmp > 0)
|
||||
p = &parent->rb_right;
|
||||
else {
|
||||
if (!list_empty(&sp->so_lru))
|
||||
list_del_init(&sp->so_lru);
|
||||
atomic_inc(&sp->so_count);
|
||||
if (!nfs4_get_state_owner_active_locked(sp))
|
||||
return NULL;
|
||||
return sp;
|
||||
}
|
||||
}
|
||||
|
|
@ -449,6 +467,10 @@ nfs4_alloc_state_owner(struct nfs_server *server,
|
|||
sp = kzalloc_obj(*sp, gfp_flags);
|
||||
if (!sp)
|
||||
return NULL;
|
||||
if (!nfs_sb_active(server->super)) {
|
||||
kfree(sp);
|
||||
return NULL;
|
||||
}
|
||||
sp->so_seqid.owner_id = atomic64_inc_return(&server->owner_ctr);
|
||||
sp->so_server = server;
|
||||
sp->so_cred = get_cred(cred);
|
||||
|
|
@ -534,8 +556,10 @@ struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server,
|
|||
spin_lock(&clp->cl_lock);
|
||||
sp = nfs4_insert_state_owner_locked(new);
|
||||
spin_unlock(&clp->cl_lock);
|
||||
if (sp != new)
|
||||
if (sp != new) {
|
||||
nfs4_free_state_owner(new);
|
||||
nfs_sb_deactive(server->super);
|
||||
}
|
||||
out:
|
||||
nfs4_gc_state_owners(server);
|
||||
return sp;
|
||||
|
|
@ -557,6 +581,7 @@ void nfs4_put_state_owner(struct nfs4_state_owner *sp)
|
|||
{
|
||||
struct nfs_server *server = sp->so_server;
|
||||
struct nfs_client *clp = server->nfs_client;
|
||||
struct super_block *sb = server->super;
|
||||
|
||||
if (!atomic_dec_and_lock(&sp->so_count, &clp->cl_lock))
|
||||
return;
|
||||
|
|
@ -564,6 +589,7 @@ void nfs4_put_state_owner(struct nfs4_state_owner *sp)
|
|||
sp->so_expires = jiffies;
|
||||
list_add_tail(&sp->so_lru, &server->state_owners_lru);
|
||||
spin_unlock(&clp->cl_lock);
|
||||
nfs_sb_deactive(sb);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -33,7 +33,8 @@
|
|||
{ NFS_ATTR_FATTR_CHANGE, "CHANGE" }, \
|
||||
{ NFS_ATTR_FATTR_OWNER_NAME, "OWNER_NAME" }, \
|
||||
{ NFS_ATTR_FATTR_GROUP_NAME, "GROUP_NAME" }, \
|
||||
{ NFS_ATTR_FATTR_BTIME, "BTIME" })
|
||||
{ NFS_ATTR_FATTR_BTIME, "BTIME" }, \
|
||||
{ NFS_ATTR_FATTR_UNCACHEABLE_FILE_DATA, "UNCACHEABLE_FILE_DATA" })
|
||||
|
||||
DECLARE_EVENT_CLASS(nfs4_clientid_event,
|
||||
TP_PROTO(
|
||||
|
|
@ -1515,7 +1516,60 @@ DECLARE_EVENT_CLASS(nfs4_inode_stateid_callback_event,
|
|||
), \
|
||||
TP_ARGS(clp, fhandle, inode, stateid, error))
|
||||
DEFINE_NFS4_INODE_STATEID_CALLBACK_EVENT(nfs4_cb_recall);
|
||||
DEFINE_NFS4_INODE_STATEID_CALLBACK_EVENT(nfs4_cb_layoutrecall_file);
|
||||
|
||||
TRACE_EVENT(nfs4_cb_layoutrecall_file,
|
||||
TP_PROTO(
|
||||
const struct nfs_client *clp,
|
||||
const struct nfs_fh *fhandle,
|
||||
const struct inode *inode,
|
||||
const nfs4_stateid *stateid,
|
||||
unsigned int changed,
|
||||
int error
|
||||
),
|
||||
|
||||
TP_ARGS(clp, fhandle, inode, stateid, changed, error),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field(unsigned long, error)
|
||||
__field(dev_t, dev)
|
||||
__field(u32, fhandle)
|
||||
__field(u64, fileid)
|
||||
__string(dstaddr, clp ? clp->cl_hostname : "unknown")
|
||||
__field(int, stateid_seq)
|
||||
__field(u32, stateid_hash)
|
||||
__field(unsigned int, changed)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->error = error < 0 ? -error : 0;
|
||||
__entry->fhandle = nfs_fhandle_hash(fhandle);
|
||||
if (!IS_ERR_OR_NULL(inode)) {
|
||||
__entry->fileid = inode->i_ino;
|
||||
__entry->dev = inode->i_sb->s_dev;
|
||||
} else {
|
||||
__entry->fileid = 0;
|
||||
__entry->dev = 0;
|
||||
}
|
||||
__assign_str(dstaddr);
|
||||
__entry->stateid_seq =
|
||||
be32_to_cpu(stateid->seqid);
|
||||
__entry->stateid_hash =
|
||||
nfs_stateid_hash(stateid);
|
||||
__entry->changed = changed;
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
"error=%ld (%s) fileid=%02x:%02x:%llu fhandle=0x%08x "
|
||||
"stateid=%d:0x%08x dstaddr=%s clora_changed=%u",
|
||||
-__entry->error,
|
||||
show_nfs4_status(__entry->error),
|
||||
MAJOR(__entry->dev), MINOR(__entry->dev),
|
||||
(unsigned long long)__entry->fileid,
|
||||
__entry->fhandle,
|
||||
__entry->stateid_seq, __entry->stateid_hash,
|
||||
__get_str(dstaddr), __entry->changed
|
||||
)
|
||||
);
|
||||
|
||||
#define show_stateid_type(type) \
|
||||
__print_symbolic(type, \
|
||||
|
|
|
|||
|
|
@ -120,7 +120,8 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req,
|
|||
3*nfstime4_maxsz + \
|
||||
nfs4_owner_maxsz + \
|
||||
nfs4_group_maxsz + nfs4_label_maxsz + \
|
||||
decode_mdsthreshold_maxsz))
|
||||
decode_mdsthreshold_maxsz + \
|
||||
1)) /* uncacheable_file_data */
|
||||
#define nfs4_fattr_maxsz (nfs4_fattr_bitmap_maxsz + \
|
||||
nfs4_fattr_value_maxsz)
|
||||
#define decode_getattr_maxsz (op_decode_hdr_maxsz + nfs4_fattr_maxsz)
|
||||
|
|
@ -4380,6 +4381,30 @@ static int decode_attr_open_arguments(struct xdr_stream *xdr, uint32_t *bitmap,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int decode_attr_uncacheable_file_data(struct xdr_stream *xdr, uint32_t *bitmap,
|
||||
uint32_t *res, uint64_t *flags)
|
||||
{
|
||||
int status = 0;
|
||||
__be32 *p;
|
||||
|
||||
if (unlikely(bitmap[2] & (FATTR4_WORD2_UNCACHEABLE_FILE_DATA - 1U)))
|
||||
return -EIO;
|
||||
if (likely(bitmap[2] & FATTR4_WORD2_UNCACHEABLE_FILE_DATA)) {
|
||||
p = xdr_inline_decode(xdr, 4);
|
||||
if (unlikely(!p))
|
||||
return -EIO;
|
||||
if (be32_to_cpup(p))
|
||||
*res |= NFS_AUX_UNCACHEABLE_FILE_DATA;
|
||||
else
|
||||
*res &= ~NFS_AUX_UNCACHEABLE_FILE_DATA;
|
||||
bitmap[2] &= ~FATTR4_WORD2_UNCACHEABLE_FILE_DATA;
|
||||
*flags |= NFS_ATTR_FATTR_UNCACHEABLE_FILE_DATA;
|
||||
}
|
||||
dprintk("%s: uncacheable_file_data: =%s\n", __func__,
|
||||
(*res & NFS_AUX_UNCACHEABLE_FILE_DATA) == 0 ? "false" : "true");
|
||||
return status;
|
||||
}
|
||||
|
||||
static int verify_attr_len(struct xdr_stream *xdr, unsigned int savep, uint32_t attrlen)
|
||||
{
|
||||
unsigned int attrwords = XDR_QUADLEN(attrlen);
|
||||
|
|
@ -4725,6 +4750,8 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
|
|||
uint32_t type;
|
||||
int32_t err;
|
||||
|
||||
fattr->aux_flags = 0;
|
||||
|
||||
status = decode_attr_type(xdr, bitmap, &type);
|
||||
if (status < 0)
|
||||
goto xdr_error;
|
||||
|
|
@ -4843,6 +4870,12 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
|
|||
goto xdr_error;
|
||||
fattr->valid |= status;
|
||||
|
||||
status = decode_attr_uncacheable_file_data(xdr, bitmap, &fattr->aux_flags,
|
||||
&fattr->valid);
|
||||
if (status < 0)
|
||||
goto xdr_error;
|
||||
|
||||
status = 0;
|
||||
xdr_error:
|
||||
dprintk("%s: xdr returned %d\n", __func__, -status);
|
||||
return status;
|
||||
|
|
|
|||
|
|
@ -33,7 +33,8 @@
|
|||
{ NFS_INO_INVALID_XATTR, "INVALID_XATTR" }, \
|
||||
{ NFS_INO_INVALID_NLINK, "INVALID_NLINK" }, \
|
||||
{ NFS_INO_INVALID_MODE, "INVALID_MODE" }, \
|
||||
{ NFS_INO_INVALID_BTIME, "INVALID_BTIME" })
|
||||
{ NFS_INO_INVALID_BTIME, "INVALID_BTIME" }, \
|
||||
{ NFS_INO_INVALID_UNCACHEABLE_FILE_DATA, "INVALID_UNCACHEABLE_FILE_DATA" })
|
||||
|
||||
#define nfs_show_nfsi_flags(v) \
|
||||
__print_flags(v, "|", \
|
||||
|
|
|
|||
|
|
@ -432,7 +432,8 @@ bool nfs4_layout_refresh_old_stateid(nfs4_stateid *dst,
|
|||
goto out;
|
||||
}
|
||||
/* Try to update the seqid to the most recent */
|
||||
err = pnfs_mark_matching_lsegs_return(lo, &head, &range, 0);
|
||||
err = pnfs_mark_matching_lsegs_return(lo, &head, &range, 0,
|
||||
true);
|
||||
if (err != -EBUSY) {
|
||||
dst->seqid = lo->plh_stateid.seqid;
|
||||
*dst_range = range;
|
||||
|
|
@ -486,7 +487,7 @@ static int pnfs_mark_layout_stateid_return(struct pnfs_layout_hdr *lo,
|
|||
.length = NFS4_MAX_UINT64,
|
||||
};
|
||||
|
||||
return pnfs_mark_matching_lsegs_return(lo, lseg_list, &range, seq);
|
||||
return pnfs_mark_matching_lsegs_return(lo, lseg_list, &range, seq, true);
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
@ -524,7 +525,7 @@ pnfs_layout_io_set_failed(struct pnfs_layout_hdr *lo, u32 iomode)
|
|||
|
||||
spin_lock(&inode->i_lock);
|
||||
pnfs_layout_set_fail_bit(lo, pnfs_iomode_to_fail_bit(iomode));
|
||||
pnfs_mark_matching_lsegs_return(lo, &head, &range, 0);
|
||||
pnfs_mark_matching_lsegs_return(lo, &head, &range, 0, true);
|
||||
spin_unlock(&inode->i_lock);
|
||||
pnfs_free_lseg_list(&head);
|
||||
dprintk("%s Setting layout IOMODE_%s fail bit\n", __func__,
|
||||
|
|
@ -1389,7 +1390,7 @@ pnfs_layout_need_return(struct pnfs_layout_hdr *lo)
|
|||
return false;
|
||||
return pnfs_mark_layout_stateid_return(lo, &lo->plh_return_segs,
|
||||
lo->plh_return_iomode,
|
||||
lo->plh_return_seq) != EBUSY;
|
||||
lo->plh_return_seq) != -EBUSY;
|
||||
}
|
||||
|
||||
static void pnfs_layoutreturn_before_put_layout_hdr(struct pnfs_layout_hdr *lo)
|
||||
|
|
@ -1461,7 +1462,7 @@ _pnfs_return_layout(struct inode *ino)
|
|||
}
|
||||
valid_layout = pnfs_layout_is_valid(lo);
|
||||
pnfs_clear_layoutcommit(ino, &tmp_list);
|
||||
pnfs_mark_matching_lsegs_return(lo, &tmp_list, &range, 0);
|
||||
pnfs_mark_matching_lsegs_return(lo, &tmp_list, &range, 0, true);
|
||||
|
||||
|
||||
/* Don't send a LAYOUTRETURN if list was initially empty */
|
||||
|
|
@ -2100,15 +2101,6 @@ static bool pnfs_is_first_layoutget(struct pnfs_layout_hdr *lo)
|
|||
return test_bit(NFS_LAYOUT_FIRST_LAYOUTGET, &lo->plh_flags);
|
||||
}
|
||||
|
||||
static void pnfs_clear_first_layoutget(struct pnfs_layout_hdr *lo)
|
||||
{
|
||||
unsigned long *bitlock = &lo->plh_flags;
|
||||
|
||||
clear_bit_unlock(NFS_LAYOUT_FIRST_LAYOUTGET, bitlock);
|
||||
smp_mb__after_atomic();
|
||||
wake_up_bit(bitlock, NFS_LAYOUT_FIRST_LAYOUTGET);
|
||||
}
|
||||
|
||||
static void _add_to_server_list(struct pnfs_layout_hdr *lo,
|
||||
struct nfs_server *server)
|
||||
{
|
||||
|
|
@ -2284,7 +2276,8 @@ pnfs_update_layout(struct inode *ino,
|
|||
iomode, lo, lseg,
|
||||
PNFS_UPDATE_LAYOUT_INVALID_OPEN);
|
||||
nfs4_schedule_stateid_recovery(server, ctx->state);
|
||||
pnfs_clear_first_layoutget(lo);
|
||||
clear_and_wake_up_bit(NFS_LAYOUT_FIRST_LAYOUTGET,
|
||||
&lo->plh_flags);
|
||||
pnfs_put_layout_hdr(lo);
|
||||
goto lookup_again;
|
||||
}
|
||||
|
|
@ -2353,7 +2346,8 @@ pnfs_update_layout(struct inode *ino,
|
|||
if (!exception.retry)
|
||||
goto out_put_layout_hdr;
|
||||
if (first)
|
||||
pnfs_clear_first_layoutget(lo);
|
||||
clear_and_wake_up_bit(NFS_LAYOUT_FIRST_LAYOUTGET,
|
||||
&lo->plh_flags);
|
||||
trace_pnfs_update_layout(ino, pos, count,
|
||||
iomode, lo, lseg, PNFS_UPDATE_LAYOUT_RETRY);
|
||||
pnfs_put_layout_hdr(lo);
|
||||
|
|
@ -2365,7 +2359,7 @@ pnfs_update_layout(struct inode *ino,
|
|||
|
||||
out_put_layout_hdr:
|
||||
if (first)
|
||||
pnfs_clear_first_layoutget(lo);
|
||||
clear_and_wake_up_bit(NFS_LAYOUT_FIRST_LAYOUTGET, &lo->plh_flags);
|
||||
trace_pnfs_update_layout(ino, pos, count, iomode, lo, lseg,
|
||||
PNFS_UPDATE_LAYOUT_EXIT);
|
||||
pnfs_put_layout_hdr(lo);
|
||||
|
|
@ -2457,7 +2451,7 @@ static void _lgopen_prepare_attached(struct nfs4_opendata *data,
|
|||
lgp = pnfs_alloc_init_layoutget_args(ino, ctx, ¤t_stateid, &rng,
|
||||
nfs_io_gfp_mask());
|
||||
if (!lgp) {
|
||||
pnfs_clear_first_layoutget(lo);
|
||||
clear_and_wake_up_bit(NFS_LAYOUT_FIRST_LAYOUTGET, &lo->plh_flags);
|
||||
nfs_layoutget_end(lo);
|
||||
pnfs_put_layout_hdr(lo);
|
||||
return;
|
||||
|
|
@ -2561,7 +2555,8 @@ void nfs4_lgopen_release(struct nfs4_layoutget *lgp)
|
|||
{
|
||||
if (lgp != NULL) {
|
||||
if (lgp->lo) {
|
||||
pnfs_clear_first_layoutget(lgp->lo);
|
||||
clear_and_wake_up_bit(NFS_LAYOUT_FIRST_LAYOUTGET,
|
||||
&lgp->lo->plh_flags);
|
||||
nfs_layoutget_end(lgp->lo);
|
||||
}
|
||||
pnfs_layoutget_free(lgp);
|
||||
|
|
@ -2621,7 +2616,7 @@ pnfs_layout_process(struct nfs4_layoutget *lgp)
|
|||
.iomode = IOMODE_ANY,
|
||||
.length = NFS4_MAX_UINT64,
|
||||
};
|
||||
pnfs_mark_matching_lsegs_return(lo, &free_me, &range, 0);
|
||||
pnfs_mark_matching_lsegs_return(lo, &free_me, &range, 0, true);
|
||||
goto out_forget;
|
||||
} else {
|
||||
/* We have a completely new layout */
|
||||
|
|
@ -2643,6 +2638,7 @@ pnfs_layout_process(struct nfs4_layoutget *lgp)
|
|||
spin_unlock(&ino->i_lock);
|
||||
lseg->pls_layout = lo;
|
||||
NFS_SERVER(ino)->pnfs_curr_ld->free_lseg(lseg);
|
||||
pnfs_free_lseg_list(&free_me);
|
||||
return ERR_PTR(-EAGAIN);
|
||||
}
|
||||
|
||||
|
|
@ -2652,6 +2648,7 @@ pnfs_layout_process(struct nfs4_layoutget *lgp)
|
|||
* @tmp_list: list header to be used with pnfs_free_lseg_list()
|
||||
* @return_range: describe layout segment ranges to be returned
|
||||
* @seq: stateid seqid to match
|
||||
* @cancel_io: signal io be cancelled
|
||||
*
|
||||
* This function is mainly intended for use by layoutrecall. It attempts
|
||||
* to free the layout segment immediately, or else to mark it for return
|
||||
|
|
@ -2666,7 +2663,7 @@ int
|
|||
pnfs_mark_matching_lsegs_return(struct pnfs_layout_hdr *lo,
|
||||
struct list_head *tmp_list,
|
||||
const struct pnfs_layout_range *return_range,
|
||||
u32 seq)
|
||||
u32 seq, bool cancel_io)
|
||||
{
|
||||
struct pnfs_layout_segment *lseg, *next;
|
||||
struct nfs_server *server = NFS_SERVER(lo->plh_inode);
|
||||
|
|
@ -2692,7 +2689,8 @@ pnfs_mark_matching_lsegs_return(struct pnfs_layout_hdr *lo,
|
|||
continue;
|
||||
remaining++;
|
||||
set_bit(NFS_LSEG_LAYOUTRETURN, &lseg->pls_flags);
|
||||
pnfs_lseg_cancel_io(server, lseg);
|
||||
if (cancel_io)
|
||||
pnfs_lseg_cancel_io(server, lseg);
|
||||
}
|
||||
|
||||
if (remaining) {
|
||||
|
|
@ -2727,7 +2725,8 @@ pnfs_mark_layout_for_return(struct inode *inode,
|
|||
* segments at hand when sending layoutreturn. See pnfs_put_lseg()
|
||||
* 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,
|
||||
true) != -EBUSY) {
|
||||
const struct cred *cred;
|
||||
nfs4_stateid stateid;
|
||||
enum pnfs_iomode iomode;
|
||||
|
|
@ -2842,7 +2841,7 @@ static int pnfs_layout_return_unused_byserver(struct nfs_server *server,
|
|||
pnfs_get_layout_hdr(lo);
|
||||
pnfs_set_plh_return_info(lo, range->iomode, 0);
|
||||
if (pnfs_mark_matching_lsegs_return(lo, &lo->plh_return_segs,
|
||||
range, 0) != 0 ||
|
||||
range, 0, true) != 0 ||
|
||||
!pnfs_prepare_layoutreturn(lo, &stateid, &cred, &iomode)) {
|
||||
spin_unlock(&inode->i_lock);
|
||||
rcu_read_unlock();
|
||||
|
|
@ -3273,15 +3272,6 @@ pnfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(pnfs_generic_pg_readpages);
|
||||
|
||||
static void pnfs_clear_layoutcommitting(struct inode *inode)
|
||||
{
|
||||
unsigned long *bitlock = &NFS_I(inode)->flags;
|
||||
|
||||
clear_bit_unlock(NFS_INO_LAYOUTCOMMITTING, bitlock);
|
||||
smp_mb__after_atomic();
|
||||
wake_up_bit(bitlock, NFS_INO_LAYOUTCOMMITTING);
|
||||
}
|
||||
|
||||
/*
|
||||
* There can be multiple RW segments.
|
||||
*/
|
||||
|
|
@ -3306,7 +3296,7 @@ static void pnfs_list_write_lseg_done(struct inode *inode, struct list_head *lis
|
|||
pnfs_put_lseg(lseg);
|
||||
}
|
||||
|
||||
pnfs_clear_layoutcommitting(inode);
|
||||
clear_and_wake_up_bit(NFS_INO_LAYOUTCOMMITTING, &NFS_I(inode)->flags);
|
||||
}
|
||||
|
||||
void pnfs_set_lo_fail(struct pnfs_layout_segment *lseg)
|
||||
|
|
@ -3446,7 +3436,7 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync)
|
|||
spin_unlock(&inode->i_lock);
|
||||
kfree(data);
|
||||
clear_layoutcommitting:
|
||||
pnfs_clear_layoutcommitting(inode);
|
||||
clear_and_wake_up_bit(NFS_INO_LAYOUTCOMMITTING, &NFS_I(inode)->flags);
|
||||
goto out;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pnfs_layoutcommit_inode);
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ struct nfs4_pnfs_ds {
|
|||
const struct net *ds_net;
|
||||
struct nfs_client *ds_clp;
|
||||
refcount_t ds_count;
|
||||
u32 ds_version; /* cache key, with ds_addrs */
|
||||
unsigned long ds_state;
|
||||
#define NFS4DS_CONNECTING 0 /* ds is establishing connection */
|
||||
};
|
||||
|
|
@ -300,7 +301,7 @@ int pnfs_mark_matching_lsegs_invalid(struct pnfs_layout_hdr *lo,
|
|||
int pnfs_mark_matching_lsegs_return(struct pnfs_layout_hdr *lo,
|
||||
struct list_head *tmp_list,
|
||||
const struct pnfs_layout_range *recall_range,
|
||||
u32 seq);
|
||||
u32 seq, bool cancel_io);
|
||||
int pnfs_mark_layout_stateid_invalid(struct pnfs_layout_hdr *lo,
|
||||
struct list_head *lseg_list);
|
||||
bool pnfs_roc(struct inode *ino, struct nfs4_layoutreturn_args *args,
|
||||
|
|
@ -417,11 +418,12 @@ 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(const struct net *net,
|
||||
struct list_head *dsaddrs,
|
||||
gfp_t gfp_flags);
|
||||
u32 version, 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,
|
||||
struct nfs4_deviceid_node *devid, unsigned int timeo,
|
||||
unsigned int retrans, u32 version, u32 minor_version);
|
||||
unsigned int retrans, u32 version, u32 minor_version,
|
||||
bool tightly_coupled);
|
||||
struct nfs4_pnfs_ds_addr *nfs4_decode_mp_ds_addr(struct net *net,
|
||||
struct xdr_stream *xdr,
|
||||
gfp_t gfp_flags);
|
||||
|
|
|
|||
|
|
@ -603,15 +603,17 @@ _same_data_server_addrs_locked(const struct list_head *dsaddrs1,
|
|||
}
|
||||
|
||||
/*
|
||||
* Lookup DS by addresses. nfs4_ds_cache_lock is held
|
||||
* Lookup DS by addresses and NFS version. nfs4_ds_cache_lock is held
|
||||
*/
|
||||
static struct nfs4_pnfs_ds *
|
||||
_data_server_lookup_locked(const struct nfs_net *nn, const struct list_head *dsaddrs)
|
||||
_data_server_lookup_locked(const struct nfs_net *nn,
|
||||
const struct list_head *dsaddrs, u32 version)
|
||||
{
|
||||
struct nfs4_pnfs_ds *ds;
|
||||
|
||||
list_for_each_entry(ds, &nn->nfs4_data_server_cache, ds_node)
|
||||
if (_same_data_server_addrs_locked(&ds->ds_addrs, dsaddrs))
|
||||
if (ds->ds_version == version &&
|
||||
_same_data_server_addrs_locked(&ds->ds_addrs, dsaddrs))
|
||||
return ds;
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -719,7 +721,8 @@ nfs4_pnfs_remotestr(struct list_head *dsaddrs, gfp_t gfp_flags)
|
|||
* uncached and return cached struct nfs4_pnfs_ds.
|
||||
*/
|
||||
struct nfs4_pnfs_ds *
|
||||
nfs4_pnfs_ds_add(const struct net *net, struct list_head *dsaddrs, gfp_t gfp_flags)
|
||||
nfs4_pnfs_ds_add(const struct net *net, struct list_head *dsaddrs, u32 version,
|
||||
gfp_t gfp_flags)
|
||||
{
|
||||
struct nfs_net *nn = net_generic(net, nfs_net_id);
|
||||
struct nfs4_pnfs_ds *tmp_ds, *ds = NULL;
|
||||
|
|
@ -738,7 +741,7 @@ nfs4_pnfs_ds_add(const struct net *net, struct list_head *dsaddrs, gfp_t gfp_fla
|
|||
remotestr = nfs4_pnfs_remotestr(dsaddrs, gfp_flags);
|
||||
|
||||
spin_lock(&nn->nfs4_data_server_lock);
|
||||
tmp_ds = _data_server_lookup_locked(nn, dsaddrs);
|
||||
tmp_ds = _data_server_lookup_locked(nn, dsaddrs, version);
|
||||
if (tmp_ds == NULL) {
|
||||
INIT_LIST_HEAD(&ds->ds_addrs);
|
||||
list_splice_init(dsaddrs, &ds->ds_addrs);
|
||||
|
|
@ -747,6 +750,7 @@ nfs4_pnfs_ds_add(const struct net *net, struct list_head *dsaddrs, gfp_t gfp_fla
|
|||
INIT_LIST_HEAD(&ds->ds_node);
|
||||
ds->ds_net = net;
|
||||
ds->ds_clp = NULL;
|
||||
ds->ds_version = version;
|
||||
list_add(&ds->ds_node, &nn->nfs4_data_server_cache);
|
||||
dprintk("%s add new data server %s\n", __func__,
|
||||
ds->ds_remotestr);
|
||||
|
|
@ -881,7 +885,8 @@ static int _nfs4_pnfs_v4_ds_connect(struct nfs_server *mds_srv,
|
|||
struct nfs4_pnfs_ds *ds,
|
||||
unsigned int timeo,
|
||||
unsigned int retrans,
|
||||
u32 minor_version)
|
||||
u32 minor_version,
|
||||
bool tightly_coupled)
|
||||
{
|
||||
struct nfs_client *clp = ERR_PTR(-EIO);
|
||||
struct nfs_client *mds_clp = mds_srv->nfs_client;
|
||||
|
|
@ -971,12 +976,14 @@ static int _nfs4_pnfs_v4_ds_connect(struct nfs_server *mds_srv,
|
|||
|
||||
clp = nfs4_set_ds_client(mds_srv, &da->da_addr,
|
||||
da->da_addrlen, ds_proto,
|
||||
timeo, retrans, minor_version);
|
||||
timeo, retrans, minor_version,
|
||||
tightly_coupled);
|
||||
if (IS_ERR(clp))
|
||||
continue;
|
||||
|
||||
status = nfs4_init_ds_session(clp,
|
||||
mds_srv->nfs_client->cl_lease_time);
|
||||
mds_srv->nfs_client->cl_lease_time,
|
||||
tightly_coupled);
|
||||
if (status) {
|
||||
nfs_put_client(clp);
|
||||
clp = ERR_PTR(-EIO);
|
||||
|
|
@ -1004,7 +1011,8 @@ static int _nfs4_pnfs_v4_ds_connect(struct nfs_server *mds_srv,
|
|||
*/
|
||||
int nfs4_pnfs_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds,
|
||||
struct nfs4_deviceid_node *devid, unsigned int timeo,
|
||||
unsigned int retrans, u32 version, u32 minor_version)
|
||||
unsigned int retrans, u32 version, u32 minor_version,
|
||||
bool tightly_coupled)
|
||||
{
|
||||
int err;
|
||||
|
||||
|
|
@ -1027,7 +1035,7 @@ int nfs4_pnfs_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds,
|
|||
break;
|
||||
case 4:
|
||||
err = _nfs4_pnfs_v4_ds_connect(mds_srv, ds, timeo, retrans,
|
||||
minor_version);
|
||||
minor_version, tightly_coupled);
|
||||
break;
|
||||
default:
|
||||
dprintk("%s: unsupported DS version %d\n", __func__, version);
|
||||
|
|
|
|||
|
|
@ -739,17 +739,18 @@ static void nfs_inode_remove_request(struct nfs_page *req)
|
|||
nfs_page_group_lock(req);
|
||||
if (nfs_page_group_sync_on_bit_locked(req, PG_REMOVE)) {
|
||||
struct folio *folio = nfs_page_to_folio(req->wb_head);
|
||||
struct address_space *mapping = folio->mapping;
|
||||
|
||||
spin_lock(&mapping->i_private_lock);
|
||||
if (likely(folio)) {
|
||||
struct address_space *mapping = folio->mapping;
|
||||
|
||||
spin_lock(&mapping->i_private_lock);
|
||||
folio->private = NULL;
|
||||
folio_clear_private(folio);
|
||||
clear_bit(PG_MAPPED, &req->wb_head->wb_flags);
|
||||
}
|
||||
spin_unlock(&mapping->i_private_lock);
|
||||
spin_unlock(&mapping->i_private_lock);
|
||||
|
||||
folio_end_dropbehind(folio);
|
||||
folio_end_dropbehind(folio);
|
||||
}
|
||||
}
|
||||
nfs_page_group_unlock(req);
|
||||
|
||||
|
|
@ -1664,7 +1665,7 @@ int nfs_initiate_commit(struct rpc_clnt *clnt, struct nfs_commit_data *data,
|
|||
dprintk("NFS: initiated commit call\n");
|
||||
|
||||
if (localio)
|
||||
return nfs_local_commit(localio, data, call_ops, how);
|
||||
return nfs_local_commit(localio, data, call_ops);
|
||||
|
||||
task = rpc_run_task(&task_setup_data);
|
||||
if (IS_ERR(task))
|
||||
|
|
|
|||
|
|
@ -389,6 +389,14 @@ enum {
|
|||
FATTR4_XATTR_SUPPORT = 82,
|
||||
};
|
||||
|
||||
/*
|
||||
* Symbol name and value are from draft-ietf-nfsv4-uncacheable-files
|
||||
* Section 7. "XDR for Uncacheable Attribute"
|
||||
*/
|
||||
enum {
|
||||
FATTR4_UNCACHEABLE_FILE_DATA = 87,
|
||||
};
|
||||
|
||||
/*
|
||||
* The following internal definitions enable processing the above
|
||||
* attribute bits within 32-bit word boundaries.
|
||||
|
|
@ -475,6 +483,7 @@ enum {
|
|||
#define FATTR4_WORD2_ACL_TRUEFORM_SCOPE BIT(FATTR4_ACL_TRUEFORM_SCOPE - 64)
|
||||
#define FATTR4_WORD2_POSIX_DEFAULT_ACL BIT(FATTR4_POSIX_DEFAULT_ACL - 64)
|
||||
#define FATTR4_WORD2_POSIX_ACCESS_ACL BIT(FATTR4_POSIX_ACCESS_ACL - 64)
|
||||
#define FATTR4_WORD2_UNCACHEABLE_FILE_DATA BIT(FATTR4_UNCACHEABLE_FILE_DATA - 64)
|
||||
|
||||
/* MDS threshold bitmap bits */
|
||||
#define THRESHOLD_RD (1UL << 0)
|
||||
|
|
|
|||
|
|
@ -110,6 +110,7 @@ struct nfs_open_context {
|
|||
#define NFS_CONTEXT_UNLOCK (3)
|
||||
#define NFS_CONTEXT_FILE_OPEN (4)
|
||||
#define NFS_CONTEXT_WRITE_SYNC (5)
|
||||
#define NFS_CONTEXT_O_DIRECT (6)
|
||||
|
||||
struct nfs4_threshold *mdsthreshold;
|
||||
struct list_head list;
|
||||
|
|
@ -162,6 +163,8 @@ struct nfs_inode {
|
|||
|
||||
struct timespec64 btime;
|
||||
|
||||
bool uncacheable_file_data : 1;
|
||||
|
||||
/*
|
||||
* read_cache_jiffies is when we started read-caching this inode.
|
||||
* attrtimeo is for how long the cached information is assumed
|
||||
|
|
@ -319,6 +322,7 @@ struct nfs4_copy_state {
|
|||
#define NFS_INO_INVALID_NLINK BIT(16) /* cached nlinks is invalid */
|
||||
#define NFS_INO_INVALID_MODE BIT(17) /* cached mode is invalid */
|
||||
#define NFS_INO_INVALID_BTIME BIT(18) /* cached btime is invalid */
|
||||
#define NFS_INO_INVALID_UNCACHEABLE_FILE_DATA BIT(19) /* cached uncacheable_file_data is invalid */
|
||||
|
||||
#define NFS_INO_INVALID_ATTR (NFS_INO_INVALID_CHANGE \
|
||||
| NFS_INO_INVALID_CTIME \
|
||||
|
|
|
|||
|
|
@ -17,6 +17,9 @@
|
|||
|
||||
#define NFS_BITMASK_SZ 3
|
||||
|
||||
/* aux_flags in nfs_fattr */
|
||||
#define NFS_AUX_UNCACHEABLE_FILE_DATA BIT(0)
|
||||
|
||||
struct nfs4_string {
|
||||
unsigned int len;
|
||||
char *data;
|
||||
|
|
@ -68,6 +71,7 @@ struct nfs_fattr {
|
|||
struct timespec64 mtime;
|
||||
struct timespec64 ctime;
|
||||
struct timespec64 btime;
|
||||
__u32 aux_flags; /* NFSv4 auxiliary flags bitfield */
|
||||
__u64 change_attr; /* NFSv4 change attribute */
|
||||
__u64 pre_change_attr;/* pre-op NFSv4 change attribute */
|
||||
__u64 pre_size; /* pre_op_attr.size */
|
||||
|
|
@ -108,6 +112,7 @@ struct nfs_fattr {
|
|||
#define NFS_ATTR_FATTR_GROUP_NAME BIT_ULL(24)
|
||||
#define NFS_ATTR_FATTR_V4_SECURITY_LABEL BIT_ULL(25)
|
||||
#define NFS_ATTR_FATTR_BTIME BIT_ULL(26)
|
||||
#define NFS_ATTR_FATTR_UNCACHEABLE_FILE_DATA BIT_ULL(27)
|
||||
|
||||
#define NFS_ATTR_FATTR (NFS_ATTR_FATTR_TYPE \
|
||||
| NFS_ATTR_FATTR_MODE \
|
||||
|
|
@ -129,7 +134,8 @@ struct nfs_fattr {
|
|||
#define NFS_ATTR_FATTR_V4 (NFS_ATTR_FATTR \
|
||||
| NFS_ATTR_FATTR_SPACE_USED \
|
||||
| NFS_ATTR_FATTR_BTIME \
|
||||
| NFS_ATTR_FATTR_V4_SECURITY_LABEL)
|
||||
| NFS_ATTR_FATTR_V4_SECURITY_LABEL \
|
||||
| NFS_ATTR_FATTR_UNCACHEABLE_FILE_DATA)
|
||||
|
||||
/*
|
||||
* Maximal number of supported layout drivers.
|
||||
|
|
@ -354,7 +360,7 @@ struct nfs4_layoutreturn {
|
|||
struct nfs4_xdr_opaque_data ld_private;
|
||||
};
|
||||
|
||||
#define PNFS_LAYOUTSTATS_MAXSIZE 256
|
||||
#define PNFS_LAYOUTSTATS_MAXSIZE 384
|
||||
|
||||
struct nfs42_layoutstat_args;
|
||||
struct nfs42_layoutstat_devinfo;
|
||||
|
|
|
|||
|
|
@ -661,6 +661,7 @@ extern void workqueue_set_min_active(struct workqueue_struct *wq,
|
|||
int min_active);
|
||||
extern struct work_struct *current_work(void);
|
||||
extern bool current_is_workqueue_rescuer(void);
|
||||
extern bool current_is_workqueue_mem_reclaim(void);
|
||||
extern bool workqueue_congested(int cpu, struct workqueue_struct *wq);
|
||||
extern unsigned int work_busy(struct work_struct *work);
|
||||
extern __printf(1, 2) void set_worker_desc(const char *fmt, ...);
|
||||
|
|
|
|||
|
|
@ -6293,6 +6293,30 @@ bool current_is_workqueue_rescuer(void)
|
|||
return worker && worker->rescue_wq;
|
||||
}
|
||||
|
||||
/**
|
||||
* current_is_workqueue_mem_reclaim - is %current a %WQ_MEM_RECLAIM worker?
|
||||
*
|
||||
* Determine whether %current is a workqueue worker executing on a workqueue
|
||||
* created with %WQ_MEM_RECLAIM. This mirrors the condition that
|
||||
* check_flush_dependency() warns on: flushing (or otherwise waiting on) a
|
||||
* !WQ_MEM_RECLAIM workqueue from such a context breaks the forward-progress
|
||||
* guarantee and can deadlock. Callers that may recurse into such a flush --
|
||||
* e.g. NFS LOCALIO submitting into a stacked filesystem that flushes its own
|
||||
* !WQ_MEM_RECLAIM workqueue -- can use this to decide whether they must defer
|
||||
* the work to a !WQ_MEM_RECLAIM workqueue rather than run it inline.
|
||||
*
|
||||
* Return: %true if %current is a %WQ_MEM_RECLAIM worker. %false otherwise.
|
||||
*/
|
||||
bool current_is_workqueue_mem_reclaim(void)
|
||||
{
|
||||
struct worker *worker = current_wq_worker();
|
||||
|
||||
return worker &&
|
||||
((worker->current_pwq->wq->flags &
|
||||
(WQ_MEM_RECLAIM | __WQ_LEGACY)) == WQ_MEM_RECLAIM);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(current_is_workqueue_mem_reclaim);
|
||||
|
||||
/**
|
||||
* workqueue_congested - test whether a workqueue is congested
|
||||
* @cpu: CPU in question
|
||||
|
|
|
|||
|
|
@ -96,7 +96,10 @@ static void rpc_unregister_client(struct rpc_clnt *clnt)
|
|||
|
||||
static void __rpc_clnt_remove_pipedir(struct rpc_clnt *clnt)
|
||||
{
|
||||
rpc_remove_client_dir(clnt);
|
||||
if (clnt->pipefs_sb) {
|
||||
rpc_remove_client_dir(clnt);
|
||||
clnt->pipefs_sb = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void rpc_clnt_remove_pipedir(struct rpc_clnt *clnt)
|
||||
|
|
@ -177,19 +180,28 @@ static int rpc_clnt_skip_event(struct rpc_clnt *clnt, unsigned long event)
|
|||
}
|
||||
|
||||
static int __rpc_clnt_handle_event(struct rpc_clnt *clnt, unsigned long event,
|
||||
struct super_block *sb)
|
||||
struct super_block *sb)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
switch (event) {
|
||||
case RPC_PIPEFS_MOUNT:
|
||||
return rpc_setup_pipedir_sb(sb, clnt);
|
||||
clnt->pipefs_sb = sb;
|
||||
err = rpc_setup_pipedir_sb(sb, clnt);
|
||||
if (err)
|
||||
clnt->pipefs_sb = NULL;
|
||||
break;
|
||||
case RPC_PIPEFS_UMOUNT:
|
||||
__rpc_clnt_remove_pipedir(clnt);
|
||||
if (clnt->pipefs_sb == sb) {
|
||||
__rpc_clnt_remove_pipedir(clnt);
|
||||
clnt->pipefs_sb = NULL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR "%s: unknown event: %ld\n", __func__, event);
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
return 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __rpc_pipefs_event(struct rpc_clnt *clnt, unsigned long event,
|
||||
|
|
|
|||
|
|
@ -490,6 +490,8 @@ static int rpcb_register_inet4(struct sunrpc_net *sn,
|
|||
int result;
|
||||
|
||||
map->r_addr = rpc_sockaddr2uaddr(sap, GFP_KERNEL);
|
||||
if (!map->r_addr)
|
||||
return -ENOMEM;
|
||||
|
||||
msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET];
|
||||
if (port != 0) {
|
||||
|
|
@ -516,6 +518,8 @@ static int rpcb_register_inet6(struct sunrpc_net *sn,
|
|||
int result;
|
||||
|
||||
map->r_addr = rpc_sockaddr2uaddr(sap, GFP_KERNEL);
|
||||
if (!map->r_addr)
|
||||
return -ENOMEM;
|
||||
|
||||
msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET];
|
||||
if (port != 0) {
|
||||
|
|
|
|||
|
|
@ -1202,9 +1202,9 @@ static void xs_save_old_callbacks(struct sock_xprt *transport, struct sock *sk)
|
|||
|
||||
static void xs_restore_old_callbacks(struct sock_xprt *transport, struct sock *sk)
|
||||
{
|
||||
sk->sk_data_ready = transport->old_data_ready;
|
||||
WRITE_ONCE(sk->sk_data_ready, transport->old_data_ready);
|
||||
sk->sk_state_change = transport->old_state_change;
|
||||
sk->sk_write_space = transport->old_write_space;
|
||||
WRITE_ONCE(sk->sk_write_space, transport->old_write_space);
|
||||
sk->sk_error_report = transport->old_error_report;
|
||||
}
|
||||
|
||||
|
|
@ -1664,6 +1664,7 @@ static void xs_udp_do_set_buffer_size(struct rpc_xprt *xprt)
|
|||
{
|
||||
struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
|
||||
struct sock *sk = transport->inet;
|
||||
void (*write_space)(struct sock *sock);
|
||||
|
||||
if (transport->rcvsize) {
|
||||
sk->sk_userlocks |= SOCK_RCVBUF_LOCK;
|
||||
|
|
@ -1672,7 +1673,8 @@ static void xs_udp_do_set_buffer_size(struct rpc_xprt *xprt)
|
|||
if (transport->sndsize) {
|
||||
sk->sk_userlocks |= SOCK_SNDBUF_LOCK;
|
||||
sk->sk_sndbuf = transport->sndsize * xprt->max_reqs * 2;
|
||||
sk->sk_write_space(sk);
|
||||
write_space = READ_ONCE(sk->sk_write_space);
|
||||
write_space(sk);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1988,8 +1990,8 @@ static int xs_local_finish_connecting(struct rpc_xprt *xprt,
|
|||
xs_save_old_callbacks(transport, sk);
|
||||
|
||||
sk->sk_user_data = xprt;
|
||||
sk->sk_data_ready = xs_data_ready;
|
||||
sk->sk_write_space = xs_udp_write_space;
|
||||
WRITE_ONCE(sk->sk_data_ready, xs_data_ready);
|
||||
WRITE_ONCE(sk->sk_write_space, xs_udp_write_space);
|
||||
sk->sk_state_change = xs_local_state_change;
|
||||
sk->sk_error_report = xs_error_report;
|
||||
sk->sk_use_task_frag = false;
|
||||
|
|
@ -2191,8 +2193,8 @@ static void xs_udp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
|
|||
xs_save_old_callbacks(transport, sk);
|
||||
|
||||
sk->sk_user_data = xprt;
|
||||
sk->sk_data_ready = xs_data_ready;
|
||||
sk->sk_write_space = xs_udp_write_space;
|
||||
WRITE_ONCE(sk->sk_data_ready, xs_data_ready);
|
||||
WRITE_ONCE(sk->sk_write_space, xs_udp_write_space);
|
||||
sk->sk_use_task_frag = false;
|
||||
|
||||
xprt_set_connected(xprt);
|
||||
|
|
@ -2378,9 +2380,9 @@ static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
|
|||
xs_save_old_callbacks(transport, sk);
|
||||
|
||||
sk->sk_user_data = xprt;
|
||||
sk->sk_data_ready = xs_data_ready;
|
||||
WRITE_ONCE(sk->sk_data_ready, xs_data_ready);
|
||||
sk->sk_state_change = xs_tcp_state_change;
|
||||
sk->sk_write_space = xs_tcp_write_space;
|
||||
WRITE_ONCE(sk->sk_write_space, xs_tcp_write_space);
|
||||
sk->sk_error_report = xs_error_report;
|
||||
sk->sk_use_task_frag = false;
|
||||
|
||||
|
|
@ -2648,7 +2650,17 @@ static int xs_tls_handshake_sync(struct rpc_xprt *lower_xprt, struct xprtsec_par
|
|||
rc = wait_for_completion_interruptible_timeout(&lower_transport->handshake_done,
|
||||
XS_TLS_HANDSHAKE_TO);
|
||||
if (rc <= 0) {
|
||||
tls_handshake_cancel(sk);
|
||||
if (!tls_handshake_cancel(sk)) {
|
||||
/*
|
||||
* Cancellation lost to handshake_complete(): the
|
||||
* callback still owns its xprt reference and is in
|
||||
* flight. Wait for it to finish before returning.
|
||||
*/
|
||||
wait_for_completion(&lower_transport->handshake_done);
|
||||
if (rc == 0)
|
||||
rc = -ETIMEDOUT;
|
||||
goto out;
|
||||
}
|
||||
if (rc == 0)
|
||||
rc = -ETIMEDOUT;
|
||||
goto out_put_xprt;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user