Skip to content

Commit d93231a

Browse files
Luís Henriquesidryomov
authored andcommitted
ceph: prevent a client from exceeding the MDS maximum xattr size
The MDS tries to enforce a limit on the total key/values in extended attributes. However, this limit is enforced only if doing a synchronous operation (MDS_OP_SETXATTR) -- if we're buffering the xattrs, the MDS doesn't have a chance to enforce these limits. This patch adds support for decoding the xattrs maximum size setting that is distributed in the mdsmap. Then, when setting an xattr, the kernel client will revert to do a synchronous operation if that maximum size is exceeded. While there, fix a dout() that would trigger a printk warning: [ 98.718078] ------------[ cut here ]------------ [ 98.719012] precision 65536 too large [ 98.719039] WARNING: CPU: 1 PID: 3755 at lib/vsprintf.c:2703 vsnprintf+0x5e3/0x600 ... Link: https://tracker.ceph.com/issues/55725 Signed-off-by: Luís Henriques <lhenriques@suse.de> Reviewed-by: Xiubo Li <xiubli@redhat.com> Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
1 parent 8266c4d commit d93231a

File tree

3 files changed

+27
-8
lines changed

3 files changed

+27
-8
lines changed

fs/ceph/mdsmap.c

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -352,12 +352,10 @@ struct ceph_mdsmap *ceph_mdsmap_decode(void **p, void *end, bool msgr2)
352352
__decode_and_drop_type(p, end, u8, bad_ext);
353353
}
354354
if (mdsmap_ev >= 8) {
355-
u32 name_len;
356355
/* enabled */
357356
ceph_decode_8_safe(p, end, m->m_enabled, bad_ext);
358-
ceph_decode_32_safe(p, end, name_len, bad_ext);
359-
ceph_decode_need(p, end, name_len, bad_ext);
360-
*p += name_len;
357+
/* fs_name */
358+
ceph_decode_skip_string(p, end, bad_ext);
361359
}
362360
/* damaged */
363361
if (mdsmap_ev >= 9) {
@@ -370,6 +368,22 @@ struct ceph_mdsmap *ceph_mdsmap_decode(void **p, void *end, bool msgr2)
370368
} else {
371369
m->m_damaged = false;
372370
}
371+
if (mdsmap_ev >= 17) {
372+
/* balancer */
373+
ceph_decode_skip_string(p, end, bad_ext);
374+
/* standby_count_wanted */
375+
ceph_decode_skip_32(p, end, bad_ext);
376+
/* old_max_mds */
377+
ceph_decode_skip_32(p, end, bad_ext);
378+
/* min_compat_client */
379+
ceph_decode_skip_8(p, end, bad_ext);
380+
/* required_client_features */
381+
ceph_decode_skip_set(p, end, 64, bad_ext);
382+
ceph_decode_64_safe(p, end, m->m_max_xattr_size, bad_ext);
383+
} else {
384+
/* This forces the usage of the (sync) SETXATTR Op */
385+
m->m_max_xattr_size = 0;
386+
}
373387
bad_ext:
374388
dout("mdsmap_decode m_enabled: %d, m_damaged: %d, m_num_laggy: %d\n",
375389
!!m->m_enabled, !!m->m_damaged, m->m_num_laggy);

fs/ceph/xattr.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1086,7 +1086,7 @@ static int ceph_sync_setxattr(struct inode *inode, const char *name,
10861086
flags |= CEPH_XATTR_REMOVE;
10871087
}
10881088

1089-
dout("setxattr value=%.*s\n", (int)size, value);
1089+
dout("setxattr value size: %zu\n", size);
10901090

10911091
/* do request */
10921092
req = ceph_mdsc_create_request(mdsc, op, USE_AUTH_MDS);
@@ -1184,8 +1184,14 @@ int __ceph_setxattr(struct inode *inode, const char *name,
11841184
spin_lock(&ci->i_ceph_lock);
11851185
retry:
11861186
issued = __ceph_caps_issued(ci, NULL);
1187-
if (ci->i_xattrs.version == 0 || !(issued & CEPH_CAP_XATTR_EXCL))
1187+
required_blob_size = __get_required_blob_size(ci, name_len, val_len);
1188+
if ((ci->i_xattrs.version == 0) || !(issued & CEPH_CAP_XATTR_EXCL) ||
1189+
(required_blob_size > mdsc->mdsmap->m_max_xattr_size)) {
1190+
dout("%s do sync setxattr: version: %llu size: %d max: %llu\n",
1191+
__func__, ci->i_xattrs.version, required_blob_size,
1192+
mdsc->mdsmap->m_max_xattr_size);
11881193
goto do_sync;
1194+
}
11891195

11901196
if (!lock_snap_rwsem && !ci->i_head_snapc) {
11911197
lock_snap_rwsem = true;
@@ -1201,8 +1207,6 @@ int __ceph_setxattr(struct inode *inode, const char *name,
12011207
ceph_cap_string(issued));
12021208
__build_xattrs(inode);
12031209

1204-
required_blob_size = __get_required_blob_size(ci, name_len, val_len);
1205-
12061210
if (!ci->i_xattrs.prealloc_blob ||
12071211
required_blob_size > ci->i_xattrs.prealloc_blob->alloc_len) {
12081212
struct ceph_buffer *blob;

include/linux/ceph/mdsmap.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ struct ceph_mdsmap {
2525
u32 m_session_timeout; /* seconds */
2626
u32 m_session_autoclose; /* seconds */
2727
u64 m_max_file_size;
28+
u64 m_max_xattr_size; /* maximum size for xattrs blob */
2829
u32 m_max_mds; /* expected up:active mds number */
2930
u32 m_num_active_mds; /* actual up:active mds number */
3031
u32 possible_max_rank; /* possible max rank index */

0 commit comments

Comments
 (0)