Skip to content

Commit 04a5da6

Browse files
fllindenTrond Myklebust
authored andcommitted
NFSv4.2: define limits and sizes for user xattr handling
Set limits for extended attributes (attribute value size and listxattr buffer size), based on the fs-independent limits (XATTR_*_MAX). Define the maximum XDR sizes for the RFC 8276 XATTR operations. In the case of operations that carry a larger payload (SETXATTR, GETXATTR, LISTXATTR), these exclude that payload, which is added as separate pages, like other operations do. Define, much like for read and write operations, the maximum overhead sizes for get/set/listxattr, and use them to limit the maximum payload size for those operations, in combination with the channel attributes. Signed-off-by: Frank van der Linden <[email protected]> Signed-off-by: Trond Myklebust <[email protected]>
1 parent 9a67fcc commit 04a5da6

File tree

6 files changed

+149
-2
lines changed

6 files changed

+149
-2
lines changed

fs/nfs/client.c

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
#include "nfs.h"
5151
#include "netns.h"
5252
#include "sysfs.h"
53+
#include "nfs42.h"
5354

5455
#define NFSDBG_FACILITY NFSDBG_CLIENT
5556

@@ -749,7 +750,7 @@ static int nfs_init_server(struct nfs_server *server,
749750
static void nfs_server_set_fsinfo(struct nfs_server *server,
750751
struct nfs_fsinfo *fsinfo)
751752
{
752-
unsigned long max_rpc_payload;
753+
unsigned long max_rpc_payload, raw_max_rpc_payload;
753754

754755
/* Work out a lot of parameters */
755756
if (server->rsize == 0)
@@ -762,7 +763,9 @@ static void nfs_server_set_fsinfo(struct nfs_server *server,
762763
if (fsinfo->wtmax >= 512 && server->wsize > fsinfo->wtmax)
763764
server->wsize = nfs_block_size(fsinfo->wtmax, NULL);
764765

765-
max_rpc_payload = nfs_block_size(rpc_max_payload(server->client), NULL);
766+
raw_max_rpc_payload = rpc_max_payload(server->client);
767+
max_rpc_payload = nfs_block_size(raw_max_rpc_payload, NULL);
768+
766769
if (server->rsize > max_rpc_payload)
767770
server->rsize = max_rpc_payload;
768771
if (server->rsize > NFS_MAX_FILE_IO_SIZE)
@@ -795,6 +798,18 @@ static void nfs_server_set_fsinfo(struct nfs_server *server,
795798
server->clone_blksize = fsinfo->clone_blksize;
796799
/* We're airborne Set socket buffersize */
797800
rpc_setbufsize(server->client, server->wsize + 100, server->rsize + 100);
801+
802+
#ifdef CONFIG_NFS_V4_2
803+
/*
804+
* Defaults until limited by the session parameters.
805+
*/
806+
server->gxasize = min_t(unsigned int, raw_max_rpc_payload,
807+
XATTR_SIZE_MAX);
808+
server->sxasize = min_t(unsigned int, raw_max_rpc_payload,
809+
XATTR_SIZE_MAX);
810+
server->lxasize = min_t(unsigned int, raw_max_rpc_payload,
811+
nfs42_listxattr_xdrsize(XATTR_LIST_MAX));
812+
#endif
798813
}
799814

800815
/*

fs/nfs/nfs42.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
#ifndef __LINUX_FS_NFS_NFS4_2_H
77
#define __LINUX_FS_NFS_NFS4_2_H
88

9+
#include <linux/xattr.h>
10+
911
/*
1012
* FIXME: four LAYOUTSTATS calls per compound at most! Do we need to support
1113
* more? Need to consider not to pre-alloc too much for a compound.
@@ -36,5 +38,19 @@ static inline bool nfs42_files_from_same_server(struct file *in,
3638
return nfs4_check_serverowner_major_id(c_in->cl_serverowner,
3739
c_out->cl_serverowner);
3840
}
41+
42+
/*
43+
* Maximum XDR buffer size needed for a listxattr buffer of buflen size.
44+
*
45+
* The upper boundary is a buffer with all 1-byte sized attribute names.
46+
* They would be 7 bytes long in the eventual buffer ("user.x\0"), and
47+
* 8 bytes long XDR-encoded.
48+
*
49+
* Include the trailing eof word as well.
50+
*/
51+
static inline u32 nfs42_listxattr_xdrsize(u32 buflen)
52+
{
53+
return ((buflen / (XATTR_USER_PREFIX_LEN + 2)) * 8) + 4;
54+
}
3955
#endif /* CONFIG_NFS_V4_2 */
4056
#endif /* __LINUX_FS_NFS_NFS4_2_H */

fs/nfs/nfs42xdr.c

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,80 @@
169169
decode_clone_maxsz + \
170170
decode_getattr_maxsz)
171171

172+
#ifdef CONFIG_NFS_V4_2
173+
/* Not limited by NFS itself, limited by the generic xattr code */
174+
#define nfs4_xattr_name_maxsz XDR_QUADLEN(XATTR_NAME_MAX)
175+
176+
#define encode_getxattr_maxsz (op_encode_hdr_maxsz + 1 + \
177+
nfs4_xattr_name_maxsz)
178+
#define decode_getxattr_maxsz (op_decode_hdr_maxsz + 1 + 1)
179+
#define encode_setxattr_maxsz (op_encode_hdr_maxsz + \
180+
1 + nfs4_xattr_name_maxsz + 1)
181+
#define decode_setxattr_maxsz (op_decode_hdr_maxsz + decode_change_info_maxsz)
182+
#define encode_listxattrs_maxsz (op_encode_hdr_maxsz + 2 + 1)
183+
#define decode_listxattrs_maxsz (op_decode_hdr_maxsz + 2 + 1 + 1)
184+
#define encode_removexattr_maxsz (op_encode_hdr_maxsz + 1 + \
185+
nfs4_xattr_name_maxsz)
186+
#define decode_removexattr_maxsz (op_decode_hdr_maxsz + \
187+
decode_change_info_maxsz)
188+
189+
#define NFS4_enc_getxattr_sz (compound_encode_hdr_maxsz + \
190+
encode_sequence_maxsz + \
191+
encode_putfh_maxsz + \
192+
encode_getxattr_maxsz)
193+
#define NFS4_dec_getxattr_sz (compound_decode_hdr_maxsz + \
194+
decode_sequence_maxsz + \
195+
decode_putfh_maxsz + \
196+
decode_getxattr_maxsz)
197+
#define NFS4_enc_setxattr_sz (compound_encode_hdr_maxsz + \
198+
encode_sequence_maxsz + \
199+
encode_putfh_maxsz + \
200+
encode_setxattr_maxsz)
201+
#define NFS4_dec_setxattr_sz (compound_decode_hdr_maxsz + \
202+
decode_sequence_maxsz + \
203+
decode_putfh_maxsz + \
204+
decode_setxattr_maxsz)
205+
#define NFS4_enc_listxattrs_sz (compound_encode_hdr_maxsz + \
206+
encode_sequence_maxsz + \
207+
encode_putfh_maxsz + \
208+
encode_listxattrs_maxsz)
209+
#define NFS4_dec_listxattrs_sz (compound_decode_hdr_maxsz + \
210+
decode_sequence_maxsz + \
211+
decode_putfh_maxsz + \
212+
decode_listxattrs_maxsz)
213+
#define NFS4_enc_removexattr_sz (compound_encode_hdr_maxsz + \
214+
encode_sequence_maxsz + \
215+
encode_putfh_maxsz + \
216+
encode_removexattr_maxsz)
217+
#define NFS4_dec_removexattr_sz (compound_decode_hdr_maxsz + \
218+
decode_sequence_maxsz + \
219+
decode_putfh_maxsz + \
220+
decode_removexattr_maxsz)
221+
222+
/*
223+
* These values specify the maximum amount of data that is not
224+
* associated with the extended attribute name or extended
225+
* attribute list in the SETXATTR, GETXATTR and LISTXATTR
226+
* respectively.
227+
*/
228+
const u32 nfs42_maxsetxattr_overhead = ((RPC_MAX_HEADER_WITH_AUTH +
229+
compound_encode_hdr_maxsz +
230+
encode_sequence_maxsz +
231+
encode_putfh_maxsz + 1 +
232+
nfs4_xattr_name_maxsz)
233+
* XDR_UNIT);
234+
235+
const u32 nfs42_maxgetxattr_overhead = ((RPC_MAX_HEADER_WITH_AUTH +
236+
compound_decode_hdr_maxsz +
237+
decode_sequence_maxsz +
238+
decode_putfh_maxsz + 1) * XDR_UNIT);
239+
240+
const u32 nfs42_maxlistxattrs_overhead = ((RPC_MAX_HEADER_WITH_AUTH +
241+
compound_decode_hdr_maxsz +
242+
decode_sequence_maxsz +
243+
decode_putfh_maxsz + 3) * XDR_UNIT);
244+
#endif
245+
172246
static void encode_fallocate(struct xdr_stream *xdr,
173247
const struct nfs42_falloc_args *args)
174248
{

fs/nfs/nfs4_fs.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,12 @@ static inline void nfs4_unregister_sysctl(void)
557557
/* nfs4xdr.c */
558558
extern const struct rpc_procinfo nfs4_procedures[];
559559

560+
#ifdef CONFIG_NFS_V4_2
561+
extern const u32 nfs42_maxsetxattr_overhead;
562+
extern const u32 nfs42_maxgetxattr_overhead;
563+
extern const u32 nfs42_maxlistxattrs_overhead;
564+
#endif
565+
560566
struct nfs4_mount_data;
561567

562568
/* callback_xdr.c */

fs/nfs/nfs4client.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -992,6 +992,36 @@ static void nfs4_session_limit_rwsize(struct nfs_server *server)
992992
#endif /* CONFIG_NFS_V4_1 */
993993
}
994994

995+
/*
996+
* Limit xattr sizes using the channel attributes.
997+
*/
998+
static void nfs4_session_limit_xasize(struct nfs_server *server)
999+
{
1000+
#ifdef CONFIG_NFS_V4_2
1001+
struct nfs4_session *sess;
1002+
u32 server_gxa_sz;
1003+
u32 server_sxa_sz;
1004+
u32 server_lxa_sz;
1005+
1006+
if (!nfs4_has_session(server->nfs_client))
1007+
return;
1008+
1009+
sess = server->nfs_client->cl_session;
1010+
1011+
server_gxa_sz = sess->fc_attrs.max_resp_sz - nfs42_maxgetxattr_overhead;
1012+
server_sxa_sz = sess->fc_attrs.max_rqst_sz - nfs42_maxsetxattr_overhead;
1013+
server_lxa_sz = sess->fc_attrs.max_resp_sz -
1014+
nfs42_maxlistxattrs_overhead;
1015+
1016+
if (server->gxasize > server_gxa_sz)
1017+
server->gxasize = server_gxa_sz;
1018+
if (server->sxasize > server_sxa_sz)
1019+
server->sxasize = server_sxa_sz;
1020+
if (server->lxasize > server_lxa_sz)
1021+
server->lxasize = server_lxa_sz;
1022+
#endif
1023+
}
1024+
9951025
static int nfs4_server_common_setup(struct nfs_server *server,
9961026
struct nfs_fh *mntfh, bool auth_probe)
9971027
{
@@ -1039,6 +1069,7 @@ static int nfs4_server_common_setup(struct nfs_server *server,
10391069
goto out;
10401070

10411071
nfs4_session_limit_rwsize(server);
1072+
nfs4_session_limit_xasize(server);
10421073

10431074
if (server->namelen == 0 || server->namelen > NFS4_MAXNAMLEN)
10441075
server->namelen = NFS4_MAXNAMLEN;

include/linux/nfs_fs_sb.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,11 @@ struct nfs_server {
163163
unsigned int dtsize; /* readdir size */
164164
unsigned short port; /* "port=" setting */
165165
unsigned int bsize; /* server block size */
166+
#ifdef CONFIG_NFS_V4_2
167+
unsigned int gxasize; /* getxattr size */
168+
unsigned int sxasize; /* setxattr size */
169+
unsigned int lxasize; /* listxattr size */
170+
#endif
166171
unsigned int acregmin; /* attr cache timeouts */
167172
unsigned int acregmax;
168173
unsigned int acdirmin;

0 commit comments

Comments
 (0)