Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ceph: fix statfs for subdir mounts

When doing a mount using as base a directory that has 'max_bytes' quotas
statfs uses that value as the total; if a subdirectory is used instead,
the same 'max_bytes' too in statfs, unless there is another quota set.

Unfortunately, if this subdirectory only has the 'max_files' quota set,
then statfs uses the filesystem total. Fix this by making sure we only
lookup realms that contain the 'max_bytes' quota.

Cc: Ryan Taylor <rptaylor@uvic.ca>
URL: https://tracker.ceph.com/issues/55090
Signed-off-by: Luís Henriques <lhenriques@suse.de>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Reviewed-by: Xiubo Li <xiubli@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>

authored by

Luís Henriques and committed by
Ilya Dryomov
55ab5520 825978fd

+36 -13
+1 -1
fs/ceph/inode.c
··· 578 578 579 579 __ceph_remove_caps(ci); 580 580 581 - if (__ceph_has_any_quota(ci)) 581 + if (__ceph_has_quota(ci, QUOTA_GET_ANY)) 582 582 ceph_adjust_quota_realms_count(inode, false); 583 583 584 584 /*
+11 -8
fs/ceph/quota.c
··· 195 195 196 196 /* 197 197 * This function walks through the snaprealm for an inode and returns the 198 - * ceph_snap_realm for the first snaprealm that has quotas set (either max_files 199 - * or max_bytes). If the root is reached, return the root ceph_snap_realm 200 - * instead. 198 + * ceph_snap_realm for the first snaprealm that has quotas set (max_files, 199 + * max_bytes, or any, depending on the 'which_quota' argument). If the root is 200 + * reached, return the root ceph_snap_realm instead. 201 201 * 202 202 * Note that the caller is responsible for calling ceph_put_snap_realm() on the 203 203 * returned realm. ··· 209 209 * will be restarted. 210 210 */ 211 211 static struct ceph_snap_realm *get_quota_realm(struct ceph_mds_client *mdsc, 212 - struct inode *inode, bool retry) 212 + struct inode *inode, 213 + enum quota_get_realm which_quota, 214 + bool retry) 213 215 { 214 216 struct ceph_inode_info *ci = NULL; 215 217 struct ceph_snap_realm *realm, *next; ··· 250 248 } 251 249 252 250 ci = ceph_inode(in); 253 - has_quota = __ceph_has_any_quota(ci); 251 + has_quota = __ceph_has_quota(ci, which_quota); 254 252 iput(in); 255 253 256 254 next = realm->parent; ··· 281 279 * dropped and we can then restart the whole operation. 282 280 */ 283 281 down_read(&mdsc->snap_rwsem); 284 - old_realm = get_quota_realm(mdsc, old, true); 285 - new_realm = get_quota_realm(mdsc, new, false); 282 + old_realm = get_quota_realm(mdsc, old, QUOTA_GET_ANY, true); 283 + new_realm = get_quota_realm(mdsc, new, QUOTA_GET_ANY, false); 286 284 if (PTR_ERR(new_realm) == -EAGAIN) { 287 285 up_read(&mdsc->snap_rwsem); 288 286 if (old_realm) ··· 485 483 bool is_updated = false; 486 484 487 485 down_read(&mdsc->snap_rwsem); 488 - realm = get_quota_realm(mdsc, d_inode(fsc->sb->s_root), true); 486 + realm = get_quota_realm(mdsc, d_inode(fsc->sb->s_root), 487 + QUOTA_GET_MAX_BYTES, true); 489 488 up_read(&mdsc->snap_rwsem); 490 489 if (!realm) 491 490 return false;
+24 -4
fs/ceph/super.h
··· 1279 1279 extern void ceph_fs_debugfs_cleanup(struct ceph_fs_client *client); 1280 1280 1281 1281 /* quota.c */ 1282 - static inline bool __ceph_has_any_quota(struct ceph_inode_info *ci) 1282 + 1283 + enum quota_get_realm { 1284 + QUOTA_GET_MAX_FILES, 1285 + QUOTA_GET_MAX_BYTES, 1286 + QUOTA_GET_ANY 1287 + }; 1288 + 1289 + static inline bool __ceph_has_quota(struct ceph_inode_info *ci, 1290 + enum quota_get_realm which) 1283 1291 { 1284 - return ci->i_max_files || ci->i_max_bytes; 1292 + bool has_quota = false; 1293 + 1294 + switch (which) { 1295 + case QUOTA_GET_MAX_BYTES: 1296 + has_quota = !!ci->i_max_bytes; 1297 + break; 1298 + case QUOTA_GET_MAX_FILES: 1299 + has_quota = !!ci->i_max_files; 1300 + break; 1301 + default: 1302 + has_quota = !!(ci->i_max_files || ci->i_max_bytes); 1303 + } 1304 + return has_quota; 1285 1305 } 1286 1306 1287 1307 extern void ceph_adjust_quota_realms_count(struct inode *inode, bool inc); ··· 1310 1290 u64 max_bytes, u64 max_files) 1311 1291 { 1312 1292 bool had_quota, has_quota; 1313 - had_quota = __ceph_has_any_quota(ci); 1293 + had_quota = __ceph_has_quota(ci, QUOTA_GET_ANY); 1314 1294 ci->i_max_bytes = max_bytes; 1315 1295 ci->i_max_files = max_files; 1316 - has_quota = __ceph_has_any_quota(ci); 1296 + has_quota = __ceph_has_quota(ci, QUOTA_GET_ANY); 1317 1297 1318 1298 if (had_quota != has_quota) 1319 1299 ceph_adjust_quota_realms_count(&ci->vfs_inode, has_quota);