mirror of
https://github.com/torvalds/linux.git
synced 2025-08-15 14:11:42 +02:00
NFS client updates for Linux 6.17
Highlights include: Stable fixes: - NFS don't inherit NFS filesystem capabilities when crossing from one filesystem to another. Bugfixes: - NFS wakeup of __nfs_lookup_revalidate() needs memory barriers. - NFS improve bounds checking in nfs_fh_to_dentry(). - NFS Fix allocation errors when writing to a NFS file backed loopback device. - NFSv4: More listxattr fixes - SUNRPC: fix client handling of TLS alerts. - pNFS block/scsi layout fix for an uninitialised pointer dereference. - pNFS block/scsi layout fixes for the extent encoding, stripe mapping, and disk offset overflows. - pNFS layoutcommit work around for RPC size limitations. - pNFS/flexfiles avoid looping when handling fatal errors after layoutget. - localio: fix various race conditions. Features and cleanups: - Add NFSv4 support for retrieving the btime. - NFS: Allow folio migration for the case of mode == MIGRATE_SYNC. - NFS: Support using a kernel keyring to store TLS certificates. - NFSv4: Speed up delegation lookup using a hash table. - Assorted cleanups to remove unused variables and struct fields. - Assorted new tracepoints to improve debugging. -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEESQctxSBg8JpV8KqEZwvnipYKAPIFAmiWBC8ACgkQZwvnipYK APKTfRAAn3ETKN15+yR6wYr/wiibaL6sRzQVo8OzFSI9hEVxljX6kK2HEHXIV93T F8bjUMB24KK+Eim8zIeLf4Ke7ldbRqtbiYLJox/I12TtQ6yaiFF+xDm7Fyc7UwcT ZUl1UnGeNY30RfQ1n8O4O/suBOsTJy1rpWBWynGeQZLiNHFVDoxH4OgCXGZ5579p 3GACtToDDH9lgCBbKLM3J0nrcW5Or6BidFxT+zN/FXqeroepuvEcloiwJY7N4f/o DW436v7ep92WlaJfuypeMmdusx6+vVaYJEKw+B+UjS3tRjbDmhj2FL3su4dQVCqU JVW7TwGFL2zwfjTZjfp43ACN16goqRhX7DnTQkgD1mDnnhENqOsa0rqyIS3Wla4d W9phfGmOo2FwuVOUXH2L4k7cfPIsktsZ0s/xg+5UfcsoG2yxUxnY9HaWQGFw6fnN Fr9B7gUmaO6o1qpZ3emjecoOdQM9IqxMo39P9/72J9pWFstO9Js/kmGXcfsDo2IE z2ZYd+roj2ylcLD9mCJ94tjNsAx0ytvUl1fxNFTRLToQ3Nti+jNy22i4jrCgWfyW 5jwCjjO87CJlJC0kixEPtQXAB6HQSraZw3Qmok1Ywez3fp4+j+QDFYP7OPJPQ0LY C3R1uzvUQKqsbsE8cwYQBrG0VNzZrET6x1dxunVtcYGOkU8s4YA= =HCFp -----END PGP SIGNATURE----- Merge tag 'nfs-for-6.17-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs Pull NFS client updates from Trond Myklebust: "Highlights include: Stable fixes: - don't inherit NFS filesystem capabilities when crossing from one filesystem to another Bugfixes: - NFS wakeup of __nfs_lookup_revalidate() needs memory barriers - NFS improve bounds checking in nfs_fh_to_dentry() - NFS Fix allocation errors when writing to a NFS file backed loopback device - NFSv4: More listxattr fixes - SUNRPC: fix client handling of TLS alerts - pNFS block/scsi layout fix for an uninitialised pointer dereference - pNFS block/scsi layout fixes for the extent encoding, stripe mapping, and disk offset overflows - pNFS layoutcommit work around for RPC size limitations - pNFS/flexfiles avoid looping when handling fatal errors after layoutget - localio: fix various race conditions Features and cleanups: - Add NFSv4 support for retrieving the btime - NFS: Allow folio migration for the case of mode == MIGRATE_SYNC - NFS: Support using a kernel keyring to store TLS certificates - NFSv4: Speed up delegation lookup using a hash table - Assorted cleanups to remove unused variables and struct fields - Assorted new tracepoints to improve debugging" * tag 'nfs-for-6.17-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: (44 commits) NFS/localio: nfs_uuid_put() fix the wake up after unlinking the file NFS/localio: nfs_uuid_put() fix races with nfs_open/close_local_fh() NFS/localio: nfs_close_local_fh() fix check for file closed NFSv4: Remove duplicate lookups, capability probes and fsinfo calls NFS: Fix the setting of capabilities when automounting a new filesystem sunrpc: fix client side handling of tls alerts nfs/localio: use read_seqbegin() rather than read_seqbegin_or_lock() NFS: Fixup allocation flags for nfsiod's __GFP_NORETRY NFSv4.2: another fix for listxattr NFS: Fix filehandle bounds checking in nfs_fh_to_dentry() SUNRPC: Silence warnings about parameters not being described NFS: Clean up pnfs_put_layout_hdr()/pnfs_destroy_layout_final() NFS: Fix wakeup of __nfs_lookup_revalidate() in unblock_revalidate() NFS: use a hash table for delegation lookup NFS: track active delegations per-server NFS: move the delegation_watermark module parameter NFS: cleanup nfs_inode_reclaim_delegation NFS: cleanup error handling in nfs4_server_common_setup pNFS/flexfiles: don't attempt pnfs on fatal DS errors NFS: drop __exit from nfs_exit_keyring ...
This commit is contained in:
commit
ccc1ead23c
35 changed files with 858 additions and 562 deletions
|
@ -149,8 +149,8 @@ do_add_page_to_bio(struct bio *bio, int npg, enum req_op op, sector_t isect,
|
||||||
|
|
||||||
/* limit length to what the device mapping allows */
|
/* limit length to what the device mapping allows */
|
||||||
end = disk_addr + *len;
|
end = disk_addr + *len;
|
||||||
if (end >= map->start + map->len)
|
if (end >= map->disk_offset + map->len)
|
||||||
*len = map->start + map->len - disk_addr;
|
*len = map->disk_offset + map->len - disk_addr;
|
||||||
|
|
||||||
retry:
|
retry:
|
||||||
if (!bio) {
|
if (!bio) {
|
||||||
|
|
|
@ -257,10 +257,11 @@ static bool bl_map_stripe(struct pnfs_block_dev *dev, u64 offset,
|
||||||
struct pnfs_block_dev *child;
|
struct pnfs_block_dev *child;
|
||||||
u64 chunk;
|
u64 chunk;
|
||||||
u32 chunk_idx;
|
u32 chunk_idx;
|
||||||
|
u64 disk_chunk;
|
||||||
u64 disk_offset;
|
u64 disk_offset;
|
||||||
|
|
||||||
chunk = div_u64(offset, dev->chunk_size);
|
chunk = div_u64(offset, dev->chunk_size);
|
||||||
div_u64_rem(chunk, dev->nr_children, &chunk_idx);
|
disk_chunk = div_u64_rem(chunk, dev->nr_children, &chunk_idx);
|
||||||
|
|
||||||
if (chunk_idx >= dev->nr_children) {
|
if (chunk_idx >= dev->nr_children) {
|
||||||
dprintk("%s: invalid chunk idx %d (%lld/%lld)\n",
|
dprintk("%s: invalid chunk idx %d (%lld/%lld)\n",
|
||||||
|
@ -273,7 +274,7 @@ static bool bl_map_stripe(struct pnfs_block_dev *dev, u64 offset,
|
||||||
offset = chunk * dev->chunk_size;
|
offset = chunk * dev->chunk_size;
|
||||||
|
|
||||||
/* disk offset of the stripe */
|
/* disk offset of the stripe */
|
||||||
disk_offset = div_u64(offset, dev->nr_children);
|
disk_offset = disk_chunk * dev->chunk_size;
|
||||||
|
|
||||||
child = &dev->children[chunk_idx];
|
child = &dev->children[chunk_idx];
|
||||||
child->map(child, disk_offset, map);
|
child->map(child, disk_offset, map);
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include <linux/vmalloc.h>
|
#include <linux/vmalloc.h>
|
||||||
|
|
||||||
#include "blocklayout.h"
|
#include "blocklayout.h"
|
||||||
|
#include "../nfs4trace.h"
|
||||||
|
|
||||||
#define NFSDBG_FACILITY NFSDBG_PNFS_LD
|
#define NFSDBG_FACILITY NFSDBG_PNFS_LD
|
||||||
|
|
||||||
|
@ -520,10 +521,71 @@ static __be32 *encode_scsi_range(struct pnfs_block_extent *be, __be32 *p)
|
||||||
return xdr_encode_hyper(p, be->be_length << SECTOR_SHIFT);
|
return xdr_encode_hyper(p, be->be_length << SECTOR_SHIFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ext_tree_encode_commit(struct pnfs_block_layout *bl, __be32 *p,
|
/**
|
||||||
|
* ext_tree_try_encode_commit - try to encode all extents into the buffer
|
||||||
|
* @bl: pointer to the layout
|
||||||
|
* @p: pointer to the output buffer
|
||||||
|
* @buffer_size: size of the output buffer
|
||||||
|
* @count: output pointer to the number of encoded extents
|
||||||
|
* @lastbyte: output pointer to the last written byte
|
||||||
|
*
|
||||||
|
* Return values:
|
||||||
|
* %0: Success, all required extents encoded, outputs are valid
|
||||||
|
* %-ENOSPC: Buffer too small, nothing encoded, outputs are invalid
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
ext_tree_try_encode_commit(struct pnfs_block_layout *bl, __be32 *p,
|
||||||
size_t buffer_size, size_t *count, __u64 *lastbyte)
|
size_t buffer_size, size_t *count, __u64 *lastbyte)
|
||||||
{
|
{
|
||||||
struct pnfs_block_extent *be;
|
struct pnfs_block_extent *be;
|
||||||
|
|
||||||
|
spin_lock(&bl->bl_ext_lock);
|
||||||
|
for (be = ext_tree_first(&bl->bl_ext_rw); be; be = ext_tree_next(be)) {
|
||||||
|
if (be->be_state != PNFS_BLOCK_INVALID_DATA ||
|
||||||
|
be->be_tag != EXTENT_WRITTEN)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
(*count)++;
|
||||||
|
if (ext_tree_layoutupdate_size(bl, *count) > buffer_size) {
|
||||||
|
spin_unlock(&bl->bl_ext_lock);
|
||||||
|
return -ENOSPC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (be = ext_tree_first(&bl->bl_ext_rw); be; be = ext_tree_next(be)) {
|
||||||
|
if (be->be_state != PNFS_BLOCK_INVALID_DATA ||
|
||||||
|
be->be_tag != EXTENT_WRITTEN)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (bl->bl_scsi_layout)
|
||||||
|
p = encode_scsi_range(be, p);
|
||||||
|
else
|
||||||
|
p = encode_block_extent(be, p);
|
||||||
|
be->be_tag = EXTENT_COMMITTING;
|
||||||
|
}
|
||||||
|
*lastbyte = (bl->bl_lwb != 0) ? bl->bl_lwb - 1 : U64_MAX;
|
||||||
|
bl->bl_lwb = 0;
|
||||||
|
spin_unlock(&bl->bl_ext_lock);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ext_tree_encode_commit - encode as much as possible extents into the buffer
|
||||||
|
* @bl: pointer to the layout
|
||||||
|
* @p: pointer to the output buffer
|
||||||
|
* @buffer_size: size of the output buffer
|
||||||
|
* @count: output pointer to the number of encoded extents
|
||||||
|
* @lastbyte: output pointer to the last written byte
|
||||||
|
*
|
||||||
|
* Return values:
|
||||||
|
* %0: Success, all required extents encoded, outputs are valid
|
||||||
|
* %-ENOSPC: Buffer too small, some extents are encoded, outputs are valid
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
ext_tree_encode_commit(struct pnfs_block_layout *bl, __be32 *p,
|
||||||
|
size_t buffer_size, size_t *count, __u64 *lastbyte)
|
||||||
|
{
|
||||||
|
struct pnfs_block_extent *be, *be_prev;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
spin_lock(&bl->bl_ext_lock);
|
spin_lock(&bl->bl_ext_lock);
|
||||||
|
@ -534,9 +596,9 @@ static int ext_tree_encode_commit(struct pnfs_block_layout *bl, __be32 *p,
|
||||||
|
|
||||||
(*count)++;
|
(*count)++;
|
||||||
if (ext_tree_layoutupdate_size(bl, *count) > buffer_size) {
|
if (ext_tree_layoutupdate_size(bl, *count) > buffer_size) {
|
||||||
/* keep counting.. */
|
(*count)--;
|
||||||
ret = -ENOSPC;
|
ret = -ENOSPC;
|
||||||
continue;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bl->bl_scsi_layout)
|
if (bl->bl_scsi_layout)
|
||||||
|
@ -544,14 +606,30 @@ static int ext_tree_encode_commit(struct pnfs_block_layout *bl, __be32 *p,
|
||||||
else
|
else
|
||||||
p = encode_block_extent(be, p);
|
p = encode_block_extent(be, p);
|
||||||
be->be_tag = EXTENT_COMMITTING;
|
be->be_tag = EXTENT_COMMITTING;
|
||||||
|
be_prev = be;
|
||||||
|
}
|
||||||
|
if (!ret) {
|
||||||
|
*lastbyte = (bl->bl_lwb != 0) ? bl->bl_lwb - 1 : U64_MAX;
|
||||||
|
bl->bl_lwb = 0;
|
||||||
|
} else {
|
||||||
|
*lastbyte = be_prev->be_f_offset + be_prev->be_length;
|
||||||
|
*lastbyte <<= SECTOR_SHIFT;
|
||||||
|
*lastbyte -= 1;
|
||||||
}
|
}
|
||||||
*lastbyte = bl->bl_lwb - 1;
|
|
||||||
bl->bl_lwb = 0;
|
|
||||||
spin_unlock(&bl->bl_ext_lock);
|
spin_unlock(&bl->bl_ext_lock);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ext_tree_prepare_commit - encode extents that need to be committed
|
||||||
|
* @arg: layout commit data
|
||||||
|
*
|
||||||
|
* Return values:
|
||||||
|
* %0: Success, all required extents are encoded
|
||||||
|
* %-ENOSPC: Some extents are encoded, but not all, due to RPC size limit
|
||||||
|
* %-ENOMEM: Out of memory, extents not encoded
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
ext_tree_prepare_commit(struct nfs4_layoutcommit_args *arg)
|
ext_tree_prepare_commit(struct nfs4_layoutcommit_args *arg)
|
||||||
{
|
{
|
||||||
|
@ -560,20 +638,18 @@ ext_tree_prepare_commit(struct nfs4_layoutcommit_args *arg)
|
||||||
__be32 *start_p;
|
__be32 *start_p;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
dprintk("%s enter\n", __func__);
|
|
||||||
|
|
||||||
arg->layoutupdate_page = alloc_page(GFP_NOFS);
|
arg->layoutupdate_page = alloc_page(GFP_NOFS);
|
||||||
if (!arg->layoutupdate_page)
|
if (!arg->layoutupdate_page)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
start_p = page_address(arg->layoutupdate_page);
|
start_p = page_address(arg->layoutupdate_page);
|
||||||
arg->layoutupdate_pages = &arg->layoutupdate_page;
|
arg->layoutupdate_pages = &arg->layoutupdate_page;
|
||||||
|
|
||||||
retry:
|
ret = ext_tree_try_encode_commit(bl, start_p + 1, buffer_size,
|
||||||
ret = ext_tree_encode_commit(bl, start_p + 1, buffer_size, &count, &arg->lastbytewritten);
|
&count, &arg->lastbytewritten);
|
||||||
if (unlikely(ret)) {
|
if (unlikely(ret)) {
|
||||||
ext_tree_free_commitdata(arg, buffer_size);
|
ext_tree_free_commitdata(arg, buffer_size);
|
||||||
|
|
||||||
buffer_size = ext_tree_layoutupdate_size(bl, count);
|
buffer_size = NFS_SERVER(arg->inode)->wsize;
|
||||||
count = 0;
|
count = 0;
|
||||||
|
|
||||||
arg->layoutupdate_pages =
|
arg->layoutupdate_pages =
|
||||||
|
@ -588,7 +664,8 @@ retry:
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
goto retry;
|
ret = ext_tree_encode_commit(bl, start_p + 1, buffer_size,
|
||||||
|
&count, &arg->lastbytewritten);
|
||||||
}
|
}
|
||||||
|
|
||||||
*start_p = cpu_to_be32(count);
|
*start_p = cpu_to_be32(count);
|
||||||
|
@ -607,8 +684,9 @@ retry:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dprintk("%s found %zu ranges\n", __func__, count);
|
trace_bl_ext_tree_prepare_commit(ret, count,
|
||||||
return 0;
|
arg->lastbytewritten, !!ret);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -682,6 +682,44 @@ struct nfs_client *nfs_init_client(struct nfs_client *clp,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(nfs_init_client);
|
EXPORT_SYMBOL_GPL(nfs_init_client);
|
||||||
|
|
||||||
|
static void nfs4_server_set_init_caps(struct nfs_server *server)
|
||||||
|
{
|
||||||
|
#if IS_ENABLED(CONFIG_NFS_V4)
|
||||||
|
/* Set the basic capabilities */
|
||||||
|
server->caps = server->nfs_client->cl_mvops->init_caps;
|
||||||
|
if (server->flags & NFS_MOUNT_NORDIRPLUS)
|
||||||
|
server->caps &= ~NFS_CAP_READDIRPLUS;
|
||||||
|
if (server->nfs_client->cl_proto == XPRT_TRANSPORT_RDMA)
|
||||||
|
server->caps &= ~NFS_CAP_READ_PLUS;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Don't use NFS uid/gid mapping if we're using AUTH_SYS or lower
|
||||||
|
* authentication.
|
||||||
|
*/
|
||||||
|
if (nfs4_disable_idmapping &&
|
||||||
|
server->client->cl_auth->au_flavor == RPC_AUTH_UNIX)
|
||||||
|
server->caps |= NFS_CAP_UIDGID_NOMAP;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfs_server_set_init_caps(struct nfs_server *server)
|
||||||
|
{
|
||||||
|
switch (server->nfs_client->rpc_ops->version) {
|
||||||
|
case 2:
|
||||||
|
server->caps = NFS_CAP_HARDLINKS | NFS_CAP_SYMLINKS;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
server->caps = NFS_CAP_HARDLINKS | NFS_CAP_SYMLINKS;
|
||||||
|
if (!(server->flags & NFS_MOUNT_NORDIRPLUS))
|
||||||
|
server->caps |= NFS_CAP_READDIRPLUS;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
nfs4_server_set_init_caps(server);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(nfs_server_set_init_caps);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create a version 2 or 3 client
|
* Create a version 2 or 3 client
|
||||||
*/
|
*/
|
||||||
|
@ -726,7 +764,6 @@ static int nfs_init_server(struct nfs_server *server,
|
||||||
/* Initialise the client representation from the mount data */
|
/* Initialise the client representation from the mount data */
|
||||||
server->flags = ctx->flags;
|
server->flags = ctx->flags;
|
||||||
server->options = ctx->options;
|
server->options = ctx->options;
|
||||||
server->caps |= NFS_CAP_HARDLINKS | NFS_CAP_SYMLINKS;
|
|
||||||
|
|
||||||
switch (clp->rpc_ops->version) {
|
switch (clp->rpc_ops->version) {
|
||||||
case 2:
|
case 2:
|
||||||
|
@ -762,6 +799,8 @@ static int nfs_init_server(struct nfs_server *server,
|
||||||
if (error < 0)
|
if (error < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
nfs_server_set_init_caps(server);
|
||||||
|
|
||||||
/* Preserve the values of mount_server-related mount options */
|
/* Preserve the values of mount_server-related mount options */
|
||||||
if (ctx->mount_server.addrlen) {
|
if (ctx->mount_server.addrlen) {
|
||||||
memcpy(&server->mountd_address, &ctx->mount_server.address,
|
memcpy(&server->mountd_address, &ctx->mount_server.address,
|
||||||
|
@ -814,7 +853,6 @@ static void nfs_server_set_fsinfo(struct nfs_server *server,
|
||||||
server->wsize = max_rpc_payload;
|
server->wsize = max_rpc_payload;
|
||||||
if (server->wsize > NFS_MAX_FILE_IO_SIZE)
|
if (server->wsize > NFS_MAX_FILE_IO_SIZE)
|
||||||
server->wsize = NFS_MAX_FILE_IO_SIZE;
|
server->wsize = NFS_MAX_FILE_IO_SIZE;
|
||||||
server->wpages = (server->wsize + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
|
||||||
|
|
||||||
server->wtmult = nfs_block_bits(fsinfo->wtmult, NULL);
|
server->wtmult = nfs_block_bits(fsinfo->wtmult, NULL);
|
||||||
|
|
||||||
|
@ -831,7 +869,6 @@ static void nfs_server_set_fsinfo(struct nfs_server *server,
|
||||||
|
|
||||||
server->maxfilesize = fsinfo->maxfilesize;
|
server->maxfilesize = fsinfo->maxfilesize;
|
||||||
|
|
||||||
server->time_delta = fsinfo->time_delta;
|
|
||||||
server->change_attr_type = fsinfo->change_attr_type;
|
server->change_attr_type = fsinfo->change_attr_type;
|
||||||
|
|
||||||
server->clone_blksize = fsinfo->clone_blksize;
|
server->clone_blksize = fsinfo->clone_blksize;
|
||||||
|
@ -936,7 +973,6 @@ void nfs_server_copy_userdata(struct nfs_server *target, struct nfs_server *sour
|
||||||
target->acregmax = source->acregmax;
|
target->acregmax = source->acregmax;
|
||||||
target->acdirmin = source->acdirmin;
|
target->acdirmin = source->acdirmin;
|
||||||
target->acdirmax = source->acdirmax;
|
target->acdirmax = source->acdirmax;
|
||||||
target->caps = source->caps;
|
|
||||||
target->options = source->options;
|
target->options = source->options;
|
||||||
target->auth_info = source->auth_info;
|
target->auth_info = source->auth_info;
|
||||||
target->port = source->port;
|
target->port = source->port;
|
||||||
|
@ -1007,6 +1043,7 @@ struct nfs_server *nfs_alloc_server(void)
|
||||||
INIT_LIST_HEAD(&server->ss_src_copies);
|
INIT_LIST_HEAD(&server->ss_src_copies);
|
||||||
|
|
||||||
atomic_set(&server->active, 0);
|
atomic_set(&server->active, 0);
|
||||||
|
atomic_long_set(&server->nr_active_delegations, 0);
|
||||||
|
|
||||||
server->io_stats = nfs_alloc_iostats();
|
server->io_stats = nfs_alloc_iostats();
|
||||||
if (!server->io_stats) {
|
if (!server->io_stats) {
|
||||||
|
@ -1170,6 +1207,8 @@ struct nfs_server *nfs_clone_server(struct nfs_server *source,
|
||||||
if (error < 0)
|
if (error < 0)
|
||||||
goto out_free_server;
|
goto out_free_server;
|
||||||
|
|
||||||
|
nfs_server_set_init_caps(server);
|
||||||
|
|
||||||
/* probe the filesystem info for this server filesystem */
|
/* probe the filesystem info for this server filesystem */
|
||||||
error = nfs_probe_server(server, fh);
|
error = nfs_probe_server(server, fh);
|
||||||
if (error < 0)
|
if (error < 0)
|
||||||
|
|
|
@ -27,8 +27,15 @@
|
||||||
|
|
||||||
#define NFS_DEFAULT_DELEGATION_WATERMARK (5000U)
|
#define NFS_DEFAULT_DELEGATION_WATERMARK (5000U)
|
||||||
|
|
||||||
static atomic_long_t nfs_active_delegations;
|
|
||||||
static unsigned nfs_delegation_watermark = NFS_DEFAULT_DELEGATION_WATERMARK;
|
static unsigned nfs_delegation_watermark = NFS_DEFAULT_DELEGATION_WATERMARK;
|
||||||
|
module_param_named(delegation_watermark, nfs_delegation_watermark, uint, 0644);
|
||||||
|
|
||||||
|
static struct hlist_head *nfs_delegation_hash(struct nfs_server *server,
|
||||||
|
const struct nfs_fh *fhandle)
|
||||||
|
{
|
||||||
|
return server->delegation_hash_table +
|
||||||
|
(nfs_fhandle_hash(fhandle) & server->delegation_hash_mask);
|
||||||
|
}
|
||||||
|
|
||||||
static void __nfs_free_delegation(struct nfs_delegation *delegation)
|
static void __nfs_free_delegation(struct nfs_delegation *delegation)
|
||||||
{
|
{
|
||||||
|
@ -37,11 +44,12 @@ static void __nfs_free_delegation(struct nfs_delegation *delegation)
|
||||||
kfree_rcu(delegation, rcu);
|
kfree_rcu(delegation, rcu);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nfs_mark_delegation_revoked(struct nfs_delegation *delegation)
|
static void nfs_mark_delegation_revoked(struct nfs_server *server,
|
||||||
|
struct nfs_delegation *delegation)
|
||||||
{
|
{
|
||||||
if (!test_and_set_bit(NFS_DELEGATION_REVOKED, &delegation->flags)) {
|
if (!test_and_set_bit(NFS_DELEGATION_REVOKED, &delegation->flags)) {
|
||||||
delegation->stateid.type = NFS4_INVALID_STATEID_TYPE;
|
delegation->stateid.type = NFS4_INVALID_STATEID_TYPE;
|
||||||
atomic_long_dec(&nfs_active_delegations);
|
atomic_long_dec(&server->nr_active_delegations);
|
||||||
if (!test_bit(NFS_DELEGATION_RETURNING, &delegation->flags))
|
if (!test_bit(NFS_DELEGATION_RETURNING, &delegation->flags))
|
||||||
nfs_clear_verifier_delegated(delegation->inode);
|
nfs_clear_verifier_delegated(delegation->inode);
|
||||||
}
|
}
|
||||||
|
@ -59,9 +67,10 @@ static void nfs_put_delegation(struct nfs_delegation *delegation)
|
||||||
__nfs_free_delegation(delegation);
|
__nfs_free_delegation(delegation);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nfs_free_delegation(struct nfs_delegation *delegation)
|
static void nfs_free_delegation(struct nfs_server *server,
|
||||||
|
struct nfs_delegation *delegation)
|
||||||
{
|
{
|
||||||
nfs_mark_delegation_revoked(delegation);
|
nfs_mark_delegation_revoked(server, delegation);
|
||||||
nfs_put_delegation(delegation);
|
nfs_put_delegation(delegation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,34 +246,34 @@ void nfs_inode_reclaim_delegation(struct inode *inode, const struct cred *cred,
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
delegation = rcu_dereference(NFS_I(inode)->delegation);
|
delegation = rcu_dereference(NFS_I(inode)->delegation);
|
||||||
if (delegation != NULL) {
|
if (!delegation) {
|
||||||
spin_lock(&delegation->lock);
|
|
||||||
nfs4_stateid_copy(&delegation->stateid, stateid);
|
|
||||||
delegation->type = type;
|
|
||||||
delegation->pagemod_limit = pagemod_limit;
|
|
||||||
oldcred = delegation->cred;
|
|
||||||
delegation->cred = get_cred(cred);
|
|
||||||
switch (deleg_type) {
|
|
||||||
case NFS4_OPEN_DELEGATE_READ_ATTRS_DELEG:
|
|
||||||
case NFS4_OPEN_DELEGATE_WRITE_ATTRS_DELEG:
|
|
||||||
set_bit(NFS_DELEGATION_DELEGTIME, &delegation->flags);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
clear_bit(NFS_DELEGATION_DELEGTIME, &delegation->flags);
|
|
||||||
}
|
|
||||||
clear_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags);
|
|
||||||
if (test_and_clear_bit(NFS_DELEGATION_REVOKED,
|
|
||||||
&delegation->flags))
|
|
||||||
atomic_long_inc(&nfs_active_delegations);
|
|
||||||
spin_unlock(&delegation->lock);
|
|
||||||
rcu_read_unlock();
|
|
||||||
put_cred(oldcred);
|
|
||||||
trace_nfs4_reclaim_delegation(inode, type);
|
|
||||||
} else {
|
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
nfs_inode_set_delegation(inode, cred, type, stateid,
|
nfs_inode_set_delegation(inode, cred, type, stateid,
|
||||||
pagemod_limit, deleg_type);
|
pagemod_limit, deleg_type);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spin_lock(&delegation->lock);
|
||||||
|
nfs4_stateid_copy(&delegation->stateid, stateid);
|
||||||
|
delegation->type = type;
|
||||||
|
delegation->pagemod_limit = pagemod_limit;
|
||||||
|
oldcred = delegation->cred;
|
||||||
|
delegation->cred = get_cred(cred);
|
||||||
|
switch (deleg_type) {
|
||||||
|
case NFS4_OPEN_DELEGATE_READ_ATTRS_DELEG:
|
||||||
|
case NFS4_OPEN_DELEGATE_WRITE_ATTRS_DELEG:
|
||||||
|
set_bit(NFS_DELEGATION_DELEGTIME, &delegation->flags);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
clear_bit(NFS_DELEGATION_DELEGTIME, &delegation->flags);
|
||||||
|
}
|
||||||
|
clear_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags);
|
||||||
|
if (test_and_clear_bit(NFS_DELEGATION_REVOKED, &delegation->flags))
|
||||||
|
atomic_long_inc(&NFS_SERVER(inode)->nr_active_delegations);
|
||||||
|
spin_unlock(&delegation->lock);
|
||||||
|
rcu_read_unlock();
|
||||||
|
put_cred(oldcred);
|
||||||
|
trace_nfs4_reclaim_delegation(inode, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nfs_do_return_delegation(struct inode *inode,
|
static int nfs_do_return_delegation(struct inode *inode,
|
||||||
|
@ -355,6 +364,8 @@ nfs_detach_delegation_locked(struct nfs_inode *nfsi,
|
||||||
rcu_dereference_protected(nfsi->delegation,
|
rcu_dereference_protected(nfsi->delegation,
|
||||||
lockdep_is_held(&clp->cl_lock));
|
lockdep_is_held(&clp->cl_lock));
|
||||||
|
|
||||||
|
trace_nfs4_detach_delegation(&nfsi->vfs_inode, delegation->type);
|
||||||
|
|
||||||
if (deleg_cur == NULL || delegation != deleg_cur)
|
if (deleg_cur == NULL || delegation != deleg_cur)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -363,6 +374,7 @@ nfs_detach_delegation_locked(struct nfs_inode *nfsi,
|
||||||
spin_unlock(&delegation->lock);
|
spin_unlock(&delegation->lock);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
hlist_del_init_rcu(&delegation->hash);
|
||||||
list_del_rcu(&delegation->super_list);
|
list_del_rcu(&delegation->super_list);
|
||||||
delegation->inode = NULL;
|
delegation->inode = NULL;
|
||||||
rcu_assign_pointer(nfsi->delegation, NULL);
|
rcu_assign_pointer(nfsi->delegation, NULL);
|
||||||
|
@ -410,7 +422,8 @@ nfs_update_delegation_cred(struct nfs_delegation *delegation,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
nfs_update_inplace_delegation(struct nfs_delegation *delegation,
|
nfs_update_inplace_delegation(struct nfs_server *server,
|
||||||
|
struct nfs_delegation *delegation,
|
||||||
const struct nfs_delegation *update)
|
const struct nfs_delegation *update)
|
||||||
{
|
{
|
||||||
if (nfs4_stateid_is_newer(&update->stateid, &delegation->stateid)) {
|
if (nfs4_stateid_is_newer(&update->stateid, &delegation->stateid)) {
|
||||||
|
@ -423,7 +436,7 @@ nfs_update_inplace_delegation(struct nfs_delegation *delegation,
|
||||||
nfs_update_delegation_cred(delegation, update->cred);
|
nfs_update_delegation_cred(delegation, update->cred);
|
||||||
/* smp_mb__before_atomic() is implicit due to xchg() */
|
/* smp_mb__before_atomic() is implicit due to xchg() */
|
||||||
clear_bit(NFS_DELEGATION_REVOKED, &delegation->flags);
|
clear_bit(NFS_DELEGATION_REVOKED, &delegation->flags);
|
||||||
atomic_long_inc(&nfs_active_delegations);
|
atomic_long_inc(&server->nr_active_delegations);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -478,7 +491,7 @@ int nfs_inode_set_delegation(struct inode *inode, const struct cred *cred,
|
||||||
if (nfs4_stateid_match_other(&old_delegation->stateid,
|
if (nfs4_stateid_match_other(&old_delegation->stateid,
|
||||||
&delegation->stateid)) {
|
&delegation->stateid)) {
|
||||||
spin_lock(&old_delegation->lock);
|
spin_lock(&old_delegation->lock);
|
||||||
nfs_update_inplace_delegation(old_delegation,
|
nfs_update_inplace_delegation(server, old_delegation,
|
||||||
delegation);
|
delegation);
|
||||||
spin_unlock(&old_delegation->lock);
|
spin_unlock(&old_delegation->lock);
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -524,10 +537,12 @@ add_new:
|
||||||
spin_unlock(&inode->i_lock);
|
spin_unlock(&inode->i_lock);
|
||||||
|
|
||||||
list_add_tail_rcu(&delegation->super_list, &server->delegations);
|
list_add_tail_rcu(&delegation->super_list, &server->delegations);
|
||||||
|
hlist_add_head_rcu(&delegation->hash,
|
||||||
|
nfs_delegation_hash(server, &NFS_I(inode)->fh));
|
||||||
rcu_assign_pointer(nfsi->delegation, delegation);
|
rcu_assign_pointer(nfsi->delegation, delegation);
|
||||||
delegation = NULL;
|
delegation = NULL;
|
||||||
|
|
||||||
atomic_long_inc(&nfs_active_delegations);
|
atomic_long_inc(&server->nr_active_delegations);
|
||||||
|
|
||||||
trace_nfs4_set_delegation(inode, type);
|
trace_nfs4_set_delegation(inode, type);
|
||||||
|
|
||||||
|
@ -541,7 +556,7 @@ out:
|
||||||
__nfs_free_delegation(delegation);
|
__nfs_free_delegation(delegation);
|
||||||
if (freeme != NULL) {
|
if (freeme != NULL) {
|
||||||
nfs_do_return_delegation(inode, freeme, 0);
|
nfs_do_return_delegation(inode, freeme, 0);
|
||||||
nfs_free_delegation(freeme);
|
nfs_free_delegation(server, freeme);
|
||||||
}
|
}
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
@ -592,6 +607,8 @@ static bool nfs_delegation_need_return(struct nfs_delegation *delegation)
|
||||||
{
|
{
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
|
|
||||||
|
trace_nfs_delegation_need_return(delegation);
|
||||||
|
|
||||||
if (test_and_clear_bit(NFS_DELEGATION_RETURN, &delegation->flags))
|
if (test_and_clear_bit(NFS_DELEGATION_RETURN, &delegation->flags))
|
||||||
ret = true;
|
ret = true;
|
||||||
if (test_bit(NFS_DELEGATION_RETURNING, &delegation->flags) ||
|
if (test_bit(NFS_DELEGATION_RETURNING, &delegation->flags) ||
|
||||||
|
@ -751,7 +768,7 @@ void nfs_inode_evict_delegation(struct inode *inode)
|
||||||
set_bit(NFS_DELEGATION_RETURNING, &delegation->flags);
|
set_bit(NFS_DELEGATION_RETURNING, &delegation->flags);
|
||||||
set_bit(NFS_DELEGATION_INODE_FREEING, &delegation->flags);
|
set_bit(NFS_DELEGATION_INODE_FREEING, &delegation->flags);
|
||||||
nfs_do_return_delegation(inode, delegation, 1);
|
nfs_do_return_delegation(inode, delegation, 1);
|
||||||
nfs_free_delegation(delegation);
|
nfs_free_delegation(NFS_SERVER(inode), delegation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -837,7 +854,8 @@ void nfs4_inode_return_delegation_on_close(struct inode *inode)
|
||||||
if (!delegation)
|
if (!delegation)
|
||||||
goto out;
|
goto out;
|
||||||
if (test_bit(NFS_DELEGATION_RETURN_IF_CLOSED, &delegation->flags) ||
|
if (test_bit(NFS_DELEGATION_RETURN_IF_CLOSED, &delegation->flags) ||
|
||||||
atomic_long_read(&nfs_active_delegations) >= nfs_delegation_watermark) {
|
atomic_long_read(&NFS_SERVER(inode)->nr_active_delegations) >=
|
||||||
|
nfs_delegation_watermark) {
|
||||||
spin_lock(&delegation->lock);
|
spin_lock(&delegation->lock);
|
||||||
if (delegation->inode &&
|
if (delegation->inode &&
|
||||||
list_empty(&NFS_I(inode)->open_files) &&
|
list_empty(&NFS_I(inode)->open_files) &&
|
||||||
|
@ -1013,7 +1031,7 @@ static void nfs_revoke_delegation(struct inode *inode,
|
||||||
}
|
}
|
||||||
spin_unlock(&delegation->lock);
|
spin_unlock(&delegation->lock);
|
||||||
}
|
}
|
||||||
nfs_mark_delegation_revoked(delegation);
|
nfs_mark_delegation_revoked(NFS_SERVER(inode), delegation);
|
||||||
ret = true;
|
ret = true;
|
||||||
out:
|
out:
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
|
@ -1045,7 +1063,7 @@ void nfs_delegation_mark_returned(struct inode *inode,
|
||||||
delegation->stateid.seqid = stateid->seqid;
|
delegation->stateid.seqid = stateid->seqid;
|
||||||
}
|
}
|
||||||
|
|
||||||
nfs_mark_delegation_revoked(delegation);
|
nfs_mark_delegation_revoked(NFS_SERVER(inode), delegation);
|
||||||
clear_bit(NFS_DELEGATION_RETURNING, &delegation->flags);
|
clear_bit(NFS_DELEGATION_RETURNING, &delegation->flags);
|
||||||
spin_unlock(&delegation->lock);
|
spin_unlock(&delegation->lock);
|
||||||
if (nfs_detach_delegation(NFS_I(inode), delegation, NFS_SERVER(inode)))
|
if (nfs_detach_delegation(NFS_I(inode), delegation, NFS_SERVER(inode)))
|
||||||
|
@ -1158,11 +1176,12 @@ static struct inode *
|
||||||
nfs_delegation_find_inode_server(struct nfs_server *server,
|
nfs_delegation_find_inode_server(struct nfs_server *server,
|
||||||
const struct nfs_fh *fhandle)
|
const struct nfs_fh *fhandle)
|
||||||
{
|
{
|
||||||
|
struct hlist_head *head = nfs_delegation_hash(server, fhandle);
|
||||||
struct nfs_delegation *delegation;
|
struct nfs_delegation *delegation;
|
||||||
struct super_block *freeme = NULL;
|
struct super_block *freeme = NULL;
|
||||||
struct inode *res = NULL;
|
struct inode *res = NULL;
|
||||||
|
|
||||||
list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
|
hlist_for_each_entry_rcu(delegation, head, hash) {
|
||||||
spin_lock(&delegation->lock);
|
spin_lock(&delegation->lock);
|
||||||
if (delegation->inode != NULL &&
|
if (delegation->inode != NULL &&
|
||||||
!test_bit(NFS_DELEGATION_REVOKED, &delegation->flags) &&
|
!test_bit(NFS_DELEGATION_REVOKED, &delegation->flags) &&
|
||||||
|
@ -1265,7 +1284,7 @@ restart:
|
||||||
if (delegation != NULL) {
|
if (delegation != NULL) {
|
||||||
if (nfs_detach_delegation(NFS_I(inode), delegation,
|
if (nfs_detach_delegation(NFS_I(inode), delegation,
|
||||||
server) != NULL)
|
server) != NULL)
|
||||||
nfs_free_delegation(delegation);
|
nfs_free_delegation(server, delegation);
|
||||||
/* Match nfs_start_delegation_return_locked */
|
/* Match nfs_start_delegation_return_locked */
|
||||||
nfs_put_delegation(delegation);
|
nfs_put_delegation(delegation);
|
||||||
}
|
}
|
||||||
|
@ -1570,4 +1589,17 @@ out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
module_param_named(delegation_watermark, nfs_delegation_watermark, uint, 0644);
|
int nfs4_delegation_hash_alloc(struct nfs_server *server)
|
||||||
|
{
|
||||||
|
int delegation_buckets, i;
|
||||||
|
|
||||||
|
delegation_buckets = roundup_pow_of_two(nfs_delegation_watermark / 16);
|
||||||
|
server->delegation_hash_mask = delegation_buckets - 1;
|
||||||
|
server->delegation_hash_table = kmalloc_array(delegation_buckets,
|
||||||
|
sizeof(*server->delegation_hash_table), GFP_KERNEL);
|
||||||
|
if (!server->delegation_hash_table)
|
||||||
|
return -ENOMEM;
|
||||||
|
for (i = 0; i < delegation_buckets; i++)
|
||||||
|
INIT_HLIST_HEAD(&server->delegation_hash_table[i]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
* NFSv4 delegation
|
* NFSv4 delegation
|
||||||
*/
|
*/
|
||||||
struct nfs_delegation {
|
struct nfs_delegation {
|
||||||
|
struct hlist_node hash;
|
||||||
struct list_head super_list;
|
struct list_head super_list;
|
||||||
const struct cred *cred;
|
const struct cred *cred;
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
|
@ -123,4 +124,6 @@ static inline int nfs_have_delegated_mtime(struct inode *inode)
|
||||||
NFS_DELEGATION_FLAG_TIME);
|
NFS_DELEGATION_FLAG_TIME);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int nfs4_delegation_hash_alloc(struct nfs_server *server);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1828,9 +1828,7 @@ static void block_revalidate(struct dentry *dentry)
|
||||||
|
|
||||||
static void unblock_revalidate(struct dentry *dentry)
|
static void unblock_revalidate(struct dentry *dentry)
|
||||||
{
|
{
|
||||||
/* store_release ensures wait_var_event() sees the update */
|
store_release_wake_up(&dentry->d_fsdata, NULL);
|
||||||
smp_store_release(&dentry->d_fsdata, NULL);
|
|
||||||
wake_up_var(&dentry->d_fsdata);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -66,14 +66,21 @@ nfs_fh_to_dentry(struct super_block *sb, struct fid *fid,
|
||||||
{
|
{
|
||||||
struct nfs_fattr *fattr = NULL;
|
struct nfs_fattr *fattr = NULL;
|
||||||
struct nfs_fh *server_fh = nfs_exp_embedfh(fid->raw);
|
struct nfs_fh *server_fh = nfs_exp_embedfh(fid->raw);
|
||||||
size_t fh_size = offsetof(struct nfs_fh, data) + server_fh->size;
|
size_t fh_size = offsetof(struct nfs_fh, data);
|
||||||
const struct nfs_rpc_ops *rpc_ops;
|
const struct nfs_rpc_ops *rpc_ops;
|
||||||
struct dentry *dentry;
|
struct dentry *dentry;
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
int len = EMBED_FH_OFF + XDR_QUADLEN(fh_size);
|
int len = EMBED_FH_OFF;
|
||||||
u32 *p = fid->raw;
|
u32 *p = fid->raw;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
/* Initial check of bounds */
|
||||||
|
if (fh_len < len + XDR_QUADLEN(fh_size) ||
|
||||||
|
fh_len > XDR_QUADLEN(NFS_MAXFHSIZE))
|
||||||
|
return NULL;
|
||||||
|
/* Calculate embedded filehandle size */
|
||||||
|
fh_size += server_fh->size;
|
||||||
|
len += XDR_QUADLEN(fh_size);
|
||||||
/* NULL translates to ESTALE */
|
/* NULL translates to ESTALE */
|
||||||
if (fh_len < len || fh_type != len)
|
if (fh_len < len || fh_type != len)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
@ -762,14 +762,14 @@ ff_layout_choose_ds_for_read(struct pnfs_layout_segment *lseg,
|
||||||
{
|
{
|
||||||
struct nfs4_ff_layout_segment *fls = FF_LAYOUT_LSEG(lseg);
|
struct nfs4_ff_layout_segment *fls = FF_LAYOUT_LSEG(lseg);
|
||||||
struct nfs4_ff_layout_mirror *mirror;
|
struct nfs4_ff_layout_mirror *mirror;
|
||||||
struct nfs4_pnfs_ds *ds;
|
struct nfs4_pnfs_ds *ds = ERR_PTR(-EAGAIN);
|
||||||
u32 idx;
|
u32 idx;
|
||||||
|
|
||||||
/* mirrors are initially sorted by efficiency */
|
/* mirrors are initially sorted by efficiency */
|
||||||
for (idx = start_idx; idx < fls->mirror_array_cnt; idx++) {
|
for (idx = start_idx; idx < fls->mirror_array_cnt; idx++) {
|
||||||
mirror = FF_LAYOUT_COMP(lseg, idx);
|
mirror = FF_LAYOUT_COMP(lseg, idx);
|
||||||
ds = nfs4_ff_layout_prepare_ds(lseg, mirror, false);
|
ds = nfs4_ff_layout_prepare_ds(lseg, mirror, false);
|
||||||
if (!ds)
|
if (IS_ERR(ds))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (check_device &&
|
if (check_device &&
|
||||||
|
@ -777,10 +777,10 @@ ff_layout_choose_ds_for_read(struct pnfs_layout_segment *lseg,
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
*best_idx = idx;
|
*best_idx = idx;
|
||||||
return ds;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return ds;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct nfs4_pnfs_ds *
|
static struct nfs4_pnfs_ds *
|
||||||
|
@ -942,7 +942,7 @@ retry:
|
||||||
for (i = 0; i < pgio->pg_mirror_count; i++) {
|
for (i = 0; i < pgio->pg_mirror_count; i++) {
|
||||||
mirror = FF_LAYOUT_COMP(pgio->pg_lseg, i);
|
mirror = FF_LAYOUT_COMP(pgio->pg_lseg, i);
|
||||||
ds = nfs4_ff_layout_prepare_ds(pgio->pg_lseg, mirror, true);
|
ds = nfs4_ff_layout_prepare_ds(pgio->pg_lseg, mirror, true);
|
||||||
if (!ds) {
|
if (IS_ERR(ds)) {
|
||||||
if (!ff_layout_no_fallback_to_mds(pgio->pg_lseg))
|
if (!ff_layout_no_fallback_to_mds(pgio->pg_lseg))
|
||||||
goto out_mds;
|
goto out_mds;
|
||||||
pnfs_generic_pg_cleanup(pgio);
|
pnfs_generic_pg_cleanup(pgio);
|
||||||
|
@ -1867,6 +1867,7 @@ ff_layout_read_pagelist(struct nfs_pgio_header *hdr)
|
||||||
u32 idx = hdr->pgio_mirror_idx;
|
u32 idx = hdr->pgio_mirror_idx;
|
||||||
int vers;
|
int vers;
|
||||||
struct nfs_fh *fh;
|
struct nfs_fh *fh;
|
||||||
|
bool ds_fatal_error = false;
|
||||||
|
|
||||||
dprintk("--> %s ino %lu pgbase %u req %zu@%llu\n",
|
dprintk("--> %s ino %lu pgbase %u req %zu@%llu\n",
|
||||||
__func__, hdr->inode->i_ino,
|
__func__, hdr->inode->i_ino,
|
||||||
|
@ -1874,8 +1875,10 @@ ff_layout_read_pagelist(struct nfs_pgio_header *hdr)
|
||||||
|
|
||||||
mirror = FF_LAYOUT_COMP(lseg, idx);
|
mirror = FF_LAYOUT_COMP(lseg, idx);
|
||||||
ds = nfs4_ff_layout_prepare_ds(lseg, mirror, false);
|
ds = nfs4_ff_layout_prepare_ds(lseg, mirror, false);
|
||||||
if (!ds)
|
if (IS_ERR(ds)) {
|
||||||
|
ds_fatal_error = nfs_error_is_fatal(PTR_ERR(ds));
|
||||||
goto out_failed;
|
goto out_failed;
|
||||||
|
}
|
||||||
|
|
||||||
ds_clnt = nfs4_ff_find_or_create_ds_client(mirror, ds->ds_clp,
|
ds_clnt = nfs4_ff_find_or_create_ds_client(mirror, ds->ds_clp,
|
||||||
hdr->inode);
|
hdr->inode);
|
||||||
|
@ -1923,7 +1926,7 @@ ff_layout_read_pagelist(struct nfs_pgio_header *hdr)
|
||||||
return PNFS_ATTEMPTED;
|
return PNFS_ATTEMPTED;
|
||||||
|
|
||||||
out_failed:
|
out_failed:
|
||||||
if (ff_layout_avoid_mds_available_ds(lseg))
|
if (ff_layout_avoid_mds_available_ds(lseg) && !ds_fatal_error)
|
||||||
return PNFS_TRY_AGAIN;
|
return PNFS_TRY_AGAIN;
|
||||||
trace_pnfs_mds_fallback_read_pagelist(hdr->inode,
|
trace_pnfs_mds_fallback_read_pagelist(hdr->inode,
|
||||||
hdr->args.offset, hdr->args.count,
|
hdr->args.offset, hdr->args.count,
|
||||||
|
@ -1945,11 +1948,14 @@ ff_layout_write_pagelist(struct nfs_pgio_header *hdr, int sync)
|
||||||
int vers;
|
int vers;
|
||||||
struct nfs_fh *fh;
|
struct nfs_fh *fh;
|
||||||
u32 idx = hdr->pgio_mirror_idx;
|
u32 idx = hdr->pgio_mirror_idx;
|
||||||
|
bool ds_fatal_error = false;
|
||||||
|
|
||||||
mirror = FF_LAYOUT_COMP(lseg, idx);
|
mirror = FF_LAYOUT_COMP(lseg, idx);
|
||||||
ds = nfs4_ff_layout_prepare_ds(lseg, mirror, true);
|
ds = nfs4_ff_layout_prepare_ds(lseg, mirror, true);
|
||||||
if (!ds)
|
if (IS_ERR(ds)) {
|
||||||
|
ds_fatal_error = nfs_error_is_fatal(PTR_ERR(ds));
|
||||||
goto out_failed;
|
goto out_failed;
|
||||||
|
}
|
||||||
|
|
||||||
ds_clnt = nfs4_ff_find_or_create_ds_client(mirror, ds->ds_clp,
|
ds_clnt = nfs4_ff_find_or_create_ds_client(mirror, ds->ds_clp,
|
||||||
hdr->inode);
|
hdr->inode);
|
||||||
|
@ -2000,7 +2006,7 @@ ff_layout_write_pagelist(struct nfs_pgio_header *hdr, int sync)
|
||||||
return PNFS_ATTEMPTED;
|
return PNFS_ATTEMPTED;
|
||||||
|
|
||||||
out_failed:
|
out_failed:
|
||||||
if (ff_layout_avoid_mds_available_ds(lseg))
|
if (ff_layout_avoid_mds_available_ds(lseg) && !ds_fatal_error)
|
||||||
return PNFS_TRY_AGAIN;
|
return PNFS_TRY_AGAIN;
|
||||||
trace_pnfs_mds_fallback_write_pagelist(hdr->inode,
|
trace_pnfs_mds_fallback_write_pagelist(hdr->inode,
|
||||||
hdr->args.offset, hdr->args.count,
|
hdr->args.offset, hdr->args.count,
|
||||||
|
@ -2043,7 +2049,7 @@ static int ff_layout_initiate_commit(struct nfs_commit_data *data, int how)
|
||||||
idx = calc_ds_index_from_commit(lseg, data->ds_commit_index);
|
idx = calc_ds_index_from_commit(lseg, data->ds_commit_index);
|
||||||
mirror = FF_LAYOUT_COMP(lseg, idx);
|
mirror = FF_LAYOUT_COMP(lseg, idx);
|
||||||
ds = nfs4_ff_layout_prepare_ds(lseg, mirror, true);
|
ds = nfs4_ff_layout_prepare_ds(lseg, mirror, true);
|
||||||
if (!ds)
|
if (IS_ERR(ds))
|
||||||
goto out_err;
|
goto out_err;
|
||||||
|
|
||||||
ds_clnt = nfs4_ff_find_or_create_ds_client(mirror, ds->ds_clp,
|
ds_clnt = nfs4_ff_find_or_create_ds_client(mirror, ds->ds_clp,
|
||||||
|
|
|
@ -370,11 +370,11 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg,
|
||||||
struct nfs4_ff_layout_mirror *mirror,
|
struct nfs4_ff_layout_mirror *mirror,
|
||||||
bool fail_return)
|
bool fail_return)
|
||||||
{
|
{
|
||||||
struct nfs4_pnfs_ds *ds = NULL;
|
struct nfs4_pnfs_ds *ds;
|
||||||
struct inode *ino = lseg->pls_layout->plh_inode;
|
struct inode *ino = lseg->pls_layout->plh_inode;
|
||||||
struct nfs_server *s = NFS_SERVER(ino);
|
struct nfs_server *s = NFS_SERVER(ino);
|
||||||
unsigned int max_payload;
|
unsigned int max_payload;
|
||||||
int status;
|
int status = -EAGAIN;
|
||||||
|
|
||||||
if (!ff_layout_init_mirror_ds(lseg->pls_layout, mirror))
|
if (!ff_layout_init_mirror_ds(lseg->pls_layout, mirror))
|
||||||
goto noconnect;
|
goto noconnect;
|
||||||
|
@ -418,7 +418,7 @@ noconnect:
|
||||||
ff_layout_send_layouterror(lseg);
|
ff_layout_send_layouterror(lseg);
|
||||||
if (fail_return || !ff_layout_has_available_ds(lseg))
|
if (fail_return || !ff_layout_has_available_ds(lseg))
|
||||||
pnfs_error_mark_layout_for_return(ino, lseg);
|
pnfs_error_mark_layout_for_return(ino, lseg);
|
||||||
ds = NULL;
|
ds = ERR_PTR(status);
|
||||||
out:
|
out:
|
||||||
return ds;
|
return ds;
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,6 +96,8 @@ enum nfs_param {
|
||||||
Opt_wsize,
|
Opt_wsize,
|
||||||
Opt_write,
|
Opt_write,
|
||||||
Opt_xprtsec,
|
Opt_xprtsec,
|
||||||
|
Opt_cert_serial,
|
||||||
|
Opt_privkey_serial,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
@ -221,6 +223,8 @@ static const struct fs_parameter_spec nfs_fs_parameters[] = {
|
||||||
fsparam_enum ("write", Opt_write, nfs_param_enums_write),
|
fsparam_enum ("write", Opt_write, nfs_param_enums_write),
|
||||||
fsparam_u32 ("wsize", Opt_wsize),
|
fsparam_u32 ("wsize", Opt_wsize),
|
||||||
fsparam_string("xprtsec", Opt_xprtsec),
|
fsparam_string("xprtsec", Opt_xprtsec),
|
||||||
|
fsparam_s32("cert_serial", Opt_cert_serial),
|
||||||
|
fsparam_s32("privkey_serial", Opt_privkey_serial),
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -551,6 +555,32 @@ static int nfs_parse_version_string(struct fs_context *fc,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_KEYS
|
||||||
|
static int nfs_tls_key_verify(key_serial_t key_id)
|
||||||
|
{
|
||||||
|
struct key *key = key_lookup(key_id);
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
if (IS_ERR(key)) {
|
||||||
|
pr_err("key id %08x not found\n", key_id);
|
||||||
|
return PTR_ERR(key);
|
||||||
|
}
|
||||||
|
if (test_bit(KEY_FLAG_REVOKED, &key->flags) ||
|
||||||
|
test_bit(KEY_FLAG_INVALIDATED, &key->flags)) {
|
||||||
|
pr_err("key id %08x revoked\n", key_id);
|
||||||
|
error = -EKEYREVOKED;
|
||||||
|
}
|
||||||
|
|
||||||
|
key_put(key);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static inline int nfs_tls_key_verify(key_serial_t key_id)
|
||||||
|
{
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_KEYS */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse a single mount parameter.
|
* Parse a single mount parameter.
|
||||||
*/
|
*/
|
||||||
|
@ -807,6 +837,18 @@ static int nfs_fs_context_parse_param(struct fs_context *fc,
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
break;
|
break;
|
||||||
|
case Opt_cert_serial:
|
||||||
|
ret = nfs_tls_key_verify(result.int_32);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
ctx->xprtsec.cert_serial = result.int_32;
|
||||||
|
break;
|
||||||
|
case Opt_privkey_serial:
|
||||||
|
ret = nfs_tls_key_verify(result.int_32);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
ctx->xprtsec.privkey_serial = result.int_32;
|
||||||
|
break;
|
||||||
|
|
||||||
case Opt_proto:
|
case Opt_proto:
|
||||||
if (!param->string)
|
if (!param->string)
|
||||||
|
|
|
@ -197,6 +197,7 @@ void nfs_set_cache_invalid(struct inode *inode, unsigned long flags)
|
||||||
if (!(flags & NFS_INO_REVAL_FORCED))
|
if (!(flags & NFS_INO_REVAL_FORCED))
|
||||||
flags &= ~(NFS_INO_INVALID_MODE |
|
flags &= ~(NFS_INO_INVALID_MODE |
|
||||||
NFS_INO_INVALID_OTHER |
|
NFS_INO_INVALID_OTHER |
|
||||||
|
NFS_INO_INVALID_BTIME |
|
||||||
NFS_INO_INVALID_XATTR);
|
NFS_INO_INVALID_XATTR);
|
||||||
flags &= ~(NFS_INO_INVALID_CHANGE | NFS_INO_INVALID_SIZE);
|
flags &= ~(NFS_INO_INVALID_CHANGE | NFS_INO_INVALID_SIZE);
|
||||||
}
|
}
|
||||||
|
@ -522,6 +523,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
|
||||||
inode_set_atime(inode, 0, 0);
|
inode_set_atime(inode, 0, 0);
|
||||||
inode_set_mtime(inode, 0, 0);
|
inode_set_mtime(inode, 0, 0);
|
||||||
inode_set_ctime(inode, 0, 0);
|
inode_set_ctime(inode, 0, 0);
|
||||||
|
memset(&nfsi->btime, 0, sizeof(nfsi->btime));
|
||||||
inode_set_iversion_raw(inode, 0);
|
inode_set_iversion_raw(inode, 0);
|
||||||
inode->i_size = 0;
|
inode->i_size = 0;
|
||||||
clear_nlink(inode);
|
clear_nlink(inode);
|
||||||
|
@ -545,6 +547,10 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
|
||||||
inode_set_ctime_to_ts(inode, fattr->ctime);
|
inode_set_ctime_to_ts(inode, fattr->ctime);
|
||||||
else if (fattr_supported & NFS_ATTR_FATTR_CTIME)
|
else if (fattr_supported & NFS_ATTR_FATTR_CTIME)
|
||||||
nfs_set_cache_invalid(inode, NFS_INO_INVALID_CTIME);
|
nfs_set_cache_invalid(inode, NFS_INO_INVALID_CTIME);
|
||||||
|
if (fattr->valid & NFS_ATTR_FATTR_BTIME)
|
||||||
|
nfsi->btime = fattr->btime;
|
||||||
|
else if (fattr_supported & NFS_ATTR_FATTR_BTIME)
|
||||||
|
nfs_set_cache_invalid(inode, NFS_INO_INVALID_BTIME);
|
||||||
if (fattr->valid & NFS_ATTR_FATTR_CHANGE)
|
if (fattr->valid & NFS_ATTR_FATTR_CHANGE)
|
||||||
inode_set_iversion_raw(inode, fattr->change_attr);
|
inode_set_iversion_raw(inode, fattr->change_attr);
|
||||||
else
|
else
|
||||||
|
@ -931,6 +937,7 @@ static void nfs_readdirplus_parent_cache_hit(struct dentry *dentry)
|
||||||
|
|
||||||
static u32 nfs_get_valid_attrmask(struct inode *inode)
|
static u32 nfs_get_valid_attrmask(struct inode *inode)
|
||||||
{
|
{
|
||||||
|
u64 fattr_valid = NFS_SERVER(inode)->fattr_valid;
|
||||||
unsigned long cache_validity = READ_ONCE(NFS_I(inode)->cache_validity);
|
unsigned long cache_validity = READ_ONCE(NFS_I(inode)->cache_validity);
|
||||||
u32 reply_mask = STATX_INO | STATX_TYPE;
|
u32 reply_mask = STATX_INO | STATX_TYPE;
|
||||||
|
|
||||||
|
@ -950,6 +957,9 @@ static u32 nfs_get_valid_attrmask(struct inode *inode)
|
||||||
reply_mask |= STATX_UID | STATX_GID;
|
reply_mask |= STATX_UID | STATX_GID;
|
||||||
if (!(cache_validity & NFS_INO_INVALID_BLOCKS))
|
if (!(cache_validity & NFS_INO_INVALID_BLOCKS))
|
||||||
reply_mask |= STATX_BLOCKS;
|
reply_mask |= STATX_BLOCKS;
|
||||||
|
if (!(cache_validity & NFS_INO_INVALID_BTIME) &&
|
||||||
|
(fattr_valid & NFS_ATTR_FATTR_BTIME))
|
||||||
|
reply_mask |= STATX_BTIME;
|
||||||
if (!(cache_validity & NFS_INO_INVALID_CHANGE))
|
if (!(cache_validity & NFS_INO_INVALID_CHANGE))
|
||||||
reply_mask |= STATX_CHANGE_COOKIE;
|
reply_mask |= STATX_CHANGE_COOKIE;
|
||||||
return reply_mask;
|
return reply_mask;
|
||||||
|
@ -960,6 +970,7 @@ int nfs_getattr(struct mnt_idmap *idmap, const struct path *path,
|
||||||
{
|
{
|
||||||
struct inode *inode = d_inode(path->dentry);
|
struct inode *inode = d_inode(path->dentry);
|
||||||
struct nfs_server *server = NFS_SERVER(inode);
|
struct nfs_server *server = NFS_SERVER(inode);
|
||||||
|
u64 fattr_valid = server->fattr_valid;
|
||||||
unsigned long cache_validity;
|
unsigned long cache_validity;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
bool force_sync = query_flags & AT_STATX_FORCE_SYNC;
|
bool force_sync = query_flags & AT_STATX_FORCE_SYNC;
|
||||||
|
@ -970,9 +981,12 @@ int nfs_getattr(struct mnt_idmap *idmap, const struct path *path,
|
||||||
|
|
||||||
request_mask &= STATX_TYPE | STATX_MODE | STATX_NLINK | STATX_UID |
|
request_mask &= STATX_TYPE | STATX_MODE | STATX_NLINK | STATX_UID |
|
||||||
STATX_GID | STATX_ATIME | STATX_MTIME | STATX_CTIME |
|
STATX_GID | STATX_ATIME | STATX_MTIME | STATX_CTIME |
|
||||||
STATX_INO | STATX_SIZE | STATX_BLOCKS |
|
STATX_INO | STATX_SIZE | STATX_BLOCKS | STATX_BTIME |
|
||||||
STATX_CHANGE_COOKIE;
|
STATX_CHANGE_COOKIE;
|
||||||
|
|
||||||
|
if (!(fattr_valid & NFS_ATTR_FATTR_BTIME))
|
||||||
|
request_mask &= ~STATX_BTIME;
|
||||||
|
|
||||||
if ((query_flags & AT_STATX_DONT_SYNC) && !force_sync) {
|
if ((query_flags & AT_STATX_DONT_SYNC) && !force_sync) {
|
||||||
if (readdirplus_enabled)
|
if (readdirplus_enabled)
|
||||||
nfs_readdirplus_parent_cache_hit(path->dentry);
|
nfs_readdirplus_parent_cache_hit(path->dentry);
|
||||||
|
@ -1004,7 +1018,7 @@ int nfs_getattr(struct mnt_idmap *idmap, const struct path *path,
|
||||||
/* Is the user requesting attributes that might need revalidation? */
|
/* Is the user requesting attributes that might need revalidation? */
|
||||||
if (!(request_mask & (STATX_MODE|STATX_NLINK|STATX_ATIME|STATX_CTIME|
|
if (!(request_mask & (STATX_MODE|STATX_NLINK|STATX_ATIME|STATX_CTIME|
|
||||||
STATX_MTIME|STATX_UID|STATX_GID|
|
STATX_MTIME|STATX_UID|STATX_GID|
|
||||||
STATX_SIZE|STATX_BLOCKS|
|
STATX_SIZE|STATX_BLOCKS|STATX_BTIME|
|
||||||
STATX_CHANGE_COOKIE)))
|
STATX_CHANGE_COOKIE)))
|
||||||
goto out_no_revalidate;
|
goto out_no_revalidate;
|
||||||
|
|
||||||
|
@ -1028,6 +1042,8 @@ int nfs_getattr(struct mnt_idmap *idmap, const struct path *path,
|
||||||
do_update |= cache_validity & NFS_INO_INVALID_OTHER;
|
do_update |= cache_validity & NFS_INO_INVALID_OTHER;
|
||||||
if (request_mask & STATX_BLOCKS)
|
if (request_mask & STATX_BLOCKS)
|
||||||
do_update |= cache_validity & NFS_INO_INVALID_BLOCKS;
|
do_update |= cache_validity & NFS_INO_INVALID_BLOCKS;
|
||||||
|
if (request_mask & STATX_BTIME)
|
||||||
|
do_update |= cache_validity & NFS_INO_INVALID_BTIME;
|
||||||
|
|
||||||
if (do_update) {
|
if (do_update) {
|
||||||
if (readdirplus_enabled)
|
if (readdirplus_enabled)
|
||||||
|
@ -1049,6 +1065,7 @@ out_no_revalidate:
|
||||||
stat->attributes |= STATX_ATTR_CHANGE_MONOTONIC;
|
stat->attributes |= STATX_ATTR_CHANGE_MONOTONIC;
|
||||||
if (S_ISDIR(inode->i_mode))
|
if (S_ISDIR(inode->i_mode))
|
||||||
stat->blksize = NFS_SERVER(inode)->dtsize;
|
stat->blksize = NFS_SERVER(inode)->dtsize;
|
||||||
|
stat->btime = NFS_I(inode)->btime;
|
||||||
out:
|
out:
|
||||||
trace_nfs_getattr_exit(inode, err);
|
trace_nfs_getattr_exit(inode, err);
|
||||||
return err;
|
return err;
|
||||||
|
@ -1943,7 +1960,7 @@ static int nfs_inode_finish_partial_attr_update(const struct nfs_fattr *fattr,
|
||||||
NFS_INO_INVALID_ATIME | NFS_INO_INVALID_CTIME |
|
NFS_INO_INVALID_ATIME | NFS_INO_INVALID_CTIME |
|
||||||
NFS_INO_INVALID_MTIME | NFS_INO_INVALID_SIZE |
|
NFS_INO_INVALID_MTIME | NFS_INO_INVALID_SIZE |
|
||||||
NFS_INO_INVALID_BLOCKS | NFS_INO_INVALID_OTHER |
|
NFS_INO_INVALID_BLOCKS | NFS_INO_INVALID_OTHER |
|
||||||
NFS_INO_INVALID_NLINK;
|
NFS_INO_INVALID_NLINK | NFS_INO_INVALID_BTIME;
|
||||||
unsigned long cache_validity = NFS_I(inode)->cache_validity;
|
unsigned long cache_validity = NFS_I(inode)->cache_validity;
|
||||||
enum nfs4_change_attr_type ctype = NFS_SERVER(inode)->change_attr_type;
|
enum nfs4_change_attr_type ctype = NFS_SERVER(inode)->change_attr_type;
|
||||||
|
|
||||||
|
@ -2209,7 +2226,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
|
||||||
bool attr_changed = false;
|
bool attr_changed = false;
|
||||||
bool have_delegation;
|
bool have_delegation;
|
||||||
|
|
||||||
dfprintk(VFS, "NFS: %s(%s/%lu fh_crc=0x%08x ct=%d info=0x%x)\n",
|
dfprintk(VFS, "NFS: %s(%s/%lu fh_crc=0x%08x ct=%d info=0x%llx)\n",
|
||||||
__func__, inode->i_sb->s_id, inode->i_ino,
|
__func__, inode->i_sb->s_id, inode->i_ino,
|
||||||
nfs_display_fhandle_hash(NFS_FH(inode)),
|
nfs_display_fhandle_hash(NFS_FH(inode)),
|
||||||
atomic_read(&inode->i_count), fattr->valid);
|
atomic_read(&inode->i_count), fattr->valid);
|
||||||
|
@ -2304,7 +2321,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
|
||||||
| NFS_INO_INVALID_BLOCKS
|
| NFS_INO_INVALID_BLOCKS
|
||||||
| NFS_INO_INVALID_NLINK
|
| NFS_INO_INVALID_NLINK
|
||||||
| NFS_INO_INVALID_MODE
|
| NFS_INO_INVALID_MODE
|
||||||
| NFS_INO_INVALID_OTHER;
|
| NFS_INO_INVALID_OTHER
|
||||||
|
| NFS_INO_INVALID_BTIME;
|
||||||
if (S_ISDIR(inode->i_mode))
|
if (S_ISDIR(inode->i_mode))
|
||||||
nfs_force_lookup_revalidate(inode);
|
nfs_force_lookup_revalidate(inode);
|
||||||
attr_changed = true;
|
attr_changed = true;
|
||||||
|
@ -2338,6 +2356,12 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
|
||||||
nfsi->cache_validity |=
|
nfsi->cache_validity |=
|
||||||
save_cache_validity & NFS_INO_INVALID_CTIME;
|
save_cache_validity & NFS_INO_INVALID_CTIME;
|
||||||
|
|
||||||
|
if (fattr->valid & NFS_ATTR_FATTR_BTIME)
|
||||||
|
nfsi->btime = fattr->btime;
|
||||||
|
else if (fattr_supported & NFS_ATTR_FATTR_BTIME)
|
||||||
|
nfsi->cache_validity |=
|
||||||
|
save_cache_validity & NFS_INO_INVALID_BTIME;
|
||||||
|
|
||||||
/* Check if our cached file size is stale */
|
/* Check if our cached file size is stale */
|
||||||
if (fattr->valid & NFS_ATTR_FATTR_SIZE) {
|
if (fattr->valid & NFS_ATTR_FATTR_SIZE) {
|
||||||
new_isize = nfs_size_to_loff_t(fattr->size);
|
new_isize = nfs_size_to_loff_t(fattr->size);
|
||||||
|
@ -2625,6 +2649,35 @@ static struct pernet_operations nfs_net_ops = {
|
||||||
.size = sizeof(struct nfs_net),
|
.size = sizeof(struct nfs_net),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_KEYS
|
||||||
|
static struct key *nfs_keyring;
|
||||||
|
|
||||||
|
static int __init nfs_init_keyring(void)
|
||||||
|
{
|
||||||
|
nfs_keyring = keyring_alloc(".nfs",
|
||||||
|
GLOBAL_ROOT_UID, GLOBAL_ROOT_GID,
|
||||||
|
current_cred(),
|
||||||
|
(KEY_POS_ALL & ~KEY_POS_SETATTR) |
|
||||||
|
(KEY_USR_ALL & ~KEY_USR_SETATTR),
|
||||||
|
KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
|
||||||
|
return PTR_ERR_OR_ZERO(nfs_keyring);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nfs_exit_keyring(void)
|
||||||
|
{
|
||||||
|
key_put(nfs_keyring);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static inline int nfs_init_keyring(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void nfs_exit_keyring(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_KEYS */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize NFS
|
* Initialize NFS
|
||||||
*/
|
*/
|
||||||
|
@ -2632,6 +2685,10 @@ static int __init init_nfs_fs(void)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
err = nfs_init_keyring();
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
err = nfs_sysfs_init();
|
err = nfs_sysfs_init();
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto out10;
|
goto out10;
|
||||||
|
@ -2692,6 +2749,7 @@ out7:
|
||||||
out9:
|
out9:
|
||||||
nfs_sysfs_exit();
|
nfs_sysfs_exit();
|
||||||
out10:
|
out10:
|
||||||
|
nfs_exit_keyring();
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2707,6 +2765,7 @@ static void __exit exit_nfs_fs(void)
|
||||||
nfs_fs_proc_exit();
|
nfs_fs_proc_exit();
|
||||||
nfsiod_stop();
|
nfsiod_stop();
|
||||||
nfs_sysfs_exit();
|
nfs_sysfs_exit();
|
||||||
|
nfs_exit_keyring();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Not quite true; I just maintain it */
|
/* Not quite true; I just maintain it */
|
||||||
|
|
|
@ -207,7 +207,6 @@ struct nfs_mount_request {
|
||||||
};
|
};
|
||||||
|
|
||||||
extern int nfs_mount(struct nfs_mount_request *info, int timeo, int retrans);
|
extern int nfs_mount(struct nfs_mount_request *info, int timeo, int retrans);
|
||||||
extern void nfs_umount(const struct nfs_mount_request *info);
|
|
||||||
|
|
||||||
/* client.c */
|
/* client.c */
|
||||||
extern const struct rpc_program nfs_program;
|
extern const struct rpc_program nfs_program;
|
||||||
|
@ -232,7 +231,7 @@ extern struct nfs_client *
|
||||||
nfs4_find_client_sessionid(struct net *, const struct sockaddr *,
|
nfs4_find_client_sessionid(struct net *, const struct sockaddr *,
|
||||||
struct nfs4_sessionid *, u32);
|
struct nfs4_sessionid *, u32);
|
||||||
extern struct nfs_server *nfs_create_server(struct fs_context *);
|
extern struct nfs_server *nfs_create_server(struct fs_context *);
|
||||||
extern void nfs4_server_set_init_caps(struct nfs_server *);
|
extern void nfs_server_set_init_caps(struct nfs_server *);
|
||||||
extern struct nfs_server *nfs4_create_server(struct fs_context *);
|
extern struct nfs_server *nfs4_create_server(struct fs_context *);
|
||||||
extern struct nfs_server *nfs4_create_referral_server(struct fs_context *);
|
extern struct nfs_server *nfs4_create_referral_server(struct fs_context *);
|
||||||
extern int nfs4_update_server(struct nfs_server *server, const char *hostname,
|
extern int nfs4_update_server(struct nfs_server *server, const char *hostname,
|
||||||
|
@ -671,9 +670,12 @@ nfs_write_match_verf(const struct nfs_writeverf *verf,
|
||||||
|
|
||||||
static inline gfp_t nfs_io_gfp_mask(void)
|
static inline gfp_t nfs_io_gfp_mask(void)
|
||||||
{
|
{
|
||||||
if (current->flags & PF_WQ_WORKER)
|
gfp_t ret = current_gfp_context(GFP_KERNEL);
|
||||||
return GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN;
|
|
||||||
return GFP_KERNEL;
|
/* For workers __GFP_NORETRY only with __GFP_IO or __GFP_FS */
|
||||||
|
if ((current->flags & PF_WQ_WORKER) && ret == GFP_KERNEL)
|
||||||
|
ret |= __GFP_NORETRY | __GFP_NOWARN;
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -500,14 +500,13 @@ nfs_copy_boot_verifier(struct nfs_write_verifier *verifier, struct inode *inode)
|
||||||
{
|
{
|
||||||
struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
|
struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
|
||||||
u32 *verf = (u32 *)verifier->data;
|
u32 *verf = (u32 *)verifier->data;
|
||||||
int seq = 0;
|
unsigned int seq;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
read_seqbegin_or_lock(&clp->cl_boot_lock, &seq);
|
seq = read_seqbegin(&clp->cl_boot_lock);
|
||||||
verf[0] = (u32)clp->cl_nfssvc_boot.tv_sec;
|
verf[0] = (u32)clp->cl_nfssvc_boot.tv_sec;
|
||||||
verf[1] = (u32)clp->cl_nfssvc_boot.tv_nsec;
|
verf[1] = (u32)clp->cl_nfssvc_boot.tv_nsec;
|
||||||
} while (need_seqretry(&clp->cl_boot_lock, seq));
|
} while (read_seqretry(&clp->cl_boot_lock, seq));
|
||||||
done_seqretry(&clp->cl_boot_lock, seq);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
@ -223,74 +223,6 @@ out_mnt_err:
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* nfs_umount - Notify a server that we have unmounted this export
|
|
||||||
* @info: pointer to umount request arguments
|
|
||||||
*
|
|
||||||
* MOUNTPROC_UMNT is advisory, so we set a short timeout, and always
|
|
||||||
* use UDP.
|
|
||||||
*/
|
|
||||||
void nfs_umount(const struct nfs_mount_request *info)
|
|
||||||
{
|
|
||||||
static const struct rpc_timeout nfs_umnt_timeout = {
|
|
||||||
.to_initval = 1 * HZ,
|
|
||||||
.to_maxval = 3 * HZ,
|
|
||||||
.to_retries = 2,
|
|
||||||
};
|
|
||||||
struct rpc_create_args args = {
|
|
||||||
.net = info->net,
|
|
||||||
.protocol = IPPROTO_UDP,
|
|
||||||
.address = (struct sockaddr *)info->sap,
|
|
||||||
.addrsize = info->salen,
|
|
||||||
.timeout = &nfs_umnt_timeout,
|
|
||||||
.servername = info->hostname,
|
|
||||||
.program = &mnt_program,
|
|
||||||
.version = info->version,
|
|
||||||
.authflavor = RPC_AUTH_UNIX,
|
|
||||||
.flags = RPC_CLNT_CREATE_NOPING,
|
|
||||||
.cred = current_cred(),
|
|
||||||
};
|
|
||||||
struct rpc_message msg = {
|
|
||||||
.rpc_argp = info->dirpath,
|
|
||||||
};
|
|
||||||
struct rpc_clnt *clnt;
|
|
||||||
int status;
|
|
||||||
|
|
||||||
if (strlen(info->dirpath) > MNTPATHLEN)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (info->noresvport)
|
|
||||||
args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
|
|
||||||
|
|
||||||
clnt = rpc_create(&args);
|
|
||||||
if (IS_ERR(clnt))
|
|
||||||
goto out_clnt_err;
|
|
||||||
|
|
||||||
dprintk("NFS: sending UMNT request for %s:%s\n",
|
|
||||||
(info->hostname ? info->hostname : "server"), info->dirpath);
|
|
||||||
|
|
||||||
if (info->version == NFS_MNT3_VERSION)
|
|
||||||
msg.rpc_proc = &clnt->cl_procinfo[MOUNTPROC3_UMNT];
|
|
||||||
else
|
|
||||||
msg.rpc_proc = &clnt->cl_procinfo[MOUNTPROC_UMNT];
|
|
||||||
|
|
||||||
status = rpc_call_sync(clnt, &msg, 0);
|
|
||||||
rpc_shutdown_client(clnt);
|
|
||||||
|
|
||||||
if (unlikely(status < 0))
|
|
||||||
goto out_call_err;
|
|
||||||
|
|
||||||
return;
|
|
||||||
|
|
||||||
out_clnt_err:
|
|
||||||
dprintk("NFS: failed to create UMNT RPC client, status=%ld\n",
|
|
||||||
PTR_ERR(clnt));
|
|
||||||
return;
|
|
||||||
|
|
||||||
out_call_err:
|
|
||||||
dprintk("NFS: UMNT request failed, status=%d\n", status);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XDR encode/decode functions for MOUNT
|
* XDR encode/decode functions for MOUNT
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -63,7 +63,7 @@ struct nfs4_minor_version_ops {
|
||||||
bool (*match_stateid)(const nfs4_stateid *,
|
bool (*match_stateid)(const nfs4_stateid *,
|
||||||
const nfs4_stateid *);
|
const nfs4_stateid *);
|
||||||
int (*find_root_sec)(struct nfs_server *, struct nfs_fh *,
|
int (*find_root_sec)(struct nfs_server *, struct nfs_fh *,
|
||||||
struct nfs_fsinfo *);
|
struct nfs_fattr *);
|
||||||
void (*free_lock_state)(struct nfs_server *,
|
void (*free_lock_state)(struct nfs_server *,
|
||||||
struct nfs4_lock_state *);
|
struct nfs4_lock_state *);
|
||||||
int (*test_and_free_expired)(struct nfs_server *,
|
int (*test_and_free_expired)(struct nfs_server *,
|
||||||
|
@ -296,7 +296,8 @@ extern int nfs4_call_sync(struct rpc_clnt *, struct nfs_server *,
|
||||||
extern void nfs4_init_sequence(struct nfs4_sequence_args *, struct nfs4_sequence_res *, int, int);
|
extern void nfs4_init_sequence(struct nfs4_sequence_args *, struct nfs4_sequence_res *, int, int);
|
||||||
extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, const struct cred *, struct nfs4_setclientid_res *);
|
extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, const struct cred *, struct nfs4_setclientid_res *);
|
||||||
extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct nfs4_setclientid_res *arg, const struct cred *);
|
extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct nfs4_setclientid_res *arg, const struct cred *);
|
||||||
extern int nfs4_proc_get_rootfh(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *, bool);
|
extern int nfs4_proc_get_rootfh(struct nfs_server *, struct nfs_fh *,
|
||||||
|
struct nfs_fattr *, bool);
|
||||||
extern int nfs4_proc_bind_conn_to_session(struct nfs_client *, const struct cred *cred);
|
extern int nfs4_proc_bind_conn_to_session(struct nfs_client *, const struct cred *cred);
|
||||||
extern int nfs4_proc_exchange_id(struct nfs_client *clp, const struct cred *cred);
|
extern int nfs4_proc_exchange_id(struct nfs_client *clp, const struct cred *cred);
|
||||||
extern int nfs4_destroy_clientid(struct nfs_client *clp);
|
extern int nfs4_destroy_clientid(struct nfs_client *clp);
|
||||||
|
|
|
@ -802,6 +802,7 @@ static void nfs4_destroy_server(struct nfs_server *server)
|
||||||
unset_pnfs_layoutdriver(server);
|
unset_pnfs_layoutdriver(server);
|
||||||
nfs4_purge_state_owners(server, &freeme);
|
nfs4_purge_state_owners(server, &freeme);
|
||||||
nfs4_free_state_owners(&freeme);
|
nfs4_free_state_owners(&freeme);
|
||||||
|
kfree(server->delegation_hash_table);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -895,55 +896,40 @@ nfs4_find_client_sessionid(struct net *net, const struct sockaddr *addr,
|
||||||
* Set up an NFS4 client
|
* Set up an NFS4 client
|
||||||
*/
|
*/
|
||||||
static int nfs4_set_client(struct nfs_server *server,
|
static int nfs4_set_client(struct nfs_server *server,
|
||||||
const char *hostname,
|
struct nfs_client_initdata *cl_init)
|
||||||
const struct sockaddr_storage *addr,
|
|
||||||
const size_t addrlen,
|
|
||||||
const char *ip_addr,
|
|
||||||
int proto, const struct rpc_timeout *timeparms,
|
|
||||||
u32 minorversion, unsigned int nconnect,
|
|
||||||
unsigned int max_connect,
|
|
||||||
struct net *net,
|
|
||||||
struct xprtsec_parms *xprtsec)
|
|
||||||
{
|
{
|
||||||
struct nfs_client_initdata cl_init = {
|
|
||||||
.hostname = hostname,
|
|
||||||
.addr = addr,
|
|
||||||
.addrlen = addrlen,
|
|
||||||
.ip_addr = ip_addr,
|
|
||||||
.nfs_mod = &nfs_v4,
|
|
||||||
.proto = proto,
|
|
||||||
.minorversion = minorversion,
|
|
||||||
.net = net,
|
|
||||||
.timeparms = timeparms,
|
|
||||||
.cred = server->cred,
|
|
||||||
.xprtsec = *xprtsec,
|
|
||||||
};
|
|
||||||
struct nfs_client *clp;
|
struct nfs_client *clp;
|
||||||
|
|
||||||
if (minorversion == 0)
|
cl_init->nfs_mod = &nfs_v4;
|
||||||
__set_bit(NFS_CS_REUSEPORT, &cl_init.init_flags);
|
cl_init->cred = server->cred;
|
||||||
else
|
|
||||||
cl_init.max_connect = max_connect;
|
if (cl_init->minorversion == 0) {
|
||||||
switch (proto) {
|
__set_bit(NFS_CS_REUSEPORT, &cl_init->init_flags);
|
||||||
|
cl_init->max_connect = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (cl_init->proto) {
|
||||||
case XPRT_TRANSPORT_RDMA:
|
case XPRT_TRANSPORT_RDMA:
|
||||||
case XPRT_TRANSPORT_TCP:
|
case XPRT_TRANSPORT_TCP:
|
||||||
case XPRT_TRANSPORT_TCP_TLS:
|
case XPRT_TRANSPORT_TCP_TLS:
|
||||||
cl_init.nconnect = nconnect;
|
break;
|
||||||
|
default:
|
||||||
|
cl_init->nconnect = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (server->flags & NFS_MOUNT_NORESVPORT)
|
if (server->flags & NFS_MOUNT_NORESVPORT)
|
||||||
__set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags);
|
__set_bit(NFS_CS_NORESVPORT, &cl_init->init_flags);
|
||||||
if (server->options & NFS_OPTION_MIGRATION)
|
if (server->options & NFS_OPTION_MIGRATION)
|
||||||
__set_bit(NFS_CS_MIGRATION, &cl_init.init_flags);
|
__set_bit(NFS_CS_MIGRATION, &cl_init->init_flags);
|
||||||
if (test_bit(NFS_MIG_TSM_POSSIBLE, &server->mig_status))
|
if (test_bit(NFS_MIG_TSM_POSSIBLE, &server->mig_status))
|
||||||
__set_bit(NFS_CS_TSM_POSSIBLE, &cl_init.init_flags);
|
__set_bit(NFS_CS_TSM_POSSIBLE, &cl_init->init_flags);
|
||||||
server->port = rpc_get_port((struct sockaddr *)addr);
|
server->port = rpc_get_port((struct sockaddr *)cl_init->addr);
|
||||||
|
|
||||||
if (server->flags & NFS_MOUNT_NETUNREACH_FATAL)
|
if (server->flags & NFS_MOUNT_NETUNREACH_FATAL)
|
||||||
__set_bit(NFS_CS_NETUNREACH_FATAL, &cl_init.init_flags);
|
__set_bit(NFS_CS_NETUNREACH_FATAL, &cl_init->init_flags);
|
||||||
|
|
||||||
/* Allocate or find a client reference we can use */
|
/* Allocate or find a client reference we can use */
|
||||||
clp = nfs_get_client(&cl_init);
|
clp = nfs_get_client(cl_init);
|
||||||
if (IS_ERR(clp))
|
if (IS_ERR(clp))
|
||||||
return PTR_ERR(clp);
|
return PTR_ERR(clp);
|
||||||
|
|
||||||
|
@ -1088,29 +1074,15 @@ static void nfs4_session_limit_xasize(struct nfs_server *server)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfs4_server_set_init_caps(struct nfs_server *server)
|
|
||||||
{
|
|
||||||
/* Set the basic capabilities */
|
|
||||||
server->caps |= server->nfs_client->cl_mvops->init_caps;
|
|
||||||
if (server->flags & NFS_MOUNT_NORDIRPLUS)
|
|
||||||
server->caps &= ~NFS_CAP_READDIRPLUS;
|
|
||||||
if (server->nfs_client->cl_proto == XPRT_TRANSPORT_RDMA)
|
|
||||||
server->caps &= ~NFS_CAP_READ_PLUS;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Don't use NFS uid/gid mapping if we're using AUTH_SYS or lower
|
|
||||||
* authentication.
|
|
||||||
*/
|
|
||||||
if (nfs4_disable_idmapping &&
|
|
||||||
server->client->cl_auth->au_flavor == RPC_AUTH_UNIX)
|
|
||||||
server->caps |= NFS_CAP_UIDGID_NOMAP;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nfs4_server_common_setup(struct nfs_server *server,
|
static int nfs4_server_common_setup(struct nfs_server *server,
|
||||||
struct nfs_fh *mntfh, bool auth_probe)
|
struct nfs_fh *mntfh, bool auth_probe)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
|
error = nfs4_delegation_hash_alloc(server);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
/* data servers support only a subset of NFSv4.1 */
|
/* data servers support only a subset of NFSv4.1 */
|
||||||
if (is_ds_only_client(server->nfs_client))
|
if (is_ds_only_client(server->nfs_client))
|
||||||
return -EPROTONOSUPPORT;
|
return -EPROTONOSUPPORT;
|
||||||
|
@ -1118,14 +1090,14 @@ static int nfs4_server_common_setup(struct nfs_server *server,
|
||||||
/* We must ensure the session is initialised first */
|
/* We must ensure the session is initialised first */
|
||||||
error = nfs4_init_session(server->nfs_client);
|
error = nfs4_init_session(server->nfs_client);
|
||||||
if (error < 0)
|
if (error < 0)
|
||||||
goto out;
|
return error;
|
||||||
|
|
||||||
nfs4_server_set_init_caps(server);
|
nfs_server_set_init_caps(server);
|
||||||
|
|
||||||
/* Probe the root fh to retrieve its FSID and filehandle */
|
/* Probe the root fh to retrieve its FSID and filehandle */
|
||||||
error = nfs4_get_rootfh(server, mntfh, auth_probe);
|
error = nfs4_get_rootfh(server, mntfh, auth_probe);
|
||||||
if (error < 0)
|
if (error < 0)
|
||||||
goto out;
|
return error;
|
||||||
|
|
||||||
dprintk("Server FSID: %llx:%llx\n",
|
dprintk("Server FSID: %llx:%llx\n",
|
||||||
(unsigned long long) server->fsid.major,
|
(unsigned long long) server->fsid.major,
|
||||||
|
@ -1134,7 +1106,7 @@ static int nfs4_server_common_setup(struct nfs_server *server,
|
||||||
|
|
||||||
error = nfs_probe_server(server, mntfh);
|
error = nfs_probe_server(server, mntfh);
|
||||||
if (error < 0)
|
if (error < 0)
|
||||||
goto out;
|
return error;
|
||||||
|
|
||||||
nfs4_session_limit_rwsize(server);
|
nfs4_session_limit_rwsize(server);
|
||||||
nfs4_session_limit_xasize(server);
|
nfs4_session_limit_xasize(server);
|
||||||
|
@ -1145,8 +1117,7 @@ static int nfs4_server_common_setup(struct nfs_server *server,
|
||||||
nfs_server_insert_lists(server);
|
nfs_server_insert_lists(server);
|
||||||
server->mount_time = jiffies;
|
server->mount_time = jiffies;
|
||||||
server->destroy = nfs4_destroy_server;
|
server->destroy = nfs4_destroy_server;
|
||||||
out:
|
return 0;
|
||||||
return error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1156,6 +1127,19 @@ static int nfs4_init_server(struct nfs_server *server, struct fs_context *fc)
|
||||||
{
|
{
|
||||||
struct nfs_fs_context *ctx = nfs_fc2context(fc);
|
struct nfs_fs_context *ctx = nfs_fc2context(fc);
|
||||||
struct rpc_timeout timeparms;
|
struct rpc_timeout timeparms;
|
||||||
|
struct nfs_client_initdata cl_init = {
|
||||||
|
.hostname = ctx->nfs_server.hostname,
|
||||||
|
.addr = &ctx->nfs_server._address,
|
||||||
|
.addrlen = ctx->nfs_server.addrlen,
|
||||||
|
.ip_addr = ctx->client_address,
|
||||||
|
.proto = ctx->nfs_server.protocol,
|
||||||
|
.minorversion = ctx->minorversion,
|
||||||
|
.net = fc->net_ns,
|
||||||
|
.timeparms = &timeparms,
|
||||||
|
.xprtsec = ctx->xprtsec,
|
||||||
|
.nconnect = ctx->nfs_server.nconnect,
|
||||||
|
.max_connect = ctx->nfs_server.max_connect,
|
||||||
|
};
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
nfs_init_timeout_values(&timeparms, ctx->nfs_server.protocol,
|
nfs_init_timeout_values(&timeparms, ctx->nfs_server.protocol,
|
||||||
|
@ -1175,18 +1159,7 @@ static int nfs4_init_server(struct nfs_server *server, struct fs_context *fc)
|
||||||
ctx->selected_flavor = RPC_AUTH_UNIX;
|
ctx->selected_flavor = RPC_AUTH_UNIX;
|
||||||
|
|
||||||
/* Get a client record */
|
/* Get a client record */
|
||||||
error = nfs4_set_client(server,
|
error = nfs4_set_client(server, &cl_init);
|
||||||
ctx->nfs_server.hostname,
|
|
||||||
&ctx->nfs_server._address,
|
|
||||||
ctx->nfs_server.addrlen,
|
|
||||||
ctx->client_address,
|
|
||||||
ctx->nfs_server.protocol,
|
|
||||||
&timeparms,
|
|
||||||
ctx->minorversion,
|
|
||||||
ctx->nfs_server.nconnect,
|
|
||||||
ctx->nfs_server.max_connect,
|
|
||||||
fc->net_ns,
|
|
||||||
&ctx->xprtsec);
|
|
||||||
if (error < 0)
|
if (error < 0)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
|
@ -1246,18 +1219,28 @@ error:
|
||||||
struct nfs_server *nfs4_create_referral_server(struct fs_context *fc)
|
struct nfs_server *nfs4_create_referral_server(struct fs_context *fc)
|
||||||
{
|
{
|
||||||
struct nfs_fs_context *ctx = nfs_fc2context(fc);
|
struct nfs_fs_context *ctx = nfs_fc2context(fc);
|
||||||
struct nfs_client *parent_client;
|
struct nfs_server *parent_server = NFS_SB(ctx->clone_data.sb);
|
||||||
struct nfs_server *server, *parent_server;
|
struct nfs_client *parent_client = parent_server->nfs_client;
|
||||||
int proto, error;
|
struct nfs_client_initdata cl_init = {
|
||||||
|
.hostname = ctx->nfs_server.hostname,
|
||||||
|
.addr = &ctx->nfs_server._address,
|
||||||
|
.addrlen = ctx->nfs_server.addrlen,
|
||||||
|
.ip_addr = parent_client->cl_ipaddr,
|
||||||
|
.minorversion = parent_client->cl_mvops->minor_version,
|
||||||
|
.net = parent_client->cl_net,
|
||||||
|
.timeparms = parent_server->client->cl_timeout,
|
||||||
|
.xprtsec = parent_client->cl_xprtsec,
|
||||||
|
.nconnect = parent_client->cl_nconnect,
|
||||||
|
.max_connect = parent_client->cl_max_connect,
|
||||||
|
};
|
||||||
|
struct nfs_server *server;
|
||||||
bool auth_probe;
|
bool auth_probe;
|
||||||
|
int error;
|
||||||
|
|
||||||
server = nfs_alloc_server();
|
server = nfs_alloc_server();
|
||||||
if (!server)
|
if (!server)
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
parent_server = NFS_SB(ctx->clone_data.sb);
|
|
||||||
parent_client = parent_server->nfs_client;
|
|
||||||
|
|
||||||
server->cred = get_cred(parent_server->cred);
|
server->cred = get_cred(parent_server->cred);
|
||||||
|
|
||||||
/* Initialise the client representation from the parent server */
|
/* Initialise the client representation from the parent server */
|
||||||
|
@ -1266,38 +1249,17 @@ struct nfs_server *nfs4_create_referral_server(struct fs_context *fc)
|
||||||
/* Get a client representation */
|
/* Get a client representation */
|
||||||
#if IS_ENABLED(CONFIG_SUNRPC_XPRT_RDMA)
|
#if IS_ENABLED(CONFIG_SUNRPC_XPRT_RDMA)
|
||||||
rpc_set_port(&ctx->nfs_server.address, NFS_RDMA_PORT);
|
rpc_set_port(&ctx->nfs_server.address, NFS_RDMA_PORT);
|
||||||
error = nfs4_set_client(server,
|
cl_init.proto = XPRT_TRANSPORT_RDMA;
|
||||||
ctx->nfs_server.hostname,
|
error = nfs4_set_client(server, &cl_init);
|
||||||
&ctx->nfs_server._address,
|
|
||||||
ctx->nfs_server.addrlen,
|
|
||||||
parent_client->cl_ipaddr,
|
|
||||||
XPRT_TRANSPORT_RDMA,
|
|
||||||
parent_server->client->cl_timeout,
|
|
||||||
parent_client->cl_mvops->minor_version,
|
|
||||||
parent_client->cl_nconnect,
|
|
||||||
parent_client->cl_max_connect,
|
|
||||||
parent_client->cl_net,
|
|
||||||
&parent_client->cl_xprtsec);
|
|
||||||
if (!error)
|
if (!error)
|
||||||
goto init_server;
|
goto init_server;
|
||||||
#endif /* IS_ENABLED(CONFIG_SUNRPC_XPRT_RDMA) */
|
#endif /* IS_ENABLED(CONFIG_SUNRPC_XPRT_RDMA) */
|
||||||
|
|
||||||
proto = XPRT_TRANSPORT_TCP;
|
cl_init.proto = XPRT_TRANSPORT_TCP;
|
||||||
if (parent_client->cl_xprtsec.policy != RPC_XPRTSEC_NONE)
|
if (parent_client->cl_xprtsec.policy != RPC_XPRTSEC_NONE)
|
||||||
proto = XPRT_TRANSPORT_TCP_TLS;
|
cl_init.proto = XPRT_TRANSPORT_TCP_TLS;
|
||||||
rpc_set_port(&ctx->nfs_server.address, NFS_PORT);
|
rpc_set_port(&ctx->nfs_server.address, NFS_PORT);
|
||||||
error = nfs4_set_client(server,
|
error = nfs4_set_client(server, &cl_init);
|
||||||
ctx->nfs_server.hostname,
|
|
||||||
&ctx->nfs_server._address,
|
|
||||||
ctx->nfs_server.addrlen,
|
|
||||||
parent_client->cl_ipaddr,
|
|
||||||
proto,
|
|
||||||
parent_server->client->cl_timeout,
|
|
||||||
parent_client->cl_mvops->minor_version,
|
|
||||||
parent_client->cl_nconnect,
|
|
||||||
parent_client->cl_max_connect,
|
|
||||||
parent_client->cl_net,
|
|
||||||
&parent_client->cl_xprtsec);
|
|
||||||
if (error < 0)
|
if (error < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
@ -1353,6 +1315,19 @@ int nfs4_update_server(struct nfs_server *server, const char *hostname,
|
||||||
char buf[INET6_ADDRSTRLEN + 1];
|
char buf[INET6_ADDRSTRLEN + 1];
|
||||||
struct sockaddr_storage address;
|
struct sockaddr_storage address;
|
||||||
struct sockaddr *localaddr = (struct sockaddr *)&address;
|
struct sockaddr *localaddr = (struct sockaddr *)&address;
|
||||||
|
struct nfs_client_initdata cl_init = {
|
||||||
|
.hostname = hostname,
|
||||||
|
.addr = sap,
|
||||||
|
.addrlen = salen,
|
||||||
|
.ip_addr = buf,
|
||||||
|
.proto = clp->cl_proto,
|
||||||
|
.minorversion = clp->cl_minorversion,
|
||||||
|
.net = net,
|
||||||
|
.timeparms = clnt->cl_timeout,
|
||||||
|
.xprtsec = clp->cl_xprtsec,
|
||||||
|
.nconnect = clp->cl_nconnect,
|
||||||
|
.max_connect = clp->cl_max_connect,
|
||||||
|
};
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
error = rpc_switch_client_transport(clnt, &xargs, clnt->cl_timeout);
|
error = rpc_switch_client_transport(clnt, &xargs, clnt->cl_timeout);
|
||||||
|
@ -1368,11 +1343,7 @@ int nfs4_update_server(struct nfs_server *server, const char *hostname,
|
||||||
|
|
||||||
nfs_server_remove_lists(server);
|
nfs_server_remove_lists(server);
|
||||||
set_bit(NFS_MIG_TSM_POSSIBLE, &server->mig_status);
|
set_bit(NFS_MIG_TSM_POSSIBLE, &server->mig_status);
|
||||||
error = nfs4_set_client(server, hostname, sap, salen, buf,
|
error = nfs4_set_client(server, &cl_init);
|
||||||
clp->cl_proto, clnt->cl_timeout,
|
|
||||||
clp->cl_minorversion,
|
|
||||||
clp->cl_nconnect, clp->cl_max_connect,
|
|
||||||
net, &clp->cl_xprtsec);
|
|
||||||
clear_bit(NFS_MIG_TSM_POSSIBLE, &server->mig_status);
|
clear_bit(NFS_MIG_TSM_POSSIBLE, &server->mig_status);
|
||||||
if (error != 0) {
|
if (error != 0) {
|
||||||
nfs_server_insert_lists(server);
|
nfs_server_insert_lists(server);
|
||||||
|
|
|
@ -253,7 +253,6 @@ static loff_t nfs42_remap_file_range(struct file *src_file, loff_t src_off,
|
||||||
struct nfs_server *server = NFS_SERVER(dst_inode);
|
struct nfs_server *server = NFS_SERVER(dst_inode);
|
||||||
struct inode *src_inode = file_inode(src_file);
|
struct inode *src_inode = file_inode(src_file);
|
||||||
unsigned int bs = server->clone_blksize;
|
unsigned int bs = server->clone_blksize;
|
||||||
bool same_inode = false;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* NFS does not support deduplication. */
|
/* NFS does not support deduplication. */
|
||||||
|
@ -275,20 +274,8 @@ static loff_t nfs42_remap_file_range(struct file *src_file, loff_t src_off,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (src_inode == dst_inode)
|
|
||||||
same_inode = true;
|
|
||||||
|
|
||||||
/* XXX: do we lock at all? what if server needs CB_RECALL_LAYOUT? */
|
/* XXX: do we lock at all? what if server needs CB_RECALL_LAYOUT? */
|
||||||
if (same_inode) {
|
lock_two_nondirectories(src_inode, dst_inode);
|
||||||
inode_lock(src_inode);
|
|
||||||
} else if (dst_inode < src_inode) {
|
|
||||||
inode_lock_nested(dst_inode, I_MUTEX_PARENT);
|
|
||||||
inode_lock_nested(src_inode, I_MUTEX_CHILD);
|
|
||||||
} else {
|
|
||||||
inode_lock_nested(src_inode, I_MUTEX_PARENT);
|
|
||||||
inode_lock_nested(dst_inode, I_MUTEX_CHILD);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* flush all pending writes on both src and dst so that server
|
/* flush all pending writes on both src and dst so that server
|
||||||
* has the latest data */
|
* has the latest data */
|
||||||
ret = nfs_sync_inode(src_inode);
|
ret = nfs_sync_inode(src_inode);
|
||||||
|
@ -306,15 +293,7 @@ static loff_t nfs42_remap_file_range(struct file *src_file, loff_t src_off,
|
||||||
truncate_inode_pages_range(&dst_inode->i_data, dst_off, dst_off + count - 1);
|
truncate_inode_pages_range(&dst_inode->i_data, dst_off, dst_off + count - 1);
|
||||||
|
|
||||||
out_unlock:
|
out_unlock:
|
||||||
if (same_inode) {
|
unlock_two_nondirectories(src_inode, dst_inode);
|
||||||
inode_unlock(src_inode);
|
|
||||||
} else if (dst_inode < src_inode) {
|
|
||||||
inode_unlock(src_inode);
|
|
||||||
inode_unlock(dst_inode);
|
|
||||||
} else {
|
|
||||||
inode_unlock(dst_inode);
|
|
||||||
inode_unlock(src_inode);
|
|
||||||
}
|
|
||||||
out:
|
out:
|
||||||
return ret < 0 ? ret : count;
|
return ret < 0 ? ret : count;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,30 +12,28 @@
|
||||||
|
|
||||||
int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh *mntfh, bool auth_probe)
|
int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh *mntfh, bool auth_probe)
|
||||||
{
|
{
|
||||||
struct nfs_fsinfo fsinfo;
|
struct nfs_fattr *fattr = nfs_alloc_fattr();
|
||||||
int ret = -ENOMEM;
|
int ret = -ENOMEM;
|
||||||
|
|
||||||
fsinfo.fattr = nfs_alloc_fattr();
|
if (fattr == NULL)
|
||||||
if (fsinfo.fattr == NULL)
|
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/* Start by getting the root filehandle from the server */
|
/* Start by getting the root filehandle from the server */
|
||||||
ret = nfs4_proc_get_rootfh(server, mntfh, &fsinfo, auth_probe);
|
ret = nfs4_proc_get_rootfh(server, mntfh, fattr, auth_probe);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dprintk("nfs4_get_rootfh: getroot error = %d\n", -ret);
|
dprintk("nfs4_get_rootfh: getroot error = %d\n", -ret);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(fsinfo.fattr->valid & NFS_ATTR_FATTR_TYPE)
|
if (!(fattr->valid & NFS_ATTR_FATTR_TYPE) || !S_ISDIR(fattr->mode)) {
|
||||||
|| !S_ISDIR(fsinfo.fattr->mode)) {
|
|
||||||
printk(KERN_ERR "nfs4_get_rootfh:"
|
printk(KERN_ERR "nfs4_get_rootfh:"
|
||||||
" getroot encountered non-directory\n");
|
" getroot encountered non-directory\n");
|
||||||
ret = -ENOTDIR;
|
ret = -ENOTDIR;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(&server->fsid, &fsinfo.fattr->fsid, sizeof(server->fsid));
|
memcpy(&server->fsid, &fattr->fsid, sizeof(server->fsid));
|
||||||
out:
|
out:
|
||||||
nfs_free_fattr(fsinfo.fattr);
|
nfs_free_fattr(fattr);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -222,6 +222,7 @@ const u32 nfs4_fattr_bitmap[3] = {
|
||||||
| FATTR4_WORD1_RAWDEV
|
| FATTR4_WORD1_RAWDEV
|
||||||
| FATTR4_WORD1_SPACE_USED
|
| FATTR4_WORD1_SPACE_USED
|
||||||
| FATTR4_WORD1_TIME_ACCESS
|
| FATTR4_WORD1_TIME_ACCESS
|
||||||
|
| FATTR4_WORD1_TIME_CREATE
|
||||||
| FATTR4_WORD1_TIME_METADATA
|
| FATTR4_WORD1_TIME_METADATA
|
||||||
| FATTR4_WORD1_TIME_MODIFY
|
| FATTR4_WORD1_TIME_MODIFY
|
||||||
| FATTR4_WORD1_MOUNTED_ON_FILEID,
|
| FATTR4_WORD1_MOUNTED_ON_FILEID,
|
||||||
|
@ -243,6 +244,7 @@ static const u32 nfs4_pnfs_open_bitmap[3] = {
|
||||||
| FATTR4_WORD1_RAWDEV
|
| FATTR4_WORD1_RAWDEV
|
||||||
| FATTR4_WORD1_SPACE_USED
|
| FATTR4_WORD1_SPACE_USED
|
||||||
| FATTR4_WORD1_TIME_ACCESS
|
| FATTR4_WORD1_TIME_ACCESS
|
||||||
|
| FATTR4_WORD1_TIME_CREATE
|
||||||
| FATTR4_WORD1_TIME_METADATA
|
| FATTR4_WORD1_TIME_METADATA
|
||||||
| FATTR4_WORD1_TIME_MODIFY,
|
| FATTR4_WORD1_TIME_MODIFY,
|
||||||
FATTR4_WORD2_MDSTHRESHOLD
|
FATTR4_WORD2_MDSTHRESHOLD
|
||||||
|
@ -323,6 +325,9 @@ static void nfs4_bitmap_copy_adjust(__u32 *dst, const __u32 *src,
|
||||||
if (!(cache_validity & NFS_INO_INVALID_OTHER))
|
if (!(cache_validity & NFS_INO_INVALID_OTHER))
|
||||||
dst[1] &= ~(FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP);
|
dst[1] &= ~(FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP);
|
||||||
|
|
||||||
|
if (!(cache_validity & NFS_INO_INVALID_BTIME))
|
||||||
|
dst[1] &= ~FATTR4_WORD1_TIME_CREATE;
|
||||||
|
|
||||||
if (nfs_have_delegated_mtime(inode)) {
|
if (nfs_have_delegated_mtime(inode)) {
|
||||||
if (!(cache_validity & NFS_INO_INVALID_ATIME))
|
if (!(cache_validity & NFS_INO_INVALID_ATIME))
|
||||||
dst[1] &= ~(FATTR4_WORD1_TIME_ACCESS|FATTR4_WORD1_TIME_ACCESS_SET);
|
dst[1] &= ~(FATTR4_WORD1_TIME_ACCESS|FATTR4_WORD1_TIME_ACCESS_SET);
|
||||||
|
@ -1307,7 +1312,8 @@ nfs4_update_changeattr_locked(struct inode *inode,
|
||||||
NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL |
|
NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL |
|
||||||
NFS_INO_INVALID_SIZE | NFS_INO_INVALID_OTHER |
|
NFS_INO_INVALID_SIZE | NFS_INO_INVALID_OTHER |
|
||||||
NFS_INO_INVALID_BLOCKS | NFS_INO_INVALID_NLINK |
|
NFS_INO_INVALID_BLOCKS | NFS_INO_INVALID_NLINK |
|
||||||
NFS_INO_INVALID_MODE | NFS_INO_INVALID_XATTR;
|
NFS_INO_INVALID_MODE | NFS_INO_INVALID_BTIME |
|
||||||
|
NFS_INO_INVALID_XATTR;
|
||||||
nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
|
nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
|
||||||
}
|
}
|
||||||
nfsi->attrtimeo_timestamp = jiffies;
|
nfsi->attrtimeo_timestamp = jiffies;
|
||||||
|
@ -4047,6 +4053,10 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
|
||||||
server->fattr_valid &= ~NFS_ATTR_FATTR_CTIME;
|
server->fattr_valid &= ~NFS_ATTR_FATTR_CTIME;
|
||||||
if (!(res.attr_bitmask[1] & FATTR4_WORD1_TIME_MODIFY))
|
if (!(res.attr_bitmask[1] & FATTR4_WORD1_TIME_MODIFY))
|
||||||
server->fattr_valid &= ~NFS_ATTR_FATTR_MTIME;
|
server->fattr_valid &= ~NFS_ATTR_FATTR_MTIME;
|
||||||
|
if (!(res.attr_bitmask[1] & FATTR4_WORD1_TIME_MODIFY))
|
||||||
|
server->fattr_valid &= ~NFS_ATTR_FATTR_MTIME;
|
||||||
|
if (!(res.attr_bitmask[1] & FATTR4_WORD1_TIME_CREATE))
|
||||||
|
server->fattr_valid &= ~NFS_ATTR_FATTR_BTIME;
|
||||||
memcpy(server->attr_bitmask_nl, res.attr_bitmask,
|
memcpy(server->attr_bitmask_nl, res.attr_bitmask,
|
||||||
sizeof(server->attr_bitmask));
|
sizeof(server->attr_bitmask));
|
||||||
server->attr_bitmask_nl[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
|
server->attr_bitmask_nl[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
|
||||||
|
@ -4082,7 +4092,7 @@ int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
|
||||||
};
|
};
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
nfs4_server_set_init_caps(server);
|
nfs_server_set_init_caps(server);
|
||||||
do {
|
do {
|
||||||
err = nfs4_handle_exception(server,
|
err = nfs4_handle_exception(server,
|
||||||
_nfs4_server_capabilities(server, fhandle),
|
_nfs4_server_capabilities(server, fhandle),
|
||||||
|
@ -4230,15 +4240,18 @@ out:
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
|
static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
|
||||||
struct nfs_fsinfo *info)
|
struct nfs_fattr *fattr)
|
||||||
{
|
{
|
||||||
u32 bitmask[3];
|
u32 bitmask[3] = {
|
||||||
|
[0] = FATTR4_WORD0_TYPE | FATTR4_WORD0_CHANGE |
|
||||||
|
FATTR4_WORD0_SIZE | FATTR4_WORD0_FSID,
|
||||||
|
};
|
||||||
struct nfs4_lookup_root_arg args = {
|
struct nfs4_lookup_root_arg args = {
|
||||||
.bitmask = bitmask,
|
.bitmask = bitmask,
|
||||||
};
|
};
|
||||||
struct nfs4_lookup_res res = {
|
struct nfs4_lookup_res res = {
|
||||||
.server = server,
|
.server = server,
|
||||||
.fattr = info->fattr,
|
.fattr = fattr,
|
||||||
.fh = fhandle,
|
.fh = fhandle,
|
||||||
};
|
};
|
||||||
struct rpc_message msg = {
|
struct rpc_message msg = {
|
||||||
|
@ -4247,27 +4260,20 @@ static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
|
||||||
.rpc_resp = &res,
|
.rpc_resp = &res,
|
||||||
};
|
};
|
||||||
|
|
||||||
bitmask[0] = nfs4_fattr_bitmap[0];
|
nfs_fattr_init(fattr);
|
||||||
bitmask[1] = nfs4_fattr_bitmap[1];
|
|
||||||
/*
|
|
||||||
* Process the label in the upcoming getfattr
|
|
||||||
*/
|
|
||||||
bitmask[2] = nfs4_fattr_bitmap[2] & ~FATTR4_WORD2_SECURITY_LABEL;
|
|
||||||
|
|
||||||
nfs_fattr_init(info->fattr);
|
|
||||||
return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
|
return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
|
static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
|
||||||
struct nfs_fsinfo *info)
|
struct nfs_fattr *fattr)
|
||||||
{
|
{
|
||||||
struct nfs4_exception exception = {
|
struct nfs4_exception exception = {
|
||||||
.interruptible = true,
|
.interruptible = true,
|
||||||
};
|
};
|
||||||
int err;
|
int err;
|
||||||
do {
|
do {
|
||||||
err = _nfs4_lookup_root(server, fhandle, info);
|
err = _nfs4_lookup_root(server, fhandle, fattr);
|
||||||
trace_nfs4_lookup_root(server, fhandle, info->fattr, err);
|
trace_nfs4_lookup_root(server, fhandle, fattr, err);
|
||||||
switch (err) {
|
switch (err) {
|
||||||
case 0:
|
case 0:
|
||||||
case -NFS4ERR_WRONGSEC:
|
case -NFS4ERR_WRONGSEC:
|
||||||
|
@ -4280,8 +4286,9 @@ out:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nfs4_lookup_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
|
static int nfs4_lookup_root_sec(struct nfs_server *server,
|
||||||
struct nfs_fsinfo *info, rpc_authflavor_t flavor)
|
struct nfs_fh *fhandle, struct nfs_fattr *fattr,
|
||||||
|
rpc_authflavor_t flavor)
|
||||||
{
|
{
|
||||||
struct rpc_auth_create_args auth_args = {
|
struct rpc_auth_create_args auth_args = {
|
||||||
.pseudoflavor = flavor,
|
.pseudoflavor = flavor,
|
||||||
|
@ -4291,7 +4298,7 @@ static int nfs4_lookup_root_sec(struct nfs_server *server, struct nfs_fh *fhandl
|
||||||
auth = rpcauth_create(&auth_args, server->client);
|
auth = rpcauth_create(&auth_args, server->client);
|
||||||
if (IS_ERR(auth))
|
if (IS_ERR(auth))
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
return nfs4_lookup_root(server, fhandle, info);
|
return nfs4_lookup_root(server, fhandle, fattr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -4304,7 +4311,7 @@ static int nfs4_lookup_root_sec(struct nfs_server *server, struct nfs_fh *fhandl
|
||||||
* negative errno value.
|
* negative errno value.
|
||||||
*/
|
*/
|
||||||
static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
|
static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
|
||||||
struct nfs_fsinfo *info)
|
struct nfs_fattr *fattr)
|
||||||
{
|
{
|
||||||
/* Per 3530bis 15.33.5 */
|
/* Per 3530bis 15.33.5 */
|
||||||
static const rpc_authflavor_t flav_array[] = {
|
static const rpc_authflavor_t flav_array[] = {
|
||||||
|
@ -4320,8 +4327,9 @@ static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
|
||||||
if (server->auth_info.flavor_len > 0) {
|
if (server->auth_info.flavor_len > 0) {
|
||||||
/* try each flavor specified by user */
|
/* try each flavor specified by user */
|
||||||
for (i = 0; i < server->auth_info.flavor_len; i++) {
|
for (i = 0; i < server->auth_info.flavor_len; i++) {
|
||||||
status = nfs4_lookup_root_sec(server, fhandle, info,
|
status = nfs4_lookup_root_sec(
|
||||||
server->auth_info.flavors[i]);
|
server, fhandle, fattr,
|
||||||
|
server->auth_info.flavors[i]);
|
||||||
if (status == -NFS4ERR_WRONGSEC || status == -EACCES)
|
if (status == -NFS4ERR_WRONGSEC || status == -EACCES)
|
||||||
continue;
|
continue;
|
||||||
break;
|
break;
|
||||||
|
@ -4329,7 +4337,7 @@ static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
|
||||||
} else {
|
} else {
|
||||||
/* no flavors specified by user, try default list */
|
/* no flavors specified by user, try default list */
|
||||||
for (i = 0; i < ARRAY_SIZE(flav_array); i++) {
|
for (i = 0; i < ARRAY_SIZE(flav_array); i++) {
|
||||||
status = nfs4_lookup_root_sec(server, fhandle, info,
|
status = nfs4_lookup_root_sec(server, fhandle, fattr,
|
||||||
flav_array[i]);
|
flav_array[i]);
|
||||||
if (status == -NFS4ERR_WRONGSEC || status == -EACCES)
|
if (status == -NFS4ERR_WRONGSEC || status == -EACCES)
|
||||||
continue;
|
continue;
|
||||||
|
@ -4353,28 +4361,22 @@ static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
|
||||||
* nfs4_proc_get_rootfh - get file handle for server's pseudoroot
|
* nfs4_proc_get_rootfh - get file handle for server's pseudoroot
|
||||||
* @server: initialized nfs_server handle
|
* @server: initialized nfs_server handle
|
||||||
* @fhandle: we fill in the pseudo-fs root file handle
|
* @fhandle: we fill in the pseudo-fs root file handle
|
||||||
* @info: we fill in an FSINFO struct
|
* @fattr: we fill in a bare bones struct fattr
|
||||||
* @auth_probe: probe the auth flavours
|
* @auth_probe: probe the auth flavours
|
||||||
*
|
*
|
||||||
* Returns zero on success, or a negative errno.
|
* Returns zero on success, or a negative errno.
|
||||||
*/
|
*/
|
||||||
int nfs4_proc_get_rootfh(struct nfs_server *server, struct nfs_fh *fhandle,
|
int nfs4_proc_get_rootfh(struct nfs_server *server, struct nfs_fh *fhandle,
|
||||||
struct nfs_fsinfo *info,
|
struct nfs_fattr *fattr, bool auth_probe)
|
||||||
bool auth_probe)
|
|
||||||
{
|
{
|
||||||
int status = 0;
|
int status = 0;
|
||||||
|
|
||||||
if (!auth_probe)
|
if (!auth_probe)
|
||||||
status = nfs4_lookup_root(server, fhandle, info);
|
status = nfs4_lookup_root(server, fhandle, fattr);
|
||||||
|
|
||||||
if (auth_probe || status == NFS4ERR_WRONGSEC)
|
if (auth_probe || status == NFS4ERR_WRONGSEC)
|
||||||
status = server->nfs_client->cl_mvops->find_root_sec(server,
|
status = server->nfs_client->cl_mvops->find_root_sec(
|
||||||
fhandle, info);
|
server, fhandle, fattr);
|
||||||
|
|
||||||
if (status == 0)
|
|
||||||
status = nfs4_server_capabilities(server, fhandle);
|
|
||||||
if (status == 0)
|
|
||||||
status = nfs4_do_fsinfo(server, fhandle, info);
|
|
||||||
|
|
||||||
return nfs4_map_errors(status);
|
return nfs4_map_errors(status);
|
||||||
}
|
}
|
||||||
|
@ -5781,6 +5783,8 @@ void nfs4_bitmask_set(__u32 bitmask[], const __u32 src[],
|
||||||
bitmask[1] |= FATTR4_WORD1_TIME_MODIFY;
|
bitmask[1] |= FATTR4_WORD1_TIME_MODIFY;
|
||||||
if (cache_validity & NFS_INO_INVALID_BLOCKS)
|
if (cache_validity & NFS_INO_INVALID_BLOCKS)
|
||||||
bitmask[1] |= FATTR4_WORD1_SPACE_USED;
|
bitmask[1] |= FATTR4_WORD1_SPACE_USED;
|
||||||
|
if (cache_validity & NFS_INO_INVALID_BTIME)
|
||||||
|
bitmask[1] |= FATTR4_WORD1_TIME_CREATE;
|
||||||
|
|
||||||
if (cache_validity & NFS_INO_INVALID_SIZE)
|
if (cache_validity & NFS_INO_INVALID_SIZE)
|
||||||
bitmask[0] |= FATTR4_WORD0_SIZE;
|
bitmask[0] |= FATTR4_WORD0_SIZE;
|
||||||
|
@ -10339,10 +10343,10 @@ nfs4_proc_layoutcommit(struct nfs4_layoutcommit_data *data, bool sync)
|
||||||
* Use the state managment nfs_client cl_rpcclient, which uses krb5i (if
|
* Use the state managment nfs_client cl_rpcclient, which uses krb5i (if
|
||||||
* possible) as per RFC3530bis and RFC5661 Security Considerations sections
|
* possible) as per RFC3530bis and RFC5661 Security Considerations sections
|
||||||
*/
|
*/
|
||||||
static int
|
static int _nfs41_proc_secinfo_no_name(struct nfs_server *server,
|
||||||
_nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle,
|
struct nfs_fh *fhandle,
|
||||||
struct nfs_fsinfo *info,
|
struct nfs4_secinfo_flavors *flavors,
|
||||||
struct nfs4_secinfo_flavors *flavors, bool use_integrity)
|
bool use_integrity)
|
||||||
{
|
{
|
||||||
struct nfs41_secinfo_no_name_args args = {
|
struct nfs41_secinfo_no_name_args args = {
|
||||||
.style = SECINFO_STYLE_CURRENT_FH,
|
.style = SECINFO_STYLE_CURRENT_FH,
|
||||||
|
@ -10386,9 +10390,9 @@ _nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle,
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int nfs41_proc_secinfo_no_name(struct nfs_server *server,
|
||||||
nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle,
|
struct nfs_fh *fhandle,
|
||||||
struct nfs_fsinfo *info, struct nfs4_secinfo_flavors *flavors)
|
struct nfs4_secinfo_flavors *flavors)
|
||||||
{
|
{
|
||||||
struct nfs4_exception exception = {
|
struct nfs4_exception exception = {
|
||||||
.interruptible = true,
|
.interruptible = true,
|
||||||
|
@ -10400,7 +10404,7 @@ nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle,
|
||||||
|
|
||||||
/* try to use integrity protection with machine cred */
|
/* try to use integrity protection with machine cred */
|
||||||
if (_nfs4_is_integrity_protected(server->nfs_client))
|
if (_nfs4_is_integrity_protected(server->nfs_client))
|
||||||
err = _nfs41_proc_secinfo_no_name(server, fhandle, info,
|
err = _nfs41_proc_secinfo_no_name(server, fhandle,
|
||||||
flavors, true);
|
flavors, true);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -10410,7 +10414,7 @@ nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle,
|
||||||
* the current filesystem's rpc_client and the user cred.
|
* the current filesystem's rpc_client and the user cred.
|
||||||
*/
|
*/
|
||||||
if (err == -NFS4ERR_WRONGSEC)
|
if (err == -NFS4ERR_WRONGSEC)
|
||||||
err = _nfs41_proc_secinfo_no_name(server, fhandle, info,
|
err = _nfs41_proc_secinfo_no_name(server, fhandle,
|
||||||
flavors, false);
|
flavors, false);
|
||||||
|
|
||||||
switch (err) {
|
switch (err) {
|
||||||
|
@ -10426,9 +10430,8 @@ out:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int nfs41_find_root_sec(struct nfs_server *server,
|
||||||
nfs41_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
|
struct nfs_fh *fhandle, struct nfs_fattr *fattr)
|
||||||
struct nfs_fsinfo *info)
|
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
struct page *page;
|
struct page *page;
|
||||||
|
@ -10444,14 +10447,14 @@ nfs41_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
|
||||||
}
|
}
|
||||||
|
|
||||||
flavors = page_address(page);
|
flavors = page_address(page);
|
||||||
err = nfs41_proc_secinfo_no_name(server, fhandle, info, flavors);
|
err = nfs41_proc_secinfo_no_name(server, fhandle, flavors);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fall back on "guess and check" method if
|
* Fall back on "guess and check" method if
|
||||||
* the server doesn't support SECINFO_NO_NAME
|
* the server doesn't support SECINFO_NO_NAME
|
||||||
*/
|
*/
|
||||||
if (err == -NFS4ERR_WRONGSEC || err == -ENOTSUPP) {
|
if (err == -NFS4ERR_WRONGSEC || err == -ENOTSUPP) {
|
||||||
err = nfs4_find_root_sec(server, fhandle, info);
|
err = nfs4_find_root_sec(server, fhandle, fattr);
|
||||||
goto out_freepage;
|
goto out_freepage;
|
||||||
}
|
}
|
||||||
if (err)
|
if (err)
|
||||||
|
@ -10476,8 +10479,8 @@ nfs41_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
|
||||||
flavor = RPC_AUTH_MAXFLAVOR;
|
flavor = RPC_AUTH_MAXFLAVOR;
|
||||||
|
|
||||||
if (flavor != RPC_AUTH_MAXFLAVOR) {
|
if (flavor != RPC_AUTH_MAXFLAVOR) {
|
||||||
err = nfs4_lookup_root_sec(server, fhandle,
|
err = nfs4_lookup_root_sec(server, fhandle, fattr,
|
||||||
info, flavor);
|
flavor);
|
||||||
if (!err)
|
if (!err)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -10680,6 +10683,8 @@ nfs41_free_lock_state(struct nfs_server *server, struct nfs4_lock_state *lsp)
|
||||||
static bool nfs41_match_stateid(const nfs4_stateid *s1,
|
static bool nfs41_match_stateid(const nfs4_stateid *s1,
|
||||||
const nfs4_stateid *s2)
|
const nfs4_stateid *s2)
|
||||||
{
|
{
|
||||||
|
trace_nfs41_match_stateid(s1, s2);
|
||||||
|
|
||||||
if (s1->type != s2->type)
|
if (s1->type != s2->type)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -10697,6 +10702,8 @@ static bool nfs41_match_stateid(const nfs4_stateid *s1,
|
||||||
static bool nfs4_match_stateid(const nfs4_stateid *s1,
|
static bool nfs4_match_stateid(const nfs4_stateid *s1,
|
||||||
const nfs4_stateid *s2)
|
const nfs4_stateid *s2)
|
||||||
{
|
{
|
||||||
|
trace_nfs4_match_stateid(s1, s2);
|
||||||
|
|
||||||
return nfs4_stateid_match(s1, s2);
|
return nfs4_stateid_match(s1, s2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10867,7 +10874,7 @@ const struct nfs4_minor_version_ops *nfs_v4_minor_ops[] = {
|
||||||
|
|
||||||
static ssize_t nfs4_listxattr(struct dentry *dentry, char *list, size_t size)
|
static ssize_t nfs4_listxattr(struct dentry *dentry, char *list, size_t size)
|
||||||
{
|
{
|
||||||
ssize_t error, error2, error3, error4;
|
ssize_t error, error2, error3, error4 = 0;
|
||||||
size_t left = size;
|
size_t left = size;
|
||||||
|
|
||||||
error = generic_listxattr(dentry, list, left);
|
error = generic_listxattr(dentry, list, left);
|
||||||
|
@ -10895,9 +10902,11 @@ static ssize_t nfs4_listxattr(struct dentry *dentry, char *list, size_t size)
|
||||||
left -= error3;
|
left -= error3;
|
||||||
}
|
}
|
||||||
|
|
||||||
error4 = security_inode_listsecurity(d_inode(dentry), list, left);
|
if (!nfs_server_capable(d_inode(dentry), NFS_CAP_SECURITY_LABEL)) {
|
||||||
if (error4 < 0)
|
error4 = security_inode_listsecurity(d_inode(dentry), list, left);
|
||||||
return error4;
|
if (error4 < 0)
|
||||||
|
return error4;
|
||||||
|
}
|
||||||
|
|
||||||
error += error2 + error3 + error4;
|
error += error2 + error3 + error4;
|
||||||
if (size && error > size)
|
if (size && error > size)
|
||||||
|
@ -10951,6 +10960,26 @@ static const struct inode_operations nfs4_file_inode_operations = {
|
||||||
.listxattr = nfs4_listxattr,
|
.listxattr = nfs4_listxattr,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct nfs_server *nfs4_clone_server(struct nfs_server *source,
|
||||||
|
struct nfs_fh *fh, struct nfs_fattr *fattr,
|
||||||
|
rpc_authflavor_t flavor)
|
||||||
|
{
|
||||||
|
struct nfs_server *server;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
server = nfs_clone_server(source, fh, fattr, flavor);
|
||||||
|
if (IS_ERR(server))
|
||||||
|
return server;
|
||||||
|
|
||||||
|
error = nfs4_delegation_hash_alloc(server);
|
||||||
|
if (error) {
|
||||||
|
nfs_free_server(server);
|
||||||
|
return ERR_PTR(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return server;
|
||||||
|
}
|
||||||
|
|
||||||
const struct nfs_rpc_ops nfs_v4_clientops = {
|
const struct nfs_rpc_ops nfs_v4_clientops = {
|
||||||
.version = 4, /* protocol version */
|
.version = 4, /* protocol version */
|
||||||
.dentry_ops = &nfs4_dentry_operations,
|
.dentry_ops = &nfs4_dentry_operations,
|
||||||
|
@ -11003,7 +11032,7 @@ const struct nfs_rpc_ops nfs_v4_clientops = {
|
||||||
.init_client = nfs4_init_client,
|
.init_client = nfs4_init_client,
|
||||||
.free_client = nfs4_free_client,
|
.free_client = nfs4_free_client,
|
||||||
.create_server = nfs4_create_server,
|
.create_server = nfs4_create_server,
|
||||||
.clone_server = nfs_clone_server,
|
.clone_server = nfs4_clone_server,
|
||||||
.discover_trunking = nfs4_discover_trunking,
|
.discover_trunking = nfs4_discover_trunking,
|
||||||
.enable_swap = nfs4_enable_swap,
|
.enable_swap = nfs4_enable_swap,
|
||||||
.disable_swap = nfs4_disable_swap,
|
.disable_swap = nfs4_disable_swap,
|
||||||
|
|
|
@ -26,11 +26,13 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(pnfs_mds_fallback_read_done);
|
||||||
EXPORT_TRACEPOINT_SYMBOL_GPL(pnfs_mds_fallback_write_done);
|
EXPORT_TRACEPOINT_SYMBOL_GPL(pnfs_mds_fallback_write_done);
|
||||||
EXPORT_TRACEPOINT_SYMBOL_GPL(pnfs_mds_fallback_read_pagelist);
|
EXPORT_TRACEPOINT_SYMBOL_GPL(pnfs_mds_fallback_read_pagelist);
|
||||||
EXPORT_TRACEPOINT_SYMBOL_GPL(pnfs_mds_fallback_write_pagelist);
|
EXPORT_TRACEPOINT_SYMBOL_GPL(pnfs_mds_fallback_write_pagelist);
|
||||||
|
EXPORT_TRACEPOINT_SYMBOL_GPL(pnfs_ds_connect);
|
||||||
|
|
||||||
EXPORT_TRACEPOINT_SYMBOL_GPL(ff_layout_read_error);
|
EXPORT_TRACEPOINT_SYMBOL_GPL(ff_layout_read_error);
|
||||||
EXPORT_TRACEPOINT_SYMBOL_GPL(ff_layout_write_error);
|
EXPORT_TRACEPOINT_SYMBOL_GPL(ff_layout_write_error);
|
||||||
EXPORT_TRACEPOINT_SYMBOL_GPL(ff_layout_commit_error);
|
EXPORT_TRACEPOINT_SYMBOL_GPL(ff_layout_commit_error);
|
||||||
|
|
||||||
|
EXPORT_TRACEPOINT_SYMBOL_GPL(bl_ext_tree_prepare_commit);
|
||||||
EXPORT_TRACEPOINT_SYMBOL_GPL(bl_pr_key_reg);
|
EXPORT_TRACEPOINT_SYMBOL_GPL(bl_pr_key_reg);
|
||||||
EXPORT_TRACEPOINT_SYMBOL_GPL(bl_pr_key_reg_err);
|
EXPORT_TRACEPOINT_SYMBOL_GPL(bl_pr_key_reg_err);
|
||||||
EXPORT_TRACEPOINT_SYMBOL_GPL(bl_pr_key_unreg);
|
EXPORT_TRACEPOINT_SYMBOL_GPL(bl_pr_key_unreg);
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
#include <trace/misc/fs.h>
|
#include <trace/misc/fs.h>
|
||||||
#include <trace/misc/nfs.h>
|
#include <trace/misc/nfs.h>
|
||||||
|
|
||||||
|
#include "delegation.h"
|
||||||
|
|
||||||
#define show_nfs_fattr_flags(valid) \
|
#define show_nfs_fattr_flags(valid) \
|
||||||
__print_flags((unsigned long)valid, "|", \
|
__print_flags((unsigned long)valid, "|", \
|
||||||
{ NFS_ATTR_FATTR_TYPE, "TYPE" }, \
|
{ NFS_ATTR_FATTR_TYPE, "TYPE" }, \
|
||||||
|
@ -30,7 +32,8 @@
|
||||||
{ NFS_ATTR_FATTR_CTIME, "CTIME" }, \
|
{ NFS_ATTR_FATTR_CTIME, "CTIME" }, \
|
||||||
{ NFS_ATTR_FATTR_CHANGE, "CHANGE" }, \
|
{ NFS_ATTR_FATTR_CHANGE, "CHANGE" }, \
|
||||||
{ NFS_ATTR_FATTR_OWNER_NAME, "OWNER_NAME" }, \
|
{ NFS_ATTR_FATTR_OWNER_NAME, "OWNER_NAME" }, \
|
||||||
{ NFS_ATTR_FATTR_GROUP_NAME, "GROUP_NAME" })
|
{ NFS_ATTR_FATTR_GROUP_NAME, "GROUP_NAME" }, \
|
||||||
|
{ NFS_ATTR_FATTR_BTIME, "BTIME" })
|
||||||
|
|
||||||
DECLARE_EVENT_CLASS(nfs4_clientid_event,
|
DECLARE_EVENT_CLASS(nfs4_clientid_event,
|
||||||
TP_PROTO(
|
TP_PROTO(
|
||||||
|
@ -273,6 +276,32 @@ TRACE_EVENT(nfs4_cb_offload,
|
||||||
show_nfs_stable_how(__entry->cb_how)
|
show_nfs_stable_how(__entry->cb_how)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
TRACE_EVENT(pnfs_ds_connect,
|
||||||
|
TP_PROTO(
|
||||||
|
char *ds_remotestr,
|
||||||
|
int status
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_ARGS(ds_remotestr, status),
|
||||||
|
|
||||||
|
TP_STRUCT__entry(
|
||||||
|
__string(ds_ips, ds_remotestr)
|
||||||
|
__field(int, status)
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_fast_assign(
|
||||||
|
__assign_str(ds_ips);
|
||||||
|
__entry->status = status;
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_printk(
|
||||||
|
"ds_ips=%s, status=%d",
|
||||||
|
__get_str(ds_ips),
|
||||||
|
__entry->status
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
#endif /* CONFIG_NFS_V4_1 */
|
#endif /* CONFIG_NFS_V4_1 */
|
||||||
|
|
||||||
TRACE_EVENT(nfs4_setup_sequence,
|
TRACE_EVENT(nfs4_setup_sequence,
|
||||||
|
@ -956,6 +985,52 @@ DECLARE_EVENT_CLASS(nfs4_set_delegation_event,
|
||||||
TP_ARGS(inode, fmode))
|
TP_ARGS(inode, fmode))
|
||||||
DEFINE_NFS4_SET_DELEGATION_EVENT(nfs4_set_delegation);
|
DEFINE_NFS4_SET_DELEGATION_EVENT(nfs4_set_delegation);
|
||||||
DEFINE_NFS4_SET_DELEGATION_EVENT(nfs4_reclaim_delegation);
|
DEFINE_NFS4_SET_DELEGATION_EVENT(nfs4_reclaim_delegation);
|
||||||
|
DEFINE_NFS4_SET_DELEGATION_EVENT(nfs4_detach_delegation);
|
||||||
|
|
||||||
|
#define show_delegation_flags(flags) \
|
||||||
|
__print_flags(flags, "|", \
|
||||||
|
{ BIT(NFS_DELEGATION_NEED_RECLAIM), "NEED_RECLAIM" }, \
|
||||||
|
{ BIT(NFS_DELEGATION_RETURN), "RETURN" }, \
|
||||||
|
{ BIT(NFS_DELEGATION_RETURN_IF_CLOSED), "RETURN_IF_CLOSED" }, \
|
||||||
|
{ BIT(NFS_DELEGATION_REFERENCED), "REFERENCED" }, \
|
||||||
|
{ BIT(NFS_DELEGATION_RETURNING), "RETURNING" }, \
|
||||||
|
{ BIT(NFS_DELEGATION_REVOKED), "REVOKED" }, \
|
||||||
|
{ BIT(NFS_DELEGATION_TEST_EXPIRED), "TEST_EXPIRED" }, \
|
||||||
|
{ BIT(NFS_DELEGATION_INODE_FREEING), "INODE_FREEING" }, \
|
||||||
|
{ BIT(NFS_DELEGATION_RETURN_DELAYED), "RETURN_DELAYED" })
|
||||||
|
|
||||||
|
DECLARE_EVENT_CLASS(nfs4_delegation_event,
|
||||||
|
TP_PROTO(
|
||||||
|
const struct nfs_delegation *delegation
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_ARGS(delegation),
|
||||||
|
|
||||||
|
TP_STRUCT__entry(
|
||||||
|
__field(u32, fhandle)
|
||||||
|
__field(unsigned int, fmode)
|
||||||
|
__field(unsigned long, flags)
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_fast_assign(
|
||||||
|
__entry->fhandle = nfs_fhandle_hash(NFS_FH(delegation->inode));
|
||||||
|
__entry->fmode = delegation->type;
|
||||||
|
__entry->flags = delegation->flags;
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_printk(
|
||||||
|
"fhandle=0x%08x fmode=%s flags=%s",
|
||||||
|
__entry->fhandle, show_fs_fmode_flags(__entry->fmode),
|
||||||
|
show_delegation_flags(__entry->flags)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
#define DEFINE_NFS4_DELEGATION_EVENT(name) \
|
||||||
|
DEFINE_EVENT(nfs4_delegation_event, name, \
|
||||||
|
TP_PROTO( \
|
||||||
|
const struct nfs_delegation *delegation \
|
||||||
|
), \
|
||||||
|
TP_ARGS(delegation))
|
||||||
|
DEFINE_NFS4_DELEGATION_EVENT(nfs_delegation_need_return);
|
||||||
|
|
||||||
TRACE_EVENT(nfs4_delegreturn_exit,
|
TRACE_EVENT(nfs4_delegreturn_exit,
|
||||||
TP_PROTO(
|
TP_PROTO(
|
||||||
|
@ -1449,6 +1524,63 @@ DECLARE_EVENT_CLASS(nfs4_inode_stateid_callback_event,
|
||||||
DEFINE_NFS4_INODE_STATEID_CALLBACK_EVENT(nfs4_cb_recall);
|
DEFINE_NFS4_INODE_STATEID_CALLBACK_EVENT(nfs4_cb_recall);
|
||||||
DEFINE_NFS4_INODE_STATEID_CALLBACK_EVENT(nfs4_cb_layoutrecall_file);
|
DEFINE_NFS4_INODE_STATEID_CALLBACK_EVENT(nfs4_cb_layoutrecall_file);
|
||||||
|
|
||||||
|
#define show_stateid_type(type) \
|
||||||
|
__print_symbolic(type, \
|
||||||
|
{ NFS4_INVALID_STATEID_TYPE, "INVALID" }, \
|
||||||
|
{ NFS4_SPECIAL_STATEID_TYPE, "SPECIAL" }, \
|
||||||
|
{ NFS4_OPEN_STATEID_TYPE, "OPEN" }, \
|
||||||
|
{ NFS4_LOCK_STATEID_TYPE, "LOCK" }, \
|
||||||
|
{ NFS4_DELEGATION_STATEID_TYPE, "DELEGATION" }, \
|
||||||
|
{ NFS4_LAYOUT_STATEID_TYPE, "LAYOUT" }, \
|
||||||
|
{ NFS4_PNFS_DS_STATEID_TYPE, "PNFS_DS" }, \
|
||||||
|
{ NFS4_REVOKED_STATEID_TYPE, "REVOKED" }, \
|
||||||
|
{ NFS4_FREED_STATEID_TYPE, "FREED" })
|
||||||
|
|
||||||
|
DECLARE_EVENT_CLASS(nfs4_match_stateid_event,
|
||||||
|
TP_PROTO(
|
||||||
|
const nfs4_stateid *s1,
|
||||||
|
const nfs4_stateid *s2
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_ARGS(s1, s2),
|
||||||
|
|
||||||
|
TP_STRUCT__entry(
|
||||||
|
__field(int, s1_seq)
|
||||||
|
__field(int, s2_seq)
|
||||||
|
__field(u32, s1_hash)
|
||||||
|
__field(u32, s2_hash)
|
||||||
|
__field(int, s1_type)
|
||||||
|
__field(int, s2_type)
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_fast_assign(
|
||||||
|
__entry->s1_seq = s1->seqid;
|
||||||
|
__entry->s1_hash = nfs_stateid_hash(s1);
|
||||||
|
__entry->s1_type = s1->type;
|
||||||
|
__entry->s2_seq = s2->seqid;
|
||||||
|
__entry->s2_hash = nfs_stateid_hash(s2);
|
||||||
|
__entry->s2_type = s2->type;
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_printk(
|
||||||
|
"s1=%s:%x:%u s2=%s:%x:%u",
|
||||||
|
show_stateid_type(__entry->s1_type),
|
||||||
|
__entry->s1_hash, __entry->s1_seq,
|
||||||
|
show_stateid_type(__entry->s2_type),
|
||||||
|
__entry->s2_hash, __entry->s2_seq
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
#define DEFINE_NFS4_MATCH_STATEID_EVENT(name) \
|
||||||
|
DEFINE_EVENT(nfs4_match_stateid_event, name, \
|
||||||
|
TP_PROTO( \
|
||||||
|
const nfs4_stateid *s1, \
|
||||||
|
const nfs4_stateid *s2 \
|
||||||
|
), \
|
||||||
|
TP_ARGS(s1, s2))
|
||||||
|
DEFINE_NFS4_MATCH_STATEID_EVENT(nfs41_match_stateid);
|
||||||
|
DEFINE_NFS4_MATCH_STATEID_EVENT(nfs4_match_stateid);
|
||||||
|
|
||||||
DECLARE_EVENT_CLASS(nfs4_idmap_event,
|
DECLARE_EVENT_CLASS(nfs4_idmap_event,
|
||||||
TP_PROTO(
|
TP_PROTO(
|
||||||
const char *name,
|
const char *name,
|
||||||
|
@ -2163,6 +2295,40 @@ TRACE_EVENT(ff_layout_commit_error,
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
TRACE_EVENT(bl_ext_tree_prepare_commit,
|
||||||
|
TP_PROTO(
|
||||||
|
int ret,
|
||||||
|
size_t count,
|
||||||
|
u64 lwb,
|
||||||
|
bool not_all_ranges
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_ARGS(ret, count, lwb, not_all_ranges),
|
||||||
|
|
||||||
|
TP_STRUCT__entry(
|
||||||
|
__field(int, ret)
|
||||||
|
__field(size_t, count)
|
||||||
|
__field(u64, lwb)
|
||||||
|
__field(bool, not_all_ranges)
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_fast_assign(
|
||||||
|
__entry->ret = ret;
|
||||||
|
__entry->count = count;
|
||||||
|
__entry->lwb = lwb;
|
||||||
|
__entry->not_all_ranges = not_all_ranges;
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_printk(
|
||||||
|
"ret=%d, found %zu ranges, lwb=%llu%s",
|
||||||
|
__entry->ret,
|
||||||
|
__entry->count,
|
||||||
|
__entry->lwb,
|
||||||
|
__entry->not_all_ranges ? ", not all ranges encoded" :
|
||||||
|
""
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
DECLARE_EVENT_CLASS(pnfs_bl_pr_key_class,
|
DECLARE_EVENT_CLASS(pnfs_bl_pr_key_class,
|
||||||
TP_PROTO(
|
TP_PROTO(
|
||||||
const struct block_device *bdev,
|
const struct block_device *bdev,
|
||||||
|
|
|
@ -1623,6 +1623,7 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg
|
||||||
| FATTR4_WORD1_RAWDEV
|
| FATTR4_WORD1_RAWDEV
|
||||||
| FATTR4_WORD1_SPACE_USED
|
| FATTR4_WORD1_SPACE_USED
|
||||||
| FATTR4_WORD1_TIME_ACCESS
|
| FATTR4_WORD1_TIME_ACCESS
|
||||||
|
| FATTR4_WORD1_TIME_CREATE
|
||||||
| FATTR4_WORD1_TIME_METADATA
|
| FATTR4_WORD1_TIME_METADATA
|
||||||
| FATTR4_WORD1_TIME_MODIFY;
|
| FATTR4_WORD1_TIME_MODIFY;
|
||||||
attrs[2] |= FATTR4_WORD2_SECURITY_LABEL;
|
attrs[2] |= FATTR4_WORD2_SECURITY_LABEL;
|
||||||
|
@ -4207,6 +4208,24 @@ static int decode_attr_time_access(struct xdr_stream *xdr, uint32_t *bitmap, str
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int decode_attr_time_create(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec64 *time)
|
||||||
|
{
|
||||||
|
int status = 0;
|
||||||
|
|
||||||
|
time->tv_sec = 0;
|
||||||
|
time->tv_nsec = 0;
|
||||||
|
if (unlikely(bitmap[1] & (FATTR4_WORD1_TIME_CREATE - 1U)))
|
||||||
|
return -EIO;
|
||||||
|
if (likely(bitmap[1] & FATTR4_WORD1_TIME_CREATE)) {
|
||||||
|
status = decode_attr_time(xdr, time);
|
||||||
|
if (status == 0)
|
||||||
|
status = NFS_ATTR_FATTR_BTIME;
|
||||||
|
bitmap[1] &= ~FATTR4_WORD1_TIME_CREATE;
|
||||||
|
}
|
||||||
|
dprintk("%s: btime=%lld\n", __func__, time->tv_sec);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
static int decode_attr_time_metadata(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec64 *time)
|
static int decode_attr_time_metadata(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec64 *time)
|
||||||
{
|
{
|
||||||
int status = 0;
|
int status = 0;
|
||||||
|
@ -4781,6 +4800,11 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
|
||||||
goto xdr_error;
|
goto xdr_error;
|
||||||
fattr->valid |= status;
|
fattr->valid |= status;
|
||||||
|
|
||||||
|
status = decode_attr_time_create(xdr, bitmap, &fattr->btime);
|
||||||
|
if (status < 0)
|
||||||
|
goto xdr_error;
|
||||||
|
fattr->valid |= status;
|
||||||
|
|
||||||
status = decode_attr_time_metadata(xdr, bitmap, &fattr->ctime);
|
status = decode_attr_time_metadata(xdr, bitmap, &fattr->ctime);
|
||||||
if (status < 0)
|
if (status < 0)
|
||||||
goto xdr_error;
|
goto xdr_error;
|
||||||
|
|
|
@ -32,7 +32,8 @@
|
||||||
{ NFS_INO_INVALID_BLOCKS, "INVALID_BLOCKS" }, \
|
{ NFS_INO_INVALID_BLOCKS, "INVALID_BLOCKS" }, \
|
||||||
{ NFS_INO_INVALID_XATTR, "INVALID_XATTR" }, \
|
{ NFS_INO_INVALID_XATTR, "INVALID_XATTR" }, \
|
||||||
{ NFS_INO_INVALID_NLINK, "INVALID_NLINK" }, \
|
{ NFS_INO_INVALID_NLINK, "INVALID_NLINK" }, \
|
||||||
{ NFS_INO_INVALID_MODE, "INVALID_MODE" })
|
{ NFS_INO_INVALID_MODE, "INVALID_MODE" }, \
|
||||||
|
{ NFS_INO_INVALID_BTIME, "INVALID_BTIME" })
|
||||||
|
|
||||||
#define nfs_show_nfsi_flags(v) \
|
#define nfs_show_nfsi_flags(v) \
|
||||||
__print_flags(v, "|", \
|
__print_flags(v, "|", \
|
||||||
|
@ -56,6 +57,7 @@ DECLARE_EVENT_CLASS(nfs_inode_event,
|
||||||
__field(u32, fhandle)
|
__field(u32, fhandle)
|
||||||
__field(u64, fileid)
|
__field(u64, fileid)
|
||||||
__field(u64, version)
|
__field(u64, version)
|
||||||
|
__field(unsigned long, cache_validity)
|
||||||
),
|
),
|
||||||
|
|
||||||
TP_fast_assign(
|
TP_fast_assign(
|
||||||
|
@ -64,14 +66,17 @@ DECLARE_EVENT_CLASS(nfs_inode_event,
|
||||||
__entry->fileid = nfsi->fileid;
|
__entry->fileid = nfsi->fileid;
|
||||||
__entry->fhandle = nfs_fhandle_hash(&nfsi->fh);
|
__entry->fhandle = nfs_fhandle_hash(&nfsi->fh);
|
||||||
__entry->version = inode_peek_iversion_raw(inode);
|
__entry->version = inode_peek_iversion_raw(inode);
|
||||||
|
__entry->cache_validity = nfsi->cache_validity;
|
||||||
),
|
),
|
||||||
|
|
||||||
TP_printk(
|
TP_printk(
|
||||||
"fileid=%02x:%02x:%llu fhandle=0x%08x version=%llu ",
|
"fileid=%02x:%02x:%llu fhandle=0x%08x version=%llu cache_validity=0x%lx (%s)",
|
||||||
MAJOR(__entry->dev), MINOR(__entry->dev),
|
MAJOR(__entry->dev), MINOR(__entry->dev),
|
||||||
(unsigned long long)__entry->fileid,
|
(unsigned long long)__entry->fileid,
|
||||||
__entry->fhandle,
|
__entry->fhandle,
|
||||||
(unsigned long long)__entry->version
|
(unsigned long long)__entry->version,
|
||||||
|
__entry->cache_validity,
|
||||||
|
nfs_show_cache_validity(__entry->cache_validity)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -306,7 +306,6 @@ void
|
||||||
pnfs_put_layout_hdr(struct pnfs_layout_hdr *lo)
|
pnfs_put_layout_hdr(struct pnfs_layout_hdr *lo)
|
||||||
{
|
{
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
unsigned long i_state;
|
|
||||||
|
|
||||||
if (!lo)
|
if (!lo)
|
||||||
return;
|
return;
|
||||||
|
@ -317,12 +316,11 @@ pnfs_put_layout_hdr(struct pnfs_layout_hdr *lo)
|
||||||
if (!list_empty(&lo->plh_segs))
|
if (!list_empty(&lo->plh_segs))
|
||||||
WARN_ONCE(1, "NFS: BUG unfreed layout segments.\n");
|
WARN_ONCE(1, "NFS: BUG unfreed layout segments.\n");
|
||||||
pnfs_detach_layout_hdr(lo);
|
pnfs_detach_layout_hdr(lo);
|
||||||
i_state = inode->i_state;
|
/* Notify pnfs_destroy_layout_final() that we're done */
|
||||||
|
if (inode->i_state & (I_FREEING | I_CLEAR))
|
||||||
|
wake_up_var_locked(lo, &inode->i_lock);
|
||||||
spin_unlock(&inode->i_lock);
|
spin_unlock(&inode->i_lock);
|
||||||
pnfs_free_layout_hdr(lo);
|
pnfs_free_layout_hdr(lo);
|
||||||
/* Notify pnfs_destroy_layout_final() that we're done */
|
|
||||||
if (i_state & (I_FREEING | I_CLEAR))
|
|
||||||
wake_up_var(lo);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -809,23 +807,17 @@ void pnfs_destroy_layout(struct nfs_inode *nfsi)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(pnfs_destroy_layout);
|
EXPORT_SYMBOL_GPL(pnfs_destroy_layout);
|
||||||
|
|
||||||
static bool pnfs_layout_removed(struct nfs_inode *nfsi,
|
|
||||||
struct pnfs_layout_hdr *lo)
|
|
||||||
{
|
|
||||||
bool ret;
|
|
||||||
|
|
||||||
spin_lock(&nfsi->vfs_inode.i_lock);
|
|
||||||
ret = nfsi->layout != lo;
|
|
||||||
spin_unlock(&nfsi->vfs_inode.i_lock);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void pnfs_destroy_layout_final(struct nfs_inode *nfsi)
|
void pnfs_destroy_layout_final(struct nfs_inode *nfsi)
|
||||||
{
|
{
|
||||||
struct pnfs_layout_hdr *lo = __pnfs_destroy_layout(nfsi);
|
struct pnfs_layout_hdr *lo = __pnfs_destroy_layout(nfsi);
|
||||||
|
struct inode *inode = &nfsi->vfs_inode;
|
||||||
|
|
||||||
if (lo)
|
if (lo) {
|
||||||
wait_var_event(lo, pnfs_layout_removed(nfsi, lo));
|
spin_lock(&inode->i_lock);
|
||||||
|
wait_var_event_spinlock(lo, nfsi->layout != lo,
|
||||||
|
&inode->i_lock);
|
||||||
|
spin_unlock(&inode->i_lock);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
@ -3340,6 +3332,7 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync)
|
||||||
struct nfs_inode *nfsi = NFS_I(inode);
|
struct nfs_inode *nfsi = NFS_I(inode);
|
||||||
loff_t end_pos;
|
loff_t end_pos;
|
||||||
int status;
|
int status;
|
||||||
|
bool mark_as_dirty = false;
|
||||||
|
|
||||||
if (!pnfs_layoutcommit_outstanding(inode))
|
if (!pnfs_layoutcommit_outstanding(inode))
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -3391,19 +3384,23 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync)
|
||||||
if (ld->prepare_layoutcommit) {
|
if (ld->prepare_layoutcommit) {
|
||||||
status = ld->prepare_layoutcommit(&data->args);
|
status = ld->prepare_layoutcommit(&data->args);
|
||||||
if (status) {
|
if (status) {
|
||||||
put_cred(data->cred);
|
if (status != -ENOSPC)
|
||||||
|
put_cred(data->cred);
|
||||||
spin_lock(&inode->i_lock);
|
spin_lock(&inode->i_lock);
|
||||||
set_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags);
|
set_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags);
|
||||||
if (end_pos > nfsi->layout->plh_lwb)
|
if (end_pos > nfsi->layout->plh_lwb)
|
||||||
nfsi->layout->plh_lwb = end_pos;
|
nfsi->layout->plh_lwb = end_pos;
|
||||||
goto out_unlock;
|
if (status != -ENOSPC)
|
||||||
|
goto out_unlock;
|
||||||
|
spin_unlock(&inode->i_lock);
|
||||||
|
mark_as_dirty = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status = nfs4_proc_layoutcommit(data, sync);
|
status = nfs4_proc_layoutcommit(data, sync);
|
||||||
out:
|
out:
|
||||||
if (status)
|
if (status || mark_as_dirty)
|
||||||
mark_inode_dirty_sync(inode);
|
mark_inode_dirty_sync(inode);
|
||||||
dprintk("<-- %s status %d\n", __func__, status);
|
dprintk("<-- %s status %d\n", __func__, status);
|
||||||
return status;
|
return status;
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
#include "pnfs.h"
|
#include "pnfs.h"
|
||||||
#include "netns.h"
|
#include "netns.h"
|
||||||
|
#include "nfs4trace.h"
|
||||||
|
|
||||||
#define NFSDBG_FACILITY NFSDBG_PNFS
|
#define NFSDBG_FACILITY NFSDBG_PNFS
|
||||||
|
|
||||||
|
@ -1007,8 +1008,10 @@ int nfs4_pnfs_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds,
|
||||||
err = nfs4_wait_ds_connect(ds);
|
err = nfs4_wait_ds_connect(ds);
|
||||||
if (err || ds->ds_clp)
|
if (err || ds->ds_clp)
|
||||||
goto out;
|
goto out;
|
||||||
if (nfs4_test_deviceid_unavailable(devid))
|
if (nfs4_test_deviceid_unavailable(devid)) {
|
||||||
return -ENODEV;
|
err = -ENODEV;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
} while (test_and_set_bit(NFS4DS_CONNECTING, &ds->ds_state) != 0);
|
} while (test_and_set_bit(NFS4DS_CONNECTING, &ds->ds_state) != 0);
|
||||||
|
|
||||||
if (ds->ds_clp)
|
if (ds->ds_clp)
|
||||||
|
@ -1038,11 +1041,12 @@ out:
|
||||||
if (!ds->ds_clp || !nfs_client_init_is_complete(ds->ds_clp)) {
|
if (!ds->ds_clp || !nfs_client_init_is_complete(ds->ds_clp)) {
|
||||||
WARN_ON_ONCE(ds->ds_clp ||
|
WARN_ON_ONCE(ds->ds_clp ||
|
||||||
!nfs4_test_deviceid_unavailable(devid));
|
!nfs4_test_deviceid_unavailable(devid));
|
||||||
return -EINVAL;
|
err = -EINVAL;
|
||||||
}
|
} else
|
||||||
err = nfs_client_init_status(ds->ds_clp);
|
err = nfs_client_init_status(ds->ds_clp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trace_pnfs_ds_connect(ds->ds_remotestr, err);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(nfs4_pnfs_ds_connect);
|
EXPORT_SYMBOL_GPL(nfs4_pnfs_ds_connect);
|
||||||
|
|
|
@ -2113,8 +2113,12 @@ int nfs_migrate_folio(struct address_space *mapping, struct folio *dst,
|
||||||
* that we can safely release the inode reference while holding
|
* that we can safely release the inode reference while holding
|
||||||
* the folio lock.
|
* the folio lock.
|
||||||
*/
|
*/
|
||||||
if (folio_test_private(src))
|
if (folio_test_private(src)) {
|
||||||
return -EBUSY;
|
if (mode == MIGRATE_SYNC)
|
||||||
|
nfs_wb_folio(src->mapping->host, src);
|
||||||
|
if (folio_test_private(src))
|
||||||
|
return -EBUSY;
|
||||||
|
}
|
||||||
|
|
||||||
if (folio_test_private_2(src)) { /* [DEPRECATED] */
|
if (folio_test_private_2(src)) { /* [DEPRECATED] */
|
||||||
if (mode == MIGRATE_ASYNC)
|
if (mode == MIGRATE_ASYNC)
|
||||||
|
|
|
@ -177,7 +177,7 @@ static bool nfs_uuid_put(nfs_uuid_t *nfs_uuid)
|
||||||
/* nfs_close_local_fh() is doing the
|
/* nfs_close_local_fh() is doing the
|
||||||
* close and we must wait. until it unlinks
|
* close and we must wait. until it unlinks
|
||||||
*/
|
*/
|
||||||
wait_var_event_spinlock(nfl,
|
wait_var_event_spinlock(nfs_uuid,
|
||||||
list_first_entry_or_null(
|
list_first_entry_or_null(
|
||||||
&nfs_uuid->files,
|
&nfs_uuid->files,
|
||||||
struct nfs_file_localio,
|
struct nfs_file_localio,
|
||||||
|
@ -198,8 +198,7 @@ static bool nfs_uuid_put(nfs_uuid_t *nfs_uuid)
|
||||||
/* Now we can allow racing nfs_close_local_fh() to
|
/* Now we can allow racing nfs_close_local_fh() to
|
||||||
* skip the locking.
|
* skip the locking.
|
||||||
*/
|
*/
|
||||||
RCU_INIT_POINTER(nfl->nfs_uuid, NULL);
|
store_release_wake_up(&nfl->nfs_uuid, RCU_INITIALIZER(NULL));
|
||||||
wake_up_var_locked(&nfl->nfs_uuid, &nfs_uuid->lock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remove client from nn->local_clients */
|
/* Remove client from nn->local_clients */
|
||||||
|
@ -243,15 +242,20 @@ void nfs_localio_invalidate_clients(struct list_head *nn_local_clients,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(nfs_localio_invalidate_clients);
|
EXPORT_SYMBOL_GPL(nfs_localio_invalidate_clients);
|
||||||
|
|
||||||
static void nfs_uuid_add_file(nfs_uuid_t *nfs_uuid, struct nfs_file_localio *nfl)
|
static int nfs_uuid_add_file(nfs_uuid_t *nfs_uuid, struct nfs_file_localio *nfl)
|
||||||
{
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
/* Add nfl to nfs_uuid->files if it isn't already */
|
/* Add nfl to nfs_uuid->files if it isn't already */
|
||||||
spin_lock(&nfs_uuid->lock);
|
spin_lock(&nfs_uuid->lock);
|
||||||
if (list_empty(&nfl->list)) {
|
if (rcu_access_pointer(nfs_uuid->net) == NULL) {
|
||||||
|
ret = -ENXIO;
|
||||||
|
} else if (list_empty(&nfl->list)) {
|
||||||
rcu_assign_pointer(nfl->nfs_uuid, nfs_uuid);
|
rcu_assign_pointer(nfl->nfs_uuid, nfs_uuid);
|
||||||
list_add_tail(&nfl->list, &nfs_uuid->files);
|
list_add_tail(&nfl->list, &nfs_uuid->files);
|
||||||
}
|
}
|
||||||
spin_unlock(&nfs_uuid->lock);
|
spin_unlock(&nfs_uuid->lock);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -285,11 +289,13 @@ struct nfsd_file *nfs_open_local_fh(nfs_uuid_t *uuid,
|
||||||
}
|
}
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
/* We have an implied reference to net thanks to nfsd_net_try_get */
|
/* We have an implied reference to net thanks to nfsd_net_try_get */
|
||||||
localio = nfs_to->nfsd_open_local_fh(net, uuid->dom, rpc_clnt,
|
localio = nfs_to->nfsd_open_local_fh(net, uuid->dom, rpc_clnt, cred,
|
||||||
cred, nfs_fh, pnf, fmode);
|
nfs_fh, pnf, fmode);
|
||||||
|
if (!IS_ERR(localio) && nfs_uuid_add_file(uuid, nfl) < 0) {
|
||||||
|
/* Delete the cached file when racing with nfs_uuid_put() */
|
||||||
|
nfs_to_nfsd_file_put_local(pnf);
|
||||||
|
}
|
||||||
nfs_to_nfsd_net_put(net);
|
nfs_to_nfsd_net_put(net);
|
||||||
if (!IS_ERR(localio))
|
|
||||||
nfs_uuid_add_file(uuid, nfl);
|
|
||||||
|
|
||||||
return localio;
|
return localio;
|
||||||
}
|
}
|
||||||
|
@ -314,7 +320,7 @@ void nfs_close_local_fh(struct nfs_file_localio *nfl)
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (list_empty(&nfs_uuid->files)) {
|
if (list_empty(&nfl->list)) {
|
||||||
/* nfs_uuid_put() has started closing files, wait for it
|
/* nfs_uuid_put() has started closing files, wait for it
|
||||||
* to finished
|
* to finished
|
||||||
*/
|
*/
|
||||||
|
@ -338,7 +344,7 @@ void nfs_close_local_fh(struct nfs_file_localio *nfl)
|
||||||
*/
|
*/
|
||||||
spin_lock(&nfs_uuid->lock);
|
spin_lock(&nfs_uuid->lock);
|
||||||
list_del_init(&nfl->list);
|
list_del_init(&nfl->list);
|
||||||
wake_up_var_locked(&nfl->nfs_uuid, &nfs_uuid->lock);
|
wake_up_var_locked(nfs_uuid, &nfs_uuid->lock);
|
||||||
spin_unlock(&nfs_uuid->lock);
|
spin_unlock(&nfs_uuid->lock);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(nfs_close_local_fh);
|
EXPORT_SYMBOL_GPL(nfs_close_local_fh);
|
||||||
|
|
|
@ -160,6 +160,12 @@ struct nfs_inode {
|
||||||
unsigned long flags; /* atomic bit ops */
|
unsigned long flags; /* atomic bit ops */
|
||||||
unsigned long cache_validity; /* bit mask */
|
unsigned long cache_validity; /* bit mask */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NFS Attributes not included in struct inode
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct timespec64 btime;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* read_cache_jiffies is when we started read-caching this inode.
|
* read_cache_jiffies is when we started read-caching this inode.
|
||||||
* attrtimeo is for how long the cached information is assumed
|
* attrtimeo is for how long the cached information is assumed
|
||||||
|
@ -316,10 +322,12 @@ struct nfs4_copy_state {
|
||||||
#define NFS_INO_INVALID_XATTR BIT(15) /* xattrs are invalid */
|
#define NFS_INO_INVALID_XATTR BIT(15) /* xattrs are invalid */
|
||||||
#define NFS_INO_INVALID_NLINK BIT(16) /* cached nlinks is invalid */
|
#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_MODE BIT(17) /* cached mode is invalid */
|
||||||
|
#define NFS_INO_INVALID_BTIME BIT(18) /* cached btime is invalid */
|
||||||
|
|
||||||
#define NFS_INO_INVALID_ATTR (NFS_INO_INVALID_CHANGE \
|
#define NFS_INO_INVALID_ATTR (NFS_INO_INVALID_CHANGE \
|
||||||
| NFS_INO_INVALID_CTIME \
|
| NFS_INO_INVALID_CTIME \
|
||||||
| NFS_INO_INVALID_MTIME \
|
| NFS_INO_INVALID_MTIME \
|
||||||
|
| NFS_INO_INVALID_BTIME \
|
||||||
| NFS_INO_INVALID_SIZE \
|
| NFS_INO_INVALID_SIZE \
|
||||||
| NFS_INO_INVALID_NLINK \
|
| NFS_INO_INVALID_NLINK \
|
||||||
| NFS_INO_INVALID_MODE \
|
| NFS_INO_INVALID_MODE \
|
||||||
|
|
|
@ -172,12 +172,11 @@ struct nfs_server {
|
||||||
#define NFS_MOUNT_FORCE_RDIRPLUS 0x20000000
|
#define NFS_MOUNT_FORCE_RDIRPLUS 0x20000000
|
||||||
#define NFS_MOUNT_NETUNREACH_FATAL 0x40000000
|
#define NFS_MOUNT_NETUNREACH_FATAL 0x40000000
|
||||||
|
|
||||||
unsigned int fattr_valid; /* Valid attributes */
|
|
||||||
unsigned int caps; /* server capabilities */
|
unsigned int caps; /* server capabilities */
|
||||||
|
__u64 fattr_valid; /* Valid attributes */
|
||||||
unsigned int rsize; /* read size */
|
unsigned int rsize; /* read size */
|
||||||
unsigned int rpages; /* read size (in pages) */
|
unsigned int rpages; /* read size (in pages) */
|
||||||
unsigned int wsize; /* write size */
|
unsigned int wsize; /* write size */
|
||||||
unsigned int wpages; /* write size (in pages) */
|
|
||||||
unsigned int wtmult; /* server disk block size */
|
unsigned int wtmult; /* server disk block size */
|
||||||
unsigned int dtsize; /* readdir size */
|
unsigned int dtsize; /* readdir size */
|
||||||
unsigned short port; /* "port=" setting */
|
unsigned short port; /* "port=" setting */
|
||||||
|
@ -203,7 +202,6 @@ struct nfs_server {
|
||||||
struct nfs_fsid fsid;
|
struct nfs_fsid fsid;
|
||||||
int s_sysfs_id; /* sysfs dentry index */
|
int s_sysfs_id; /* sysfs dentry index */
|
||||||
__u64 maxfilesize; /* maximum file size */
|
__u64 maxfilesize; /* maximum file size */
|
||||||
struct timespec64 time_delta; /* smallest time granularity */
|
|
||||||
unsigned long mount_time; /* when this fs was mounted */
|
unsigned long mount_time; /* when this fs was mounted */
|
||||||
struct super_block *super; /* VFS super block */
|
struct super_block *super; /* VFS super block */
|
||||||
dev_t s_dev; /* superblock dev numbers */
|
dev_t s_dev; /* superblock dev numbers */
|
||||||
|
@ -248,7 +246,6 @@ struct nfs_server {
|
||||||
filesystem */
|
filesystem */
|
||||||
struct pnfs_layoutdriver_type *pnfs_curr_ld; /* Active layout driver */
|
struct pnfs_layoutdriver_type *pnfs_curr_ld; /* Active layout driver */
|
||||||
struct rpc_wait_queue roc_rpcwaitq;
|
struct rpc_wait_queue roc_rpcwaitq;
|
||||||
void *pnfs_ld_data; /* per mount point data */
|
|
||||||
|
|
||||||
/* the following fields are protected by nfs_client->cl_lock */
|
/* the following fields are protected by nfs_client->cl_lock */
|
||||||
struct rb_root state_owners;
|
struct rb_root state_owners;
|
||||||
|
@ -257,6 +254,9 @@ struct nfs_server {
|
||||||
struct list_head state_owners_lru;
|
struct list_head state_owners_lru;
|
||||||
struct list_head layouts;
|
struct list_head layouts;
|
||||||
struct list_head delegations;
|
struct list_head delegations;
|
||||||
|
atomic_long_t nr_active_delegations;
|
||||||
|
unsigned int delegation_hash_mask;
|
||||||
|
struct hlist_head *delegation_hash_table;
|
||||||
struct list_head ss_copies;
|
struct list_head ss_copies;
|
||||||
struct list_head ss_src_copies;
|
struct list_head ss_src_copies;
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ struct nfs4_threshold {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nfs_fattr {
|
struct nfs_fattr {
|
||||||
unsigned int valid; /* which fields are valid */
|
__u64 valid; /* which fields are valid */
|
||||||
umode_t mode;
|
umode_t mode;
|
||||||
__u32 nlink;
|
__u32 nlink;
|
||||||
kuid_t uid;
|
kuid_t uid;
|
||||||
|
@ -67,6 +67,7 @@ struct nfs_fattr {
|
||||||
struct timespec64 atime;
|
struct timespec64 atime;
|
||||||
struct timespec64 mtime;
|
struct timespec64 mtime;
|
||||||
struct timespec64 ctime;
|
struct timespec64 ctime;
|
||||||
|
struct timespec64 btime;
|
||||||
__u64 change_attr; /* NFSv4 change attribute */
|
__u64 change_attr; /* NFSv4 change attribute */
|
||||||
__u64 pre_change_attr;/* pre-op NFSv4 change attribute */
|
__u64 pre_change_attr;/* pre-op NFSv4 change attribute */
|
||||||
__u64 pre_size; /* pre_op_attr.size */
|
__u64 pre_size; /* pre_op_attr.size */
|
||||||
|
@ -80,32 +81,33 @@ struct nfs_fattr {
|
||||||
struct nfs4_label *label;
|
struct nfs4_label *label;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define NFS_ATTR_FATTR_TYPE (1U << 0)
|
#define NFS_ATTR_FATTR_TYPE BIT_ULL(0)
|
||||||
#define NFS_ATTR_FATTR_MODE (1U << 1)
|
#define NFS_ATTR_FATTR_MODE BIT_ULL(1)
|
||||||
#define NFS_ATTR_FATTR_NLINK (1U << 2)
|
#define NFS_ATTR_FATTR_NLINK BIT_ULL(2)
|
||||||
#define NFS_ATTR_FATTR_OWNER (1U << 3)
|
#define NFS_ATTR_FATTR_OWNER BIT_ULL(3)
|
||||||
#define NFS_ATTR_FATTR_GROUP (1U << 4)
|
#define NFS_ATTR_FATTR_GROUP BIT_ULL(4)
|
||||||
#define NFS_ATTR_FATTR_RDEV (1U << 5)
|
#define NFS_ATTR_FATTR_RDEV BIT_ULL(5)
|
||||||
#define NFS_ATTR_FATTR_SIZE (1U << 6)
|
#define NFS_ATTR_FATTR_SIZE BIT_ULL(6)
|
||||||
#define NFS_ATTR_FATTR_PRESIZE (1U << 7)
|
#define NFS_ATTR_FATTR_PRESIZE BIT_ULL(7)
|
||||||
#define NFS_ATTR_FATTR_BLOCKS_USED (1U << 8)
|
#define NFS_ATTR_FATTR_BLOCKS_USED BIT_ULL(8)
|
||||||
#define NFS_ATTR_FATTR_SPACE_USED (1U << 9)
|
#define NFS_ATTR_FATTR_SPACE_USED BIT_ULL(9)
|
||||||
#define NFS_ATTR_FATTR_FSID (1U << 10)
|
#define NFS_ATTR_FATTR_FSID BIT_ULL(10)
|
||||||
#define NFS_ATTR_FATTR_FILEID (1U << 11)
|
#define NFS_ATTR_FATTR_FILEID BIT_ULL(11)
|
||||||
#define NFS_ATTR_FATTR_ATIME (1U << 12)
|
#define NFS_ATTR_FATTR_ATIME BIT_ULL(12)
|
||||||
#define NFS_ATTR_FATTR_MTIME (1U << 13)
|
#define NFS_ATTR_FATTR_MTIME BIT_ULL(13)
|
||||||
#define NFS_ATTR_FATTR_CTIME (1U << 14)
|
#define NFS_ATTR_FATTR_CTIME BIT_ULL(14)
|
||||||
#define NFS_ATTR_FATTR_PREMTIME (1U << 15)
|
#define NFS_ATTR_FATTR_PREMTIME BIT_ULL(15)
|
||||||
#define NFS_ATTR_FATTR_PRECTIME (1U << 16)
|
#define NFS_ATTR_FATTR_PRECTIME BIT_ULL(16)
|
||||||
#define NFS_ATTR_FATTR_CHANGE (1U << 17)
|
#define NFS_ATTR_FATTR_CHANGE BIT_ULL(17)
|
||||||
#define NFS_ATTR_FATTR_PRECHANGE (1U << 18)
|
#define NFS_ATTR_FATTR_PRECHANGE BIT_ULL(18)
|
||||||
#define NFS_ATTR_FATTR_V4_LOCATIONS (1U << 19)
|
#define NFS_ATTR_FATTR_V4_LOCATIONS BIT_ULL(19)
|
||||||
#define NFS_ATTR_FATTR_V4_REFERRAL (1U << 20)
|
#define NFS_ATTR_FATTR_V4_REFERRAL BIT_ULL(20)
|
||||||
#define NFS_ATTR_FATTR_MOUNTPOINT (1U << 21)
|
#define NFS_ATTR_FATTR_MOUNTPOINT BIT_ULL(21)
|
||||||
#define NFS_ATTR_FATTR_MOUNTED_ON_FILEID (1U << 22)
|
#define NFS_ATTR_FATTR_MOUNTED_ON_FILEID BIT_ULL(22)
|
||||||
#define NFS_ATTR_FATTR_OWNER_NAME (1U << 23)
|
#define NFS_ATTR_FATTR_OWNER_NAME BIT_ULL(23)
|
||||||
#define NFS_ATTR_FATTR_GROUP_NAME (1U << 24)
|
#define NFS_ATTR_FATTR_GROUP_NAME BIT_ULL(24)
|
||||||
#define NFS_ATTR_FATTR_V4_SECURITY_LABEL (1U << 25)
|
#define NFS_ATTR_FATTR_V4_SECURITY_LABEL BIT_ULL(25)
|
||||||
|
#define NFS_ATTR_FATTR_BTIME BIT_ULL(26)
|
||||||
|
|
||||||
#define NFS_ATTR_FATTR (NFS_ATTR_FATTR_TYPE \
|
#define NFS_ATTR_FATTR (NFS_ATTR_FATTR_TYPE \
|
||||||
| NFS_ATTR_FATTR_MODE \
|
| NFS_ATTR_FATTR_MODE \
|
||||||
|
@ -126,6 +128,7 @@ struct nfs_fattr {
|
||||||
| NFS_ATTR_FATTR_SPACE_USED)
|
| NFS_ATTR_FATTR_SPACE_USED)
|
||||||
#define NFS_ATTR_FATTR_V4 (NFS_ATTR_FATTR \
|
#define NFS_ATTR_FATTR_V4 (NFS_ATTR_FATTR \
|
||||||
| NFS_ATTR_FATTR_SPACE_USED \
|
| NFS_ATTR_FATTR_SPACE_USED \
|
||||||
|
| NFS_ATTR_FATTR_BTIME \
|
||||||
| NFS_ATTR_FATTR_V4_SECURITY_LABEL)
|
| NFS_ATTR_FATTR_V4_SECURITY_LABEL)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -130,10 +130,7 @@ xdr_buf_init(struct xdr_buf *buf, void *start, size_t len)
|
||||||
__be32 *xdr_encode_opaque_fixed(__be32 *p, const void *ptr, unsigned int len);
|
__be32 *xdr_encode_opaque_fixed(__be32 *p, const void *ptr, unsigned int len);
|
||||||
__be32 *xdr_encode_opaque(__be32 *p, const void *ptr, unsigned int len);
|
__be32 *xdr_encode_opaque(__be32 *p, const void *ptr, unsigned int len);
|
||||||
__be32 *xdr_encode_string(__be32 *p, const char *s);
|
__be32 *xdr_encode_string(__be32 *p, const char *s);
|
||||||
__be32 *xdr_decode_string_inplace(__be32 *p, char **sp, unsigned int *lenp,
|
|
||||||
unsigned int maxlen);
|
|
||||||
__be32 *xdr_encode_netobj(__be32 *p, const struct xdr_netobj *);
|
__be32 *xdr_encode_netobj(__be32 *p, const struct xdr_netobj *);
|
||||||
__be32 *xdr_decode_netobj(__be32 *p, struct xdr_netobj *);
|
|
||||||
|
|
||||||
void xdr_inline_pages(struct xdr_buf *, unsigned int,
|
void xdr_inline_pages(struct xdr_buf *, unsigned int,
|
||||||
struct page **, unsigned int, unsigned int);
|
struct page **, unsigned int, unsigned int);
|
||||||
|
@ -342,12 +339,6 @@ xdr_stream_remaining(const struct xdr_stream *xdr)
|
||||||
return xdr->nwords << 2;
|
return xdr->nwords << 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t xdr_stream_decode_opaque(struct xdr_stream *xdr, void *ptr,
|
|
||||||
size_t size);
|
|
||||||
ssize_t xdr_stream_decode_opaque_dup(struct xdr_stream *xdr, void **ptr,
|
|
||||||
size_t maxlen, gfp_t gfp_flags);
|
|
||||||
ssize_t xdr_stream_decode_string(struct xdr_stream *xdr, char *str,
|
|
||||||
size_t size);
|
|
||||||
ssize_t xdr_stream_decode_string_dup(struct xdr_stream *xdr, char **str,
|
ssize_t xdr_stream_decode_string_dup(struct xdr_stream *xdr, char **str,
|
||||||
size_t maxlen, gfp_t gfp_flags);
|
size_t maxlen, gfp_t gfp_flags);
|
||||||
ssize_t xdr_stream_decode_opaque_auth(struct xdr_stream *xdr, u32 *flavor,
|
ssize_t xdr_stream_decode_opaque_auth(struct xdr_stream *xdr, u32 *flavor,
|
||||||
|
|
|
@ -875,8 +875,8 @@ out_err:
|
||||||
* krb5_etm_decrypt - Decrypt using the RFC 8009 rules
|
* krb5_etm_decrypt - Decrypt using the RFC 8009 rules
|
||||||
* @kctx: Kerberos context
|
* @kctx: Kerberos context
|
||||||
* @offset: starting offset of the ciphertext, in bytes
|
* @offset: starting offset of the ciphertext, in bytes
|
||||||
* @len:
|
* @len: size of ciphertext to unwrap
|
||||||
* @buf:
|
* @buf: ciphertext to unwrap
|
||||||
* @headskip: OUT: the enctype's confounder length, in octets
|
* @headskip: OUT: the enctype's confounder length, in octets
|
||||||
* @tailskip: OUT: the enctype's HMAC length, in octets
|
* @tailskip: OUT: the enctype's HMAC length, in octets
|
||||||
*
|
*
|
||||||
|
|
110
net/sunrpc/xdr.c
110
net/sunrpc/xdr.c
|
@ -37,19 +37,6 @@ xdr_encode_netobj(__be32 *p, const struct xdr_netobj *obj)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(xdr_encode_netobj);
|
EXPORT_SYMBOL_GPL(xdr_encode_netobj);
|
||||||
|
|
||||||
__be32 *
|
|
||||||
xdr_decode_netobj(__be32 *p, struct xdr_netobj *obj)
|
|
||||||
{
|
|
||||||
unsigned int len;
|
|
||||||
|
|
||||||
if ((len = be32_to_cpu(*p++)) > XDR_MAX_NETOBJ)
|
|
||||||
return NULL;
|
|
||||||
obj->len = len;
|
|
||||||
obj->data = (u8 *) p;
|
|
||||||
return p + XDR_QUADLEN(len);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(xdr_decode_netobj);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* xdr_encode_opaque_fixed - Encode fixed length opaque data
|
* xdr_encode_opaque_fixed - Encode fixed length opaque data
|
||||||
* @p: pointer to current position in XDR buffer.
|
* @p: pointer to current position in XDR buffer.
|
||||||
|
@ -102,21 +89,6 @@ xdr_encode_string(__be32 *p, const char *string)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(xdr_encode_string);
|
EXPORT_SYMBOL_GPL(xdr_encode_string);
|
||||||
|
|
||||||
__be32 *
|
|
||||||
xdr_decode_string_inplace(__be32 *p, char **sp,
|
|
||||||
unsigned int *lenp, unsigned int maxlen)
|
|
||||||
{
|
|
||||||
u32 len;
|
|
||||||
|
|
||||||
len = be32_to_cpu(*p++);
|
|
||||||
if (len > maxlen)
|
|
||||||
return NULL;
|
|
||||||
*lenp = len;
|
|
||||||
*sp = (char *) p;
|
|
||||||
return p + XDR_QUADLEN(len);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(xdr_decode_string_inplace);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* xdr_terminate_string - '\0'-terminate a string residing in an xdr_buf
|
* xdr_terminate_string - '\0'-terminate a string residing in an xdr_buf
|
||||||
* @buf: XDR buffer where string resides
|
* @buf: XDR buffer where string resides
|
||||||
|
@ -2244,88 +2216,6 @@ out:
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(xdr_process_buf);
|
EXPORT_SYMBOL_GPL(xdr_process_buf);
|
||||||
|
|
||||||
/**
|
|
||||||
* xdr_stream_decode_opaque - Decode variable length opaque
|
|
||||||
* @xdr: pointer to xdr_stream
|
|
||||||
* @ptr: location to store opaque data
|
|
||||||
* @size: size of storage buffer @ptr
|
|
||||||
*
|
|
||||||
* Return values:
|
|
||||||
* On success, returns size of object stored in *@ptr
|
|
||||||
* %-EBADMSG on XDR buffer overflow
|
|
||||||
* %-EMSGSIZE on overflow of storage buffer @ptr
|
|
||||||
*/
|
|
||||||
ssize_t xdr_stream_decode_opaque(struct xdr_stream *xdr, void *ptr, size_t size)
|
|
||||||
{
|
|
||||||
ssize_t ret;
|
|
||||||
void *p;
|
|
||||||
|
|
||||||
ret = xdr_stream_decode_opaque_inline(xdr, &p, size);
|
|
||||||
if (ret <= 0)
|
|
||||||
return ret;
|
|
||||||
memcpy(ptr, p, ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(xdr_stream_decode_opaque);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* xdr_stream_decode_opaque_dup - Decode and duplicate variable length opaque
|
|
||||||
* @xdr: pointer to xdr_stream
|
|
||||||
* @ptr: location to store pointer to opaque data
|
|
||||||
* @maxlen: maximum acceptable object size
|
|
||||||
* @gfp_flags: GFP mask to use
|
|
||||||
*
|
|
||||||
* Return values:
|
|
||||||
* On success, returns size of object stored in *@ptr
|
|
||||||
* %-EBADMSG on XDR buffer overflow
|
|
||||||
* %-EMSGSIZE if the size of the object would exceed @maxlen
|
|
||||||
* %-ENOMEM on memory allocation failure
|
|
||||||
*/
|
|
||||||
ssize_t xdr_stream_decode_opaque_dup(struct xdr_stream *xdr, void **ptr,
|
|
||||||
size_t maxlen, gfp_t gfp_flags)
|
|
||||||
{
|
|
||||||
ssize_t ret;
|
|
||||||
void *p;
|
|
||||||
|
|
||||||
ret = xdr_stream_decode_opaque_inline(xdr, &p, maxlen);
|
|
||||||
if (ret > 0) {
|
|
||||||
*ptr = kmemdup(p, ret, gfp_flags);
|
|
||||||
if (*ptr != NULL)
|
|
||||||
return ret;
|
|
||||||
ret = -ENOMEM;
|
|
||||||
}
|
|
||||||
*ptr = NULL;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(xdr_stream_decode_opaque_dup);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* xdr_stream_decode_string - Decode variable length string
|
|
||||||
* @xdr: pointer to xdr_stream
|
|
||||||
* @str: location to store string
|
|
||||||
* @size: size of storage buffer @str
|
|
||||||
*
|
|
||||||
* Return values:
|
|
||||||
* On success, returns length of NUL-terminated string stored in *@str
|
|
||||||
* %-EBADMSG on XDR buffer overflow
|
|
||||||
* %-EMSGSIZE on overflow of storage buffer @str
|
|
||||||
*/
|
|
||||||
ssize_t xdr_stream_decode_string(struct xdr_stream *xdr, char *str, size_t size)
|
|
||||||
{
|
|
||||||
ssize_t ret;
|
|
||||||
void *p;
|
|
||||||
|
|
||||||
ret = xdr_stream_decode_opaque_inline(xdr, &p, size);
|
|
||||||
if (ret > 0) {
|
|
||||||
memcpy(str, p, ret);
|
|
||||||
str[ret] = '\0';
|
|
||||||
return strlen(str);
|
|
||||||
}
|
|
||||||
*str = '\0';
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(xdr_stream_decode_string);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* xdr_stream_decode_string_dup - Decode and duplicate variable length string
|
* xdr_stream_decode_string_dup - Decode and duplicate variable length string
|
||||||
* @xdr: pointer to xdr_stream
|
* @xdr: pointer to xdr_stream
|
||||||
|
|
|
@ -358,7 +358,7 @@ xs_alloc_sparse_pages(struct xdr_buf *buf, size_t want, gfp_t gfp)
|
||||||
|
|
||||||
static int
|
static int
|
||||||
xs_sock_process_cmsg(struct socket *sock, struct msghdr *msg,
|
xs_sock_process_cmsg(struct socket *sock, struct msghdr *msg,
|
||||||
struct cmsghdr *cmsg, int ret)
|
unsigned int *msg_flags, struct cmsghdr *cmsg, int ret)
|
||||||
{
|
{
|
||||||
u8 content_type = tls_get_record_type(sock->sk, cmsg);
|
u8 content_type = tls_get_record_type(sock->sk, cmsg);
|
||||||
u8 level, description;
|
u8 level, description;
|
||||||
|
@ -371,7 +371,7 @@ xs_sock_process_cmsg(struct socket *sock, struct msghdr *msg,
|
||||||
* record, even though there might be more frames
|
* record, even though there might be more frames
|
||||||
* waiting to be decrypted.
|
* waiting to be decrypted.
|
||||||
*/
|
*/
|
||||||
msg->msg_flags &= ~MSG_EOR;
|
*msg_flags &= ~MSG_EOR;
|
||||||
break;
|
break;
|
||||||
case TLS_RECORD_TYPE_ALERT:
|
case TLS_RECORD_TYPE_ALERT:
|
||||||
tls_alert_recv(sock->sk, msg, &level, &description);
|
tls_alert_recv(sock->sk, msg, &level, &description);
|
||||||
|
@ -386,19 +386,33 @@ xs_sock_process_cmsg(struct socket *sock, struct msghdr *msg,
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
xs_sock_recv_cmsg(struct socket *sock, struct msghdr *msg, int flags)
|
xs_sock_recv_cmsg(struct socket *sock, unsigned int *msg_flags, int flags)
|
||||||
{
|
{
|
||||||
union {
|
union {
|
||||||
struct cmsghdr cmsg;
|
struct cmsghdr cmsg;
|
||||||
u8 buf[CMSG_SPACE(sizeof(u8))];
|
u8 buf[CMSG_SPACE(sizeof(u8))];
|
||||||
} u;
|
} u;
|
||||||
|
u8 alert[2];
|
||||||
|
struct kvec alert_kvec = {
|
||||||
|
.iov_base = alert,
|
||||||
|
.iov_len = sizeof(alert),
|
||||||
|
};
|
||||||
|
struct msghdr msg = {
|
||||||
|
.msg_flags = *msg_flags,
|
||||||
|
.msg_control = &u,
|
||||||
|
.msg_controllen = sizeof(u),
|
||||||
|
};
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
msg->msg_control = &u;
|
iov_iter_kvec(&msg.msg_iter, ITER_DEST, &alert_kvec, 1,
|
||||||
msg->msg_controllen = sizeof(u);
|
alert_kvec.iov_len);
|
||||||
ret = sock_recvmsg(sock, msg, flags);
|
ret = sock_recvmsg(sock, &msg, flags);
|
||||||
if (msg->msg_controllen != sizeof(u))
|
if (ret > 0 &&
|
||||||
ret = xs_sock_process_cmsg(sock, msg, &u.cmsg, ret);
|
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);
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -408,7 +422,13 @@ xs_sock_recvmsg(struct socket *sock, struct msghdr *msg, int flags, size_t seek)
|
||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
if (seek != 0)
|
if (seek != 0)
|
||||||
iov_iter_advance(&msg->msg_iter, seek);
|
iov_iter_advance(&msg->msg_iter, seek);
|
||||||
ret = xs_sock_recv_cmsg(sock, msg, flags);
|
ret = sock_recvmsg(sock, msg, flags);
|
||||||
|
/* Handle TLS inband control message lazily */
|
||||||
|
if (msg->msg_flags & MSG_CTRUNC) {
|
||||||
|
msg->msg_flags &= ~(MSG_CTRUNC | MSG_EOR);
|
||||||
|
if (ret == 0 || ret == -EIO)
|
||||||
|
ret = xs_sock_recv_cmsg(sock, &msg->msg_flags, flags);
|
||||||
|
}
|
||||||
return ret > 0 ? ret + seek : ret;
|
return ret > 0 ? ret + seek : ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -434,7 +454,7 @@ xs_read_discard(struct socket *sock, struct msghdr *msg, int flags,
|
||||||
size_t count)
|
size_t count)
|
||||||
{
|
{
|
||||||
iov_iter_discard(&msg->msg_iter, ITER_DEST, count);
|
iov_iter_discard(&msg->msg_iter, ITER_DEST, count);
|
||||||
return xs_sock_recv_cmsg(sock, msg, flags);
|
return xs_sock_recvmsg(sock, msg, flags, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
|
#if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue