NFS client bugfixes for Linux 6.17
Stable patches:
- Revert "SUNRPC: Don't allow waiting for exiting tasks" as it is
breaking ltp tests.
Bugfixes:
- Another set of fixes to the tracking of NFSv4 server capabilities
when crossing filesystem boundaries.
- Localio fix to restore credentials and prevent triggering a BUG_ON().
- Fix to prevent flapping of the localio on/off trigger.
- Protections against 'eof page pollution' as demonstrated in xfstests
generic/363.
- Series of patches to ensure correct ordering of O_DIRECT i/o and
truncate, fallocate and copy functions.
- Fix a NULL pointer check in flexfiles reads that regresses 6.17.
- Correct a typo that breaks flexfiles layout segment processing.
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEESQctxSBg8JpV8KqEZwvnipYKAPIFAmjBjysACgkQZwvnipYK
APJkNg/9Gd2IWoWse0PeOkijLhsxwnH6S6huvX3ouD9RziWobJAHbk7zpgycMt5/
C+DYoqhpM/uIKRBjLPafnMFXQhsx/jEJcBSZOP3C1AD5OEvA/qtaE5nfGw9Zbnyr
/j+B5yVhC8yPrDGFH9PlQ6UeFxnK9frqqqbNXDoCn5QCpmAjlbyESOiQ6ZZKUpZV
vXPv9C4DeSZoZ2CsXMAWsLarGcrHE3ctpi+Bpfq7iDdUCdeYBOtaJHrgKtgwmCQy
My5J3l7KRKmAy22XWvu+sRn7wQO0y5UOWtXUiDZD73ufC4hF1IIRuBWHW/5IBYD+
6ojdBxYqTW01JeFWt4MoT8f+AKbej36x7abnf0ztxVpzXhp19KXiF+ddWrcyjKvc
bjohM0slddM4TLAz/98D6Kwm7N/KFOD7DHPBv9vvMA8ci2efx+cQvKToNRnxK0xi
FNmIi8+ZuKz9Pr32JINHHC1RFtl1dTb39l7jJVIK2niGYTjPwlxpcE7bax9CL1S7
ke9m7GtX5dUyBYG2rKzLjihpTthL4GQgW6PlSMhIk2BA/m1ZZUVLAxI8xh9TR02V
oMlxq78fsFNCxCvvqlUeo93IH7YHGSl1PbUqPjD0fs5k8lOX6rHXmHULqYgkmsC/
QCAiXDg6gh2Rj69/9yvkWPe0KIXIULKGT++oZakgbMQPujNEtxE=
=5TC7
-----END PGP SIGNATURE-----
Merge tag 'nfs-for-6.17-3' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS client fixes from Trond Myklebust:
"Stable patches:
- Revert "SUNRPC: Don't allow waiting for exiting tasks" as it is
breaking ltp tests
Bugfixes:
- Another set of fixes to the tracking of NFSv4 server capabilities
when crossing filesystem boundaries
- Localio fix to restore credentials and prevent triggering a
BUG_ON()
- Fix to prevent flapping of the localio on/off trigger
- Protections against 'eof page pollution' as demonstrated in
xfstests generic/363
- Series of patches to ensure correct ordering of O_DIRECT i/o and
truncate, fallocate and copy functions
- Fix a NULL pointer check in flexfiles reads that regresses 6.17
- Correct a typo that breaks flexfiles layout segment processing"
* tag 'nfs-for-6.17-3' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
NFSv4/flexfiles: Fix layout merge mirror check.
SUNRPC: call xs_sock_process_cmsg for all cmsg
Revert "SUNRPC: Don't allow waiting for exiting tasks"
NFS: Fix the marking of the folio as up to date
NFS: nfs_invalidate_folio() must observe the offset and size arguments
NFSv4.2: Serialise O_DIRECT i/o and copy range
NFSv4.2: Serialise O_DIRECT i/o and clone range
NFSv4.2: Serialise O_DIRECT i/o and fallocate()
NFS: Serialise O_DIRECT i/o and truncate()
NFSv4.2: Protect copy offload and clone against 'eof page pollution'
NFS: Protect against 'eof page pollution'
flexfiles/pNFS: fix NULL checks on result of ff_layout_choose_ds_for_read
nfs/localio: avoid bouncing LOCALIO if nfs_client_is_local()
nfs/localio: restore creds before releasing pageio data
NFSv4: Clear the NFS_CAP_XATTR flag if not supported by the server
NFSv4: Clear NFS_CAP_OPEN_XOR and NFS_CAP_DELEGTIME if not supported
NFSv4: Clear the NFS_CAP_FS_LOCATIONS flag if it is not set
NFSv4: Don't clear capabilities that won't be reset
pull/824/head
commit
7aac71907b
|
|
@ -888,6 +888,8 @@ static void nfs_server_set_fsinfo(struct nfs_server *server,
|
|||
|
||||
if (fsinfo->xattr_support)
|
||||
server->caps |= NFS_CAP_XATTR;
|
||||
else
|
||||
server->caps &= ~NFS_CAP_XATTR;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
#include <linux/mm.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/rmap.h>
|
||||
#include <linux/swap.h>
|
||||
#include <linux/compaction.h>
|
||||
|
||||
|
|
@ -280,6 +281,37 @@ nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(nfs_file_fsync);
|
||||
|
||||
void nfs_truncate_last_folio(struct address_space *mapping, loff_t from,
|
||||
loff_t to)
|
||||
{
|
||||
struct folio *folio;
|
||||
|
||||
if (from >= to)
|
||||
return;
|
||||
|
||||
folio = filemap_lock_folio(mapping, from >> PAGE_SHIFT);
|
||||
if (IS_ERR(folio))
|
||||
return;
|
||||
|
||||
if (folio_mkclean(folio))
|
||||
folio_mark_dirty(folio);
|
||||
|
||||
if (folio_test_uptodate(folio)) {
|
||||
loff_t fpos = folio_pos(folio);
|
||||
size_t offset = from - fpos;
|
||||
size_t end = folio_size(folio);
|
||||
|
||||
if (to - fpos < end)
|
||||
end = to - fpos;
|
||||
folio_zero_segment(folio, offset, end);
|
||||
trace_nfs_size_truncate_folio(mapping->host, to);
|
||||
}
|
||||
|
||||
folio_unlock(folio);
|
||||
folio_put(folio);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nfs_truncate_last_folio);
|
||||
|
||||
/*
|
||||
* Decide whether a read/modify/write cycle may be more efficient
|
||||
* then a modify/write/read cycle when writing to a page in the
|
||||
|
|
@ -356,6 +388,7 @@ static int nfs_write_begin(const struct kiocb *iocb,
|
|||
|
||||
dfprintk(PAGECACHE, "NFS: write_begin(%pD2(%lu), %u@%lld)\n",
|
||||
file, mapping->host->i_ino, len, (long long) pos);
|
||||
nfs_truncate_last_folio(mapping, i_size_read(mapping->host), pos);
|
||||
|
||||
fgp |= fgf_set_order(len);
|
||||
start:
|
||||
|
|
@ -442,10 +475,11 @@ static void nfs_invalidate_folio(struct folio *folio, size_t offset,
|
|||
dfprintk(PAGECACHE, "NFS: invalidate_folio(%lu, %zu, %zu)\n",
|
||||
folio->index, offset, length);
|
||||
|
||||
if (offset != 0 || length < folio_size(folio))
|
||||
return;
|
||||
/* Cancel any unstarted writes on this page */
|
||||
nfs_wb_folio_cancel(inode, folio);
|
||||
if (offset != 0 || length < folio_size(folio))
|
||||
nfs_wb_folio(inode, folio);
|
||||
else
|
||||
nfs_wb_folio_cancel(inode, folio);
|
||||
folio_wait_private_2(folio); /* [DEPRECATED] */
|
||||
trace_nfs_invalidate_folio(inode, folio_pos(folio) + offset, length);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -293,7 +293,7 @@ ff_lseg_match_mirrors(struct pnfs_layout_segment *l1,
|
|||
struct pnfs_layout_segment *l2)
|
||||
{
|
||||
const struct nfs4_ff_layout_segment *fl1 = FF_LAYOUT_LSEG(l1);
|
||||
const struct nfs4_ff_layout_segment *fl2 = FF_LAYOUT_LSEG(l1);
|
||||
const struct nfs4_ff_layout_segment *fl2 = FF_LAYOUT_LSEG(l2);
|
||||
u32 i;
|
||||
|
||||
if (fl1->mirror_array_cnt != fl2->mirror_array_cnt)
|
||||
|
|
@ -773,8 +773,11 @@ ff_layout_choose_ds_for_read(struct pnfs_layout_segment *lseg,
|
|||
continue;
|
||||
|
||||
if (check_device &&
|
||||
nfs4_test_deviceid_unavailable(&mirror->mirror_ds->id_node))
|
||||
nfs4_test_deviceid_unavailable(&mirror->mirror_ds->id_node)) {
|
||||
// reinitialize the error state in case if this is the last iteration
|
||||
ds = ERR_PTR(-EINVAL);
|
||||
continue;
|
||||
}
|
||||
|
||||
*best_idx = idx;
|
||||
break;
|
||||
|
|
@ -804,7 +807,7 @@ ff_layout_choose_best_ds_for_read(struct pnfs_layout_segment *lseg,
|
|||
struct nfs4_pnfs_ds *ds;
|
||||
|
||||
ds = ff_layout_choose_valid_ds_for_read(lseg, start_idx, best_idx);
|
||||
if (ds)
|
||||
if (!IS_ERR(ds))
|
||||
return ds;
|
||||
return ff_layout_choose_any_ds_for_read(lseg, start_idx, best_idx);
|
||||
}
|
||||
|
|
@ -818,7 +821,7 @@ ff_layout_get_ds_for_read(struct nfs_pageio_descriptor *pgio,
|
|||
|
||||
ds = ff_layout_choose_best_ds_for_read(lseg, pgio->pg_mirror_idx,
|
||||
best_idx);
|
||||
if (ds || !pgio->pg_mirror_idx)
|
||||
if (!IS_ERR(ds) || !pgio->pg_mirror_idx)
|
||||
return ds;
|
||||
return ff_layout_choose_best_ds_for_read(lseg, 0, best_idx);
|
||||
}
|
||||
|
|
@ -868,7 +871,7 @@ retry:
|
|||
req->wb_nio = 0;
|
||||
|
||||
ds = ff_layout_get_ds_for_read(pgio, &ds_idx);
|
||||
if (!ds) {
|
||||
if (IS_ERR(ds)) {
|
||||
if (!ff_layout_no_fallback_to_mds(pgio->pg_lseg))
|
||||
goto out_mds;
|
||||
pnfs_generic_pg_cleanup(pgio);
|
||||
|
|
@ -1072,11 +1075,13 @@ static void ff_layout_resend_pnfs_read(struct nfs_pgio_header *hdr)
|
|||
{
|
||||
u32 idx = hdr->pgio_mirror_idx + 1;
|
||||
u32 new_idx = 0;
|
||||
struct nfs4_pnfs_ds *ds;
|
||||
|
||||
if (ff_layout_choose_any_ds_for_read(hdr->lseg, idx, &new_idx))
|
||||
ff_layout_send_layouterror(hdr->lseg);
|
||||
else
|
||||
ds = ff_layout_choose_any_ds_for_read(hdr->lseg, idx, &new_idx);
|
||||
if (IS_ERR(ds))
|
||||
pnfs_error_mark_layout_for_return(hdr->inode, hdr->lseg);
|
||||
else
|
||||
ff_layout_send_layouterror(hdr->lseg);
|
||||
pnfs_read_resend_pnfs(hdr, new_idx);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -716,6 +716,7 @@ nfs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
|
|||
{
|
||||
struct inode *inode = d_inode(dentry);
|
||||
struct nfs_fattr *fattr;
|
||||
loff_t oldsize = i_size_read(inode);
|
||||
int error = 0;
|
||||
|
||||
nfs_inc_stats(inode, NFSIOS_VFSSETATTR);
|
||||
|
|
@ -731,7 +732,7 @@ nfs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
|
|||
if (error)
|
||||
return error;
|
||||
|
||||
if (attr->ia_size == i_size_read(inode))
|
||||
if (attr->ia_size == oldsize)
|
||||
attr->ia_valid &= ~ATTR_SIZE;
|
||||
}
|
||||
|
||||
|
|
@ -767,8 +768,10 @@ nfs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
|
|||
trace_nfs_setattr_enter(inode);
|
||||
|
||||
/* Write all dirty data */
|
||||
if (S_ISREG(inode->i_mode))
|
||||
if (S_ISREG(inode->i_mode)) {
|
||||
nfs_file_block_o_direct(NFS_I(inode));
|
||||
nfs_sync_inode(inode);
|
||||
}
|
||||
|
||||
fattr = nfs_alloc_fattr_with_label(NFS_SERVER(inode));
|
||||
if (fattr == NULL) {
|
||||
|
|
@ -777,8 +780,12 @@ nfs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
|
|||
}
|
||||
|
||||
error = NFS_PROTO(inode)->setattr(dentry, fattr, attr);
|
||||
if (error == 0)
|
||||
if (error == 0) {
|
||||
if (attr->ia_valid & ATTR_SIZE)
|
||||
nfs_truncate_last_folio(inode->i_mapping, oldsize,
|
||||
attr->ia_size);
|
||||
error = nfs_refresh_inode(inode, fattr);
|
||||
}
|
||||
nfs_free_fattr(fattr);
|
||||
out:
|
||||
trace_nfs_setattr_exit(inode, error);
|
||||
|
|
|
|||
|
|
@ -437,6 +437,8 @@ int nfs_file_release(struct inode *, struct file *);
|
|||
int nfs_lock(struct file *, int, struct file_lock *);
|
||||
int nfs_flock(struct file *, int, struct file_lock *);
|
||||
int nfs_check_flags(int);
|
||||
void nfs_truncate_last_folio(struct address_space *mapping, loff_t from,
|
||||
loff_t to);
|
||||
|
||||
/* inode.c */
|
||||
extern struct workqueue_struct *nfsiod_workqueue;
|
||||
|
|
@ -530,6 +532,16 @@ static inline bool nfs_file_io_is_buffered(struct nfs_inode *nfsi)
|
|||
return test_bit(NFS_INO_ODIRECT, &nfsi->flags) == 0;
|
||||
}
|
||||
|
||||
/* Must be called with exclusively locked inode->i_rwsem */
|
||||
static inline void nfs_file_block_o_direct(struct nfs_inode *nfsi)
|
||||
{
|
||||
if (test_bit(NFS_INO_ODIRECT, &nfsi->flags)) {
|
||||
clear_bit(NFS_INO_ODIRECT, &nfsi->flags);
|
||||
inode_dio_wait(&nfsi->vfs_inode);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* namespace.c */
|
||||
#define NFS_PATH_CANONICAL 1
|
||||
extern char *nfs_path(char **p, struct dentry *dentry,
|
||||
|
|
|
|||
13
fs/nfs/io.c
13
fs/nfs/io.c
|
|
@ -14,15 +14,6 @@
|
|||
|
||||
#include "internal.h"
|
||||
|
||||
/* Call with exclusively locked inode->i_rwsem */
|
||||
static void nfs_block_o_direct(struct nfs_inode *nfsi, struct inode *inode)
|
||||
{
|
||||
if (test_bit(NFS_INO_ODIRECT, &nfsi->flags)) {
|
||||
clear_bit(NFS_INO_ODIRECT, &nfsi->flags);
|
||||
inode_dio_wait(inode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* nfs_start_io_read - declare the file is being used for buffered reads
|
||||
* @inode: file inode
|
||||
|
|
@ -57,7 +48,7 @@ nfs_start_io_read(struct inode *inode)
|
|||
err = down_write_killable(&inode->i_rwsem);
|
||||
if (err)
|
||||
return err;
|
||||
nfs_block_o_direct(nfsi, inode);
|
||||
nfs_file_block_o_direct(nfsi);
|
||||
downgrade_write(&inode->i_rwsem);
|
||||
|
||||
return 0;
|
||||
|
|
@ -90,7 +81,7 @@ nfs_start_io_write(struct inode *inode)
|
|||
|
||||
err = down_write_killable(&inode->i_rwsem);
|
||||
if (!err)
|
||||
nfs_block_o_direct(NFS_I(inode), inode);
|
||||
nfs_file_block_o_direct(NFS_I(inode));
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -180,10 +180,8 @@ static void nfs_local_probe(struct nfs_client *clp)
|
|||
return;
|
||||
}
|
||||
|
||||
if (nfs_client_is_local(clp)) {
|
||||
/* If already enabled, disable and re-enable */
|
||||
nfs_localio_disable_client(clp);
|
||||
}
|
||||
if (nfs_client_is_local(clp))
|
||||
return;
|
||||
|
||||
if (!nfs_uuid_begin(&clp->cl_uuid))
|
||||
return;
|
||||
|
|
@ -244,7 +242,8 @@ __nfs_local_open_fh(struct nfs_client *clp, const struct cred *cred,
|
|||
case -ENOMEM:
|
||||
case -ENXIO:
|
||||
case -ENOENT:
|
||||
/* Revalidate localio, will disable if unsupported */
|
||||
/* Revalidate localio */
|
||||
nfs_localio_disable_client(clp);
|
||||
nfs_local_probe(clp);
|
||||
}
|
||||
}
|
||||
|
|
@ -453,12 +452,13 @@ static void nfs_local_call_read(struct work_struct *work)
|
|||
nfs_local_iter_init(&iter, iocb, READ);
|
||||
|
||||
status = filp->f_op->read_iter(&iocb->kiocb, &iter);
|
||||
|
||||
revert_creds(save_cred);
|
||||
|
||||
if (status != -EIOCBQUEUED) {
|
||||
nfs_local_read_done(iocb, status);
|
||||
nfs_local_pgio_release(iocb);
|
||||
}
|
||||
|
||||
revert_creds(save_cred);
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
@ -648,14 +648,15 @@ static void nfs_local_call_write(struct work_struct *work)
|
|||
file_start_write(filp);
|
||||
status = filp->f_op->write_iter(&iocb->kiocb, &iter);
|
||||
file_end_write(filp);
|
||||
|
||||
revert_creds(save_cred);
|
||||
current->flags = old_flags;
|
||||
|
||||
if (status != -EIOCBQUEUED) {
|
||||
nfs_local_write_done(iocb, status);
|
||||
nfs_local_vfs_getattr(iocb);
|
||||
nfs_local_pgio_release(iocb);
|
||||
}
|
||||
|
||||
revert_creds(save_cred);
|
||||
current->flags = old_flags;
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
|
|||
|
|
@ -114,6 +114,7 @@ static int nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep,
|
|||
exception.inode = inode;
|
||||
exception.state = lock->open_context->state;
|
||||
|
||||
nfs_file_block_o_direct(NFS_I(inode));
|
||||
err = nfs_sync_inode(inode);
|
||||
if (err)
|
||||
goto out;
|
||||
|
|
@ -137,6 +138,7 @@ int nfs42_proc_allocate(struct file *filep, loff_t offset, loff_t len)
|
|||
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_ALLOCATE],
|
||||
};
|
||||
struct inode *inode = file_inode(filep);
|
||||
loff_t oldsize = i_size_read(inode);
|
||||
int err;
|
||||
|
||||
if (!nfs_server_capable(inode, NFS_CAP_ALLOCATE))
|
||||
|
|
@ -145,7 +147,11 @@ int nfs42_proc_allocate(struct file *filep, loff_t offset, loff_t len)
|
|||
inode_lock(inode);
|
||||
|
||||
err = nfs42_proc_fallocate(&msg, filep, offset, len);
|
||||
if (err == -EOPNOTSUPP)
|
||||
|
||||
if (err == 0)
|
||||
nfs_truncate_last_folio(inode->i_mapping, oldsize,
|
||||
offset + len);
|
||||
else if (err == -EOPNOTSUPP)
|
||||
NFS_SERVER(inode)->caps &= ~(NFS_CAP_ALLOCATE |
|
||||
NFS_CAP_ZERO_RANGE);
|
||||
|
||||
|
|
@ -183,6 +189,7 @@ int nfs42_proc_zero_range(struct file *filep, loff_t offset, loff_t len)
|
|||
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_ZERO_RANGE],
|
||||
};
|
||||
struct inode *inode = file_inode(filep);
|
||||
loff_t oldsize = i_size_read(inode);
|
||||
int err;
|
||||
|
||||
if (!nfs_server_capable(inode, NFS_CAP_ZERO_RANGE))
|
||||
|
|
@ -191,9 +198,11 @@ int nfs42_proc_zero_range(struct file *filep, loff_t offset, loff_t len)
|
|||
inode_lock(inode);
|
||||
|
||||
err = nfs42_proc_fallocate(&msg, filep, offset, len);
|
||||
if (err == 0)
|
||||
if (err == 0) {
|
||||
nfs_truncate_last_folio(inode->i_mapping, oldsize,
|
||||
offset + len);
|
||||
truncate_pagecache_range(inode, offset, (offset + len) -1);
|
||||
if (err == -EOPNOTSUPP)
|
||||
} else if (err == -EOPNOTSUPP)
|
||||
NFS_SERVER(inode)->caps &= ~NFS_CAP_ZERO_RANGE;
|
||||
|
||||
inode_unlock(inode);
|
||||
|
|
@ -354,22 +363,27 @@ out:
|
|||
|
||||
/**
|
||||
* nfs42_copy_dest_done - perform inode cache updates after clone/copy offload
|
||||
* @inode: pointer to destination inode
|
||||
* @file: pointer to destination file
|
||||
* @pos: destination offset
|
||||
* @len: copy length
|
||||
* @oldsize: length of the file prior to clone/copy
|
||||
*
|
||||
* Punch a hole in the inode page cache, so that the NFS client will
|
||||
* know to retrieve new data.
|
||||
* Update the file size if necessary, and then mark the inode as having
|
||||
* invalid cached values for change attribute, ctime, mtime and space used.
|
||||
*/
|
||||
static void nfs42_copy_dest_done(struct inode *inode, loff_t pos, loff_t len)
|
||||
static void nfs42_copy_dest_done(struct file *file, loff_t pos, loff_t len,
|
||||
loff_t oldsize)
|
||||
{
|
||||
struct inode *inode = file_inode(file);
|
||||
struct address_space *mapping = file->f_mapping;
|
||||
loff_t newsize = pos + len;
|
||||
loff_t end = newsize - 1;
|
||||
|
||||
WARN_ON_ONCE(invalidate_inode_pages2_range(inode->i_mapping,
|
||||
pos >> PAGE_SHIFT, end >> PAGE_SHIFT));
|
||||
nfs_truncate_last_folio(mapping, oldsize, pos);
|
||||
WARN_ON_ONCE(invalidate_inode_pages2_range(mapping, pos >> PAGE_SHIFT,
|
||||
end >> PAGE_SHIFT));
|
||||
|
||||
spin_lock(&inode->i_lock);
|
||||
if (newsize > i_size_read(inode))
|
||||
|
|
@ -402,6 +416,7 @@ static ssize_t _nfs42_proc_copy(struct file *src,
|
|||
struct nfs_server *src_server = NFS_SERVER(src_inode);
|
||||
loff_t pos_src = args->src_pos;
|
||||
loff_t pos_dst = args->dst_pos;
|
||||
loff_t oldsize_dst = i_size_read(dst_inode);
|
||||
size_t count = args->count;
|
||||
ssize_t status;
|
||||
|
||||
|
|
@ -430,6 +445,7 @@ static ssize_t _nfs42_proc_copy(struct file *src,
|
|||
return status;
|
||||
}
|
||||
|
||||
nfs_file_block_o_direct(NFS_I(dst_inode));
|
||||
status = nfs_sync_inode(dst_inode);
|
||||
if (status)
|
||||
return status;
|
||||
|
|
@ -475,7 +491,7 @@ static ssize_t _nfs42_proc_copy(struct file *src,
|
|||
goto out;
|
||||
}
|
||||
|
||||
nfs42_copy_dest_done(dst_inode, pos_dst, res->write_res.count);
|
||||
nfs42_copy_dest_done(dst, pos_dst, res->write_res.count, oldsize_dst);
|
||||
nfs_invalidate_atime(src_inode);
|
||||
status = res->write_res.count;
|
||||
out:
|
||||
|
|
@ -1242,6 +1258,7 @@ static int _nfs42_proc_clone(struct rpc_message *msg, struct file *src_f,
|
|||
struct nfs42_clone_res res = {
|
||||
.server = server,
|
||||
};
|
||||
loff_t oldsize_dst = i_size_read(dst_inode);
|
||||
int status;
|
||||
|
||||
msg->rpc_argp = &args;
|
||||
|
|
@ -1276,7 +1293,7 @@ static int _nfs42_proc_clone(struct rpc_message *msg, struct file *src_f,
|
|||
/* a zero-length count means clone to EOF in src */
|
||||
if (count == 0 && res.dst_fattr->valid & NFS_ATTR_FATTR_SIZE)
|
||||
count = nfs_size_to_loff_t(res.dst_fattr->size) - dst_offset;
|
||||
nfs42_copy_dest_done(dst_inode, dst_offset, count);
|
||||
nfs42_copy_dest_done(dst_f, dst_offset, count, oldsize_dst);
|
||||
status = nfs_post_op_update_inode(dst_inode, res.dst_fattr);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -278,9 +278,11 @@ static loff_t nfs42_remap_file_range(struct file *src_file, loff_t src_off,
|
|||
lock_two_nondirectories(src_inode, dst_inode);
|
||||
/* flush all pending writes on both src and dst so that server
|
||||
* has the latest data */
|
||||
nfs_file_block_o_direct(NFS_I(src_inode));
|
||||
ret = nfs_sync_inode(src_inode);
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
nfs_file_block_o_direct(NFS_I(dst_inode));
|
||||
ret = nfs_sync_inode(dst_inode);
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
|
|
|
|||
|
|
@ -4013,8 +4013,10 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
|
|||
res.attr_bitmask[2];
|
||||
}
|
||||
memcpy(server->attr_bitmask, res.attr_bitmask, sizeof(server->attr_bitmask));
|
||||
server->caps &= ~(NFS_CAP_ACLS | NFS_CAP_HARDLINKS |
|
||||
NFS_CAP_SYMLINKS| NFS_CAP_SECURITY_LABEL);
|
||||
server->caps &=
|
||||
~(NFS_CAP_ACLS | NFS_CAP_HARDLINKS | NFS_CAP_SYMLINKS |
|
||||
NFS_CAP_SECURITY_LABEL | NFS_CAP_FS_LOCATIONS |
|
||||
NFS_CAP_OPEN_XOR | NFS_CAP_DELEGTIME);
|
||||
server->fattr_valid = NFS_ATTR_FATTR_V4;
|
||||
if (res.attr_bitmask[0] & FATTR4_WORD0_ACL &&
|
||||
res.acl_bitmask & ACL4_SUPPORT_ALLOW_ACL)
|
||||
|
|
@ -4092,7 +4094,6 @@ int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
|
|||
};
|
||||
int err;
|
||||
|
||||
nfs_server_set_init_caps(server);
|
||||
do {
|
||||
err = nfs4_handle_exception(server,
|
||||
_nfs4_server_capabilities(server, fhandle),
|
||||
|
|
|
|||
|
|
@ -272,6 +272,7 @@ DECLARE_EVENT_CLASS(nfs_update_size_class,
|
|||
TP_ARGS(inode, new_size))
|
||||
|
||||
DEFINE_NFS_UPDATE_SIZE_EVENT(truncate);
|
||||
DEFINE_NFS_UPDATE_SIZE_EVENT(truncate_folio);
|
||||
DEFINE_NFS_UPDATE_SIZE_EVENT(wcc);
|
||||
DEFINE_NFS_UPDATE_SIZE_EVENT(update);
|
||||
DEFINE_NFS_UPDATE_SIZE_EVENT(grow);
|
||||
|
|
|
|||
|
|
@ -237,59 +237,17 @@ static void nfs_mapping_set_error(struct folio *folio, int error)
|
|||
}
|
||||
|
||||
/*
|
||||
* nfs_page_group_search_locked
|
||||
* @head - head request of page group
|
||||
* @page_offset - offset into page
|
||||
* nfs_page_covers_folio
|
||||
* @req: struct nfs_page
|
||||
*
|
||||
* Search page group with head @head to find a request that contains the
|
||||
* page offset @page_offset.
|
||||
*
|
||||
* Returns a pointer to the first matching nfs request, or NULL if no
|
||||
* match is found.
|
||||
*
|
||||
* Must be called with the page group lock held
|
||||
*/
|
||||
static struct nfs_page *
|
||||
nfs_page_group_search_locked(struct nfs_page *head, unsigned int page_offset)
|
||||
{
|
||||
struct nfs_page *req;
|
||||
|
||||
req = head;
|
||||
do {
|
||||
if (page_offset >= req->wb_pgbase &&
|
||||
page_offset < (req->wb_pgbase + req->wb_bytes))
|
||||
return req;
|
||||
|
||||
req = req->wb_this_page;
|
||||
} while (req != head);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* nfs_page_group_covers_page
|
||||
* @head - head request of page group
|
||||
*
|
||||
* Return true if the page group with head @head covers the whole page,
|
||||
* returns false otherwise
|
||||
* Return true if the request covers the whole folio.
|
||||
* Note that the caller should ensure all subrequests have been joined
|
||||
*/
|
||||
static bool nfs_page_group_covers_page(struct nfs_page *req)
|
||||
{
|
||||
unsigned int len = nfs_folio_length(nfs_page_to_folio(req));
|
||||
struct nfs_page *tmp;
|
||||
unsigned int pos = 0;
|
||||
|
||||
nfs_page_group_lock(req);
|
||||
|
||||
for (;;) {
|
||||
tmp = nfs_page_group_search_locked(req->wb_head, pos);
|
||||
if (!tmp)
|
||||
break;
|
||||
pos = tmp->wb_pgbase + tmp->wb_bytes;
|
||||
}
|
||||
|
||||
nfs_page_group_unlock(req);
|
||||
return pos >= len;
|
||||
return req->wb_pgbase == 0 && req->wb_bytes == len;
|
||||
}
|
||||
|
||||
/* We can set the PG_uptodate flag if we see that a write request
|
||||
|
|
@ -2045,6 +2003,7 @@ int nfs_wb_folio_cancel(struct inode *inode, struct folio *folio)
|
|||
* release it */
|
||||
nfs_inode_remove_request(req);
|
||||
nfs_unlock_and_release_request(req);
|
||||
folio_cancel_dirty(folio);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -276,8 +276,6 @@ EXPORT_SYMBOL_GPL(rpc_destroy_wait_queue);
|
|||
|
||||
static int rpc_wait_bit_killable(struct wait_bit_key *key, int mode)
|
||||
{
|
||||
if (unlikely(current->flags & PF_EXITING))
|
||||
return -EINTR;
|
||||
schedule();
|
||||
if (signal_pending_state(mode, current))
|
||||
return -ERESTARTSYS;
|
||||
|
|
|
|||
|
|
@ -407,9 +407,9 @@ xs_sock_recv_cmsg(struct socket *sock, unsigned int *msg_flags, int flags)
|
|||
iov_iter_kvec(&msg.msg_iter, ITER_DEST, &alert_kvec, 1,
|
||||
alert_kvec.iov_len);
|
||||
ret = sock_recvmsg(sock, &msg, flags);
|
||||
if (ret > 0 &&
|
||||
tls_get_record_type(sock->sk, &u.cmsg) == TLS_RECORD_TYPE_ALERT) {
|
||||
iov_iter_revert(&msg.msg_iter, ret);
|
||||
if (ret > 0) {
|
||||
if (tls_get_record_type(sock->sk, &u.cmsg) == TLS_RECORD_TYPE_ALERT)
|
||||
iov_iter_revert(&msg.msg_iter, ret);
|
||||
ret = xs_sock_process_cmsg(sock, &msg, msg_flags, &u.cmsg,
|
||||
-EAGAIN);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue