Skip to content

Commit 74eca35

Browse files
committed
Merge tag 'ceph-for-6.10-rc1' of https://github.com/ceph/ceph-client
Pull ceph updates from Ilya Dryomov: "A series from Xiubo that adds support for additional access checks based on MDS auth caps which were recently made available to clients. This is needed to prevent scenarios where the MDS quietly discards updates that a UID-restricted client previously (wrongfully) acked to the user. Other than that, just a documentation fixup" * tag 'ceph-for-6.10-rc1' of https://github.com/ceph/ceph-client: doc: ceph: update userspace command to get CephFS metadata ceph: add CEPHFS_FEATURE_MDS_AUTH_CAPS_CHECK feature bit ceph: check the cephx mds auth access for async dirop ceph: check the cephx mds auth access for open ceph: check the cephx mds auth access for setattr ceph: add ceph_mds_check_access() helper ceph: save cap_auths in MDS client when session is opened
2 parents 89b61ca + 93a2221 commit 74eca35

File tree

6 files changed

+434
-19
lines changed

6 files changed

+434
-19
lines changed

Documentation/filesystems/ceph.rst

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,15 @@ Snapshot names have two limitations:
6767
more than 255 characters, and `<node-id>` takes 13 characters, the long
6868
snapshot names can take as much as 255 - 1 - 1 - 13 = 240.
6969

70-
Ceph also provides some recursive accounting on directories for nested
71-
files and bytes. That is, a 'getfattr -d foo' on any directory in the
72-
system will reveal the total number of nested regular files and
73-
subdirectories, and a summation of all nested file sizes. This makes
74-
the identification of large disk space consumers relatively quick, as
75-
no 'du' or similar recursive scan of the file system is required.
70+
Ceph also provides some recursive accounting on directories for nested files
71+
and bytes. You can run the commands::
72+
73+
getfattr -n ceph.dir.rfiles /some/dir
74+
getfattr -n ceph.dir.rbytes /some/dir
75+
76+
to get the total number of nested files and their combined size, respectively.
77+
This makes the identification of large disk space consumers relatively quick,
78+
as no 'du' or similar recursive scan of the file system is required.
7679

7780
Finally, Ceph also allows quotas to be set on any directory in the system.
7881
The quota can restrict the number of bytes or the number of files stored

fs/ceph/dir.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1336,8 +1336,12 @@ static int ceph_unlink(struct inode *dir, struct dentry *dentry)
13361336
struct inode *inode = d_inode(dentry);
13371337
struct ceph_mds_request *req;
13381338
bool try_async = ceph_test_mount_opt(fsc, ASYNC_DIROPS);
1339+
struct dentry *dn;
13391340
int err = -EROFS;
13401341
int op;
1342+
char *path;
1343+
int pathlen;
1344+
u64 pathbase;
13411345

13421346
if (ceph_snap(dir) == CEPH_SNAPDIR) {
13431347
/* rmdir .snap/foo is RMSNAP */
@@ -1351,6 +1355,30 @@ static int ceph_unlink(struct inode *dir, struct dentry *dentry)
13511355
CEPH_MDS_OP_RMDIR : CEPH_MDS_OP_UNLINK;
13521356
} else
13531357
goto out;
1358+
1359+
dn = d_find_alias(dir);
1360+
if (!dn) {
1361+
try_async = false;
1362+
} else {
1363+
path = ceph_mdsc_build_path(mdsc, dn, &pathlen, &pathbase, 0);
1364+
if (IS_ERR(path)) {
1365+
try_async = false;
1366+
err = 0;
1367+
} else {
1368+
err = ceph_mds_check_access(mdsc, path, MAY_WRITE);
1369+
}
1370+
ceph_mdsc_free_path(path, pathlen);
1371+
dput(dn);
1372+
1373+
/* For none EACCES cases will let the MDS do the mds auth check */
1374+
if (err == -EACCES) {
1375+
return err;
1376+
} else if (err < 0) {
1377+
try_async = false;
1378+
err = 0;
1379+
}
1380+
}
1381+
13541382
retry:
13551383
req = ceph_mdsc_create_request(mdsc, op, USE_AUTH_MDS);
13561384
if (IS_ERR(req)) {

fs/ceph/file.c

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,12 @@ int ceph_open(struct inode *inode, struct file *file)
366366
struct ceph_file_info *fi = file->private_data;
367367
int err;
368368
int flags, fmode, wanted;
369+
struct dentry *dentry;
370+
char *path;
371+
int pathlen;
372+
u64 pathbase;
373+
bool do_sync = false;
374+
int mask = MAY_READ;
369375

370376
if (fi) {
371377
doutc(cl, "file %p is already opened\n", file);
@@ -387,6 +393,31 @@ int ceph_open(struct inode *inode, struct file *file)
387393
fmode = ceph_flags_to_mode(flags);
388394
wanted = ceph_caps_for_mode(fmode);
389395

396+
if (fmode & CEPH_FILE_MODE_WR)
397+
mask |= MAY_WRITE;
398+
dentry = d_find_alias(inode);
399+
if (!dentry) {
400+
do_sync = true;
401+
} else {
402+
path = ceph_mdsc_build_path(mdsc, dentry, &pathlen, &pathbase, 0);
403+
if (IS_ERR(path)) {
404+
do_sync = true;
405+
err = 0;
406+
} else {
407+
err = ceph_mds_check_access(mdsc, path, mask);
408+
}
409+
ceph_mdsc_free_path(path, pathlen);
410+
dput(dentry);
411+
412+
/* For none EACCES cases will let the MDS do the mds auth check */
413+
if (err == -EACCES) {
414+
return err;
415+
} else if (err < 0) {
416+
do_sync = true;
417+
err = 0;
418+
}
419+
}
420+
390421
/* snapped files are read-only */
391422
if (ceph_snap(inode) != CEPH_NOSNAP && (file->f_mode & FMODE_WRITE))
392423
return -EROFS;
@@ -402,7 +433,7 @@ int ceph_open(struct inode *inode, struct file *file)
402433
* asynchronously.
403434
*/
404435
spin_lock(&ci->i_ceph_lock);
405-
if (__ceph_is_any_real_caps(ci) &&
436+
if (!do_sync && __ceph_is_any_real_caps(ci) &&
406437
(((fmode & CEPH_FILE_MODE_WR) == 0) || ci->i_auth_cap)) {
407438
int mds_wanted = __ceph_caps_mds_wanted(ci, true);
408439
int issued = __ceph_caps_issued(ci, NULL);
@@ -420,7 +451,7 @@ int ceph_open(struct inode *inode, struct file *file)
420451
ceph_check_caps(ci, 0);
421452

422453
return ceph_init_file(inode, file, fmode);
423-
} else if (ceph_snap(inode) != CEPH_NOSNAP &&
454+
} else if (!do_sync && ceph_snap(inode) != CEPH_NOSNAP &&
424455
(ci->i_snap_caps & wanted) == wanted) {
425456
__ceph_touch_fmode(ci, mdsc, fmode);
426457
spin_unlock(&ci->i_ceph_lock);
@@ -759,6 +790,9 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry,
759790
bool try_async = ceph_test_mount_opt(fsc, ASYNC_DIROPS);
760791
int mask;
761792
int err;
793+
char *path;
794+
int pathlen;
795+
u64 pathbase;
762796

763797
doutc(cl, "%p %llx.%llx dentry %p '%pd' %s flags %d mode 0%o\n",
764798
dir, ceph_vinop(dir), dentry, dentry,
@@ -776,6 +810,34 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry,
776810
*/
777811
flags &= ~O_TRUNC;
778812

813+
dn = d_find_alias(dir);
814+
if (!dn) {
815+
try_async = false;
816+
} else {
817+
path = ceph_mdsc_build_path(mdsc, dn, &pathlen, &pathbase, 0);
818+
if (IS_ERR(path)) {
819+
try_async = false;
820+
err = 0;
821+
} else {
822+
int fmode = ceph_flags_to_mode(flags);
823+
824+
mask = MAY_READ;
825+
if (fmode & CEPH_FILE_MODE_WR)
826+
mask |= MAY_WRITE;
827+
err = ceph_mds_check_access(mdsc, path, mask);
828+
}
829+
ceph_mdsc_free_path(path, pathlen);
830+
dput(dn);
831+
832+
/* For none EACCES cases will let the MDS do the mds auth check */
833+
if (err == -EACCES) {
834+
return err;
835+
} else if (err < 0) {
836+
try_async = false;
837+
err = 0;
838+
}
839+
}
840+
779841
retry:
780842
if (flags & O_CREAT) {
781843
if (ceph_quota_is_max_files_exceeded(dir))

fs/ceph/inode.c

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2482,6 +2482,34 @@ int __ceph_setattr(struct mnt_idmap *idmap, struct inode *inode,
24822482
bool lock_snap_rwsem = false;
24832483
bool fill_fscrypt;
24842484
int truncate_retry = 20; /* The RMW will take around 50ms */
2485+
struct dentry *dentry;
2486+
char *path;
2487+
int pathlen;
2488+
u64 pathbase;
2489+
bool do_sync = false;
2490+
2491+
dentry = d_find_alias(inode);
2492+
if (!dentry) {
2493+
do_sync = true;
2494+
} else {
2495+
path = ceph_mdsc_build_path(mdsc, dentry, &pathlen, &pathbase, 0);
2496+
if (IS_ERR(path)) {
2497+
do_sync = true;
2498+
err = 0;
2499+
} else {
2500+
err = ceph_mds_check_access(mdsc, path, MAY_WRITE);
2501+
}
2502+
ceph_mdsc_free_path(path, pathlen);
2503+
dput(dentry);
2504+
2505+
/* For none EACCES cases will let the MDS do the mds auth check */
2506+
if (err == -EACCES) {
2507+
return err;
2508+
} else if (err < 0) {
2509+
do_sync = true;
2510+
err = 0;
2511+
}
2512+
}
24852513

24862514
retry:
24872515
prealloc_cf = ceph_alloc_cap_flush();
@@ -2528,7 +2556,7 @@ int __ceph_setattr(struct mnt_idmap *idmap, struct inode *inode,
25282556
/* It should never be re-set once set */
25292557
WARN_ON_ONCE(ci->fscrypt_auth);
25302558

2531-
if (issued & CEPH_CAP_AUTH_EXCL) {
2559+
if (!do_sync && (issued & CEPH_CAP_AUTH_EXCL)) {
25322560
dirtied |= CEPH_CAP_AUTH_EXCL;
25332561
kfree(ci->fscrypt_auth);
25342562
ci->fscrypt_auth = (u8 *)cia->fscrypt_auth;
@@ -2557,7 +2585,7 @@ int __ceph_setattr(struct mnt_idmap *idmap, struct inode *inode,
25572585
ceph_vinop(inode),
25582586
from_kuid(&init_user_ns, inode->i_uid),
25592587
from_kuid(&init_user_ns, attr->ia_uid));
2560-
if (issued & CEPH_CAP_AUTH_EXCL) {
2588+
if (!do_sync && (issued & CEPH_CAP_AUTH_EXCL)) {
25612589
inode->i_uid = fsuid;
25622590
dirtied |= CEPH_CAP_AUTH_EXCL;
25632591
} else if ((issued & CEPH_CAP_AUTH_SHARED) == 0 ||
@@ -2575,7 +2603,7 @@ int __ceph_setattr(struct mnt_idmap *idmap, struct inode *inode,
25752603
ceph_vinop(inode),
25762604
from_kgid(&init_user_ns, inode->i_gid),
25772605
from_kgid(&init_user_ns, attr->ia_gid));
2578-
if (issued & CEPH_CAP_AUTH_EXCL) {
2606+
if (!do_sync && (issued & CEPH_CAP_AUTH_EXCL)) {
25792607
inode->i_gid = fsgid;
25802608
dirtied |= CEPH_CAP_AUTH_EXCL;
25812609
} else if ((issued & CEPH_CAP_AUTH_SHARED) == 0 ||
@@ -2589,7 +2617,7 @@ int __ceph_setattr(struct mnt_idmap *idmap, struct inode *inode,
25892617
if (ia_valid & ATTR_MODE) {
25902618
doutc(cl, "%p %llx.%llx mode 0%o -> 0%o\n", inode,
25912619
ceph_vinop(inode), inode->i_mode, attr->ia_mode);
2592-
if (issued & CEPH_CAP_AUTH_EXCL) {
2620+
if (!do_sync && (issued & CEPH_CAP_AUTH_EXCL)) {
25932621
inode->i_mode = attr->ia_mode;
25942622
dirtied |= CEPH_CAP_AUTH_EXCL;
25952623
} else if ((issued & CEPH_CAP_AUTH_SHARED) == 0 ||
@@ -2608,11 +2636,11 @@ int __ceph_setattr(struct mnt_idmap *idmap, struct inode *inode,
26082636
inode, ceph_vinop(inode),
26092637
atime.tv_sec, atime.tv_nsec,
26102638
attr->ia_atime.tv_sec, attr->ia_atime.tv_nsec);
2611-
if (issued & CEPH_CAP_FILE_EXCL) {
2639+
if (!do_sync && (issued & CEPH_CAP_FILE_EXCL)) {
26122640
ci->i_time_warp_seq++;
26132641
inode_set_atime_to_ts(inode, attr->ia_atime);
26142642
dirtied |= CEPH_CAP_FILE_EXCL;
2615-
} else if ((issued & CEPH_CAP_FILE_WR) &&
2643+
} else if (!do_sync && (issued & CEPH_CAP_FILE_WR) &&
26162644
timespec64_compare(&atime,
26172645
&attr->ia_atime) < 0) {
26182646
inode_set_atime_to_ts(inode, attr->ia_atime);
@@ -2648,7 +2676,7 @@ int __ceph_setattr(struct mnt_idmap *idmap, struct inode *inode,
26482676
CEPH_FSCRYPT_BLOCK_SIZE));
26492677
req->r_fscrypt_file = attr->ia_size;
26502678
fill_fscrypt = true;
2651-
} else if ((issued & CEPH_CAP_FILE_EXCL) && attr->ia_size >= isize) {
2679+
} else if (!do_sync && (issued & CEPH_CAP_FILE_EXCL) && attr->ia_size >= isize) {
26522680
if (attr->ia_size > isize) {
26532681
i_size_write(inode, attr->ia_size);
26542682
inode->i_blocks = calc_inode_blocks(attr->ia_size);
@@ -2685,11 +2713,11 @@ int __ceph_setattr(struct mnt_idmap *idmap, struct inode *inode,
26852713
inode, ceph_vinop(inode),
26862714
mtime.tv_sec, mtime.tv_nsec,
26872715
attr->ia_mtime.tv_sec, attr->ia_mtime.tv_nsec);
2688-
if (issued & CEPH_CAP_FILE_EXCL) {
2716+
if (!do_sync && (issued & CEPH_CAP_FILE_EXCL)) {
26892717
ci->i_time_warp_seq++;
26902718
inode_set_mtime_to_ts(inode, attr->ia_mtime);
26912719
dirtied |= CEPH_CAP_FILE_EXCL;
2692-
} else if ((issued & CEPH_CAP_FILE_WR) &&
2720+
} else if (!do_sync && (issued & CEPH_CAP_FILE_WR) &&
26932721
timespec64_compare(&mtime, &attr->ia_mtime) < 0) {
26942722
inode_set_mtime_to_ts(inode, attr->ia_mtime);
26952723
dirtied |= CEPH_CAP_FILE_WR;

0 commit comments

Comments
 (0)