Skip to content

Commit 16be62f

Browse files
jtlaytonidryomov
authored andcommitted
ceph: size handling in MClientRequest, cap updates and inode traces
For encrypted inodes, transmit a rounded-up size to the MDS as the normal file size and send the real inode size in fscrypt_file field. Also, fix up creates and truncates to also transmit fscrypt_file. When we get an inode trace from the MDS, grab the fscrypt_file field if the inode is encrypted, and use it to populate the i_size field instead of the regular inode size field. Signed-off-by: Jeff Layton <jlayton@kernel.org> Reviewed-by: Xiubo Li <xiubli@redhat.com> Reviewed-and-tested-by: Luís Henriques <lhenriques@suse.de> Reviewed-by: Milind Changire <mchangir@redhat.com> Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
1 parent 14e034a commit 16be62f

6 files changed

Lines changed: 70 additions & 22 deletions

File tree

fs/ceph/caps.c

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1217,10 +1217,9 @@ struct cap_msg_args {
12171217
umode_t mode;
12181218
bool inline_data;
12191219
bool wake;
1220+
bool encrypted;
12201221
u32 fscrypt_auth_len;
1221-
u32 fscrypt_file_len;
12221222
u8 fscrypt_auth[sizeof(struct ceph_fscrypt_auth)]; // for context
1223-
u8 fscrypt_file[sizeof(u64)]; // for size
12241223
};
12251224

12261225
/* Marshal up the cap msg to the MDS */
@@ -1255,7 +1254,13 @@ static void encode_cap_msg(struct ceph_msg *msg, struct cap_msg_args *arg)
12551254
fc->ino = cpu_to_le64(arg->ino);
12561255
fc->snap_follows = cpu_to_le64(arg->follows);
12571256

1258-
fc->size = cpu_to_le64(arg->size);
1257+
#if IS_ENABLED(CONFIG_FS_ENCRYPTION)
1258+
if (arg->encrypted)
1259+
fc->size = cpu_to_le64(round_up(arg->size,
1260+
CEPH_FSCRYPT_BLOCK_SIZE));
1261+
else
1262+
#endif
1263+
fc->size = cpu_to_le64(arg->size);
12591264
fc->max_size = cpu_to_le64(arg->max_size);
12601265
ceph_encode_timespec64(&fc->mtime, &arg->mtime);
12611266
ceph_encode_timespec64(&fc->atime, &arg->atime);
@@ -1315,11 +1320,17 @@ static void encode_cap_msg(struct ceph_msg *msg, struct cap_msg_args *arg)
13151320
ceph_encode_64(&p, 0);
13161321

13171322
#if IS_ENABLED(CONFIG_FS_ENCRYPTION)
1318-
/* fscrypt_auth and fscrypt_file (version 12) */
1323+
/*
1324+
* fscrypt_auth and fscrypt_file (version 12)
1325+
*
1326+
* fscrypt_auth holds the crypto context (if any). fscrypt_file
1327+
* tracks the real i_size as an __le64 field (and we use a rounded-up
1328+
* i_size in the traditional size field).
1329+
*/
13191330
ceph_encode_32(&p, arg->fscrypt_auth_len);
13201331
ceph_encode_copy(&p, arg->fscrypt_auth, arg->fscrypt_auth_len);
1321-
ceph_encode_32(&p, arg->fscrypt_file_len);
1322-
ceph_encode_copy(&p, arg->fscrypt_file, arg->fscrypt_file_len);
1332+
ceph_encode_32(&p, sizeof(__le64));
1333+
ceph_encode_64(&p, arg->size);
13231334
#else /* CONFIG_FS_ENCRYPTION */
13241335
ceph_encode_32(&p, 0);
13251336
ceph_encode_32(&p, 0);
@@ -1391,7 +1402,6 @@ static void __prep_cap(struct cap_msg_args *arg, struct ceph_cap *cap,
13911402
arg->follows = flushing ? ci->i_head_snapc->seq : 0;
13921403
arg->flush_tid = flush_tid;
13931404
arg->oldest_flush_tid = oldest_flush_tid;
1394-
13951405
arg->size = i_size_read(inode);
13961406
ci->i_reported_size = arg->size;
13971407
arg->max_size = ci->i_wanted_max_size;
@@ -1445,6 +1455,7 @@ static void __prep_cap(struct cap_msg_args *arg, struct ceph_cap *cap,
14451455
}
14461456
}
14471457
arg->flags = flags;
1458+
arg->encrypted = IS_ENCRYPTED(inode);
14481459
#if IS_ENABLED(CONFIG_FS_ENCRYPTION)
14491460
if (ci->fscrypt_auth_len &&
14501461
WARN_ON_ONCE(ci->fscrypt_auth_len > sizeof(struct ceph_fscrypt_auth))) {
@@ -1456,21 +1467,21 @@ static void __prep_cap(struct cap_msg_args *arg, struct ceph_cap *cap,
14561467
min_t(size_t, ci->fscrypt_auth_len,
14571468
sizeof(arg->fscrypt_auth)));
14581469
}
1459-
/* FIXME: use this to track "real" size */
1460-
arg->fscrypt_file_len = 0;
14611470
#endif /* CONFIG_FS_ENCRYPTION */
14621471
}
14631472

1473+
#if IS_ENABLED(CONFIG_FS_ENCRYPTION)
14641474
#define CAP_MSG_FIXED_FIELDS (sizeof(struct ceph_mds_caps) + \
1465-
4 + 8 + 4 + 4 + 8 + 4 + 4 + 4 + 8 + 8 + 4 + 8 + 8 + 4 + 4)
1475+
4 + 8 + 4 + 4 + 8 + 4 + 4 + 4 + 8 + 8 + 4 + 8 + 8 + 4 + 4 + 8)
14661476

1467-
#if IS_ENABLED(CONFIG_FS_ENCRYPTION)
14681477
static inline int cap_msg_size(struct cap_msg_args *arg)
14691478
{
1470-
return CAP_MSG_FIXED_FIELDS + arg->fscrypt_auth_len +
1471-
arg->fscrypt_file_len;
1479+
return CAP_MSG_FIXED_FIELDS + arg->fscrypt_auth_len;
14721480
}
14731481
#else
1482+
#define CAP_MSG_FIXED_FIELDS (sizeof(struct ceph_mds_caps) + \
1483+
4 + 8 + 4 + 4 + 8 + 4 + 4 + 4 + 8 + 8 + 4 + 8 + 8 + 4 + 4)
1484+
14741485
static inline int cap_msg_size(struct cap_msg_args *arg)
14751486
{
14761487
return CAP_MSG_FIXED_FIELDS;
@@ -1550,13 +1561,10 @@ static inline int __send_flush_snap(struct inode *inode,
15501561
arg.inline_data = capsnap->inline_data;
15511562
arg.flags = 0;
15521563
arg.wake = false;
1564+
arg.encrypted = IS_ENCRYPTED(inode);
15531565

1554-
/*
1555-
* No fscrypt_auth changes from a capsnap. It will need
1556-
* to update fscrypt_file on size changes (TODO).
1557-
*/
1566+
/* No fscrypt_auth changes from a capsnap.*/
15581567
arg.fscrypt_auth_len = 0;
1559-
arg.fscrypt_file_len = 0;
15601568

15611569
msg = ceph_msg_new(CEPH_MSG_CLIENT_CAPS, cap_msg_size(&arg),
15621570
GFP_NOFS, false);

fs/ceph/dir.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -915,6 +915,9 @@ static int ceph_mknod(struct mnt_idmap *idmap, struct inode *dir,
915915
goto out_req;
916916
}
917917

918+
if (S_ISREG(mode) && IS_ENCRYPTED(dir))
919+
set_bit(CEPH_MDS_R_FSCRYPT_FILE, &req->r_req_flags);
920+
918921
req->r_dentry = dget(dentry);
919922
req->r_num_caps = 2;
920923
req->r_parent = dir;

fs/ceph/file.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -790,6 +790,7 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry,
790790
req->r_parent = dir;
791791
ihold(dir);
792792
if (IS_ENCRYPTED(dir)) {
793+
set_bit(CEPH_MDS_R_FSCRYPT_FILE, &req->r_req_flags);
793794
if (!fscrypt_has_encryption_key(dir)) {
794795
spin_lock(&dentry->d_lock);
795796
dentry->d_flags |= DCACHE_NOKEY_NAME;

fs/ceph/inode.c

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1028,6 +1028,7 @@ int ceph_fill_inode(struct inode *inode, struct page *locked_page,
10281028

10291029
if (new_version ||
10301030
(new_issued & (CEPH_CAP_ANY_FILE_RD | CEPH_CAP_ANY_FILE_WR))) {
1031+
u64 size = le64_to_cpu(info->size);
10311032
s64 old_pool = ci->i_layout.pool_id;
10321033
struct ceph_string *old_ns;
10331034

@@ -1041,10 +1042,22 @@ int ceph_fill_inode(struct inode *inode, struct page *locked_page,
10411042

10421043
pool_ns = old_ns;
10431044

1045+
if (IS_ENCRYPTED(inode) && size &&
1046+
iinfo->fscrypt_file_len == sizeof(__le64)) {
1047+
u64 fsize = __le64_to_cpu(*(__le64 *)iinfo->fscrypt_file);
1048+
1049+
if (size == round_up(fsize, CEPH_FSCRYPT_BLOCK_SIZE)) {
1050+
size = fsize;
1051+
} else {
1052+
pr_warn("fscrypt size mismatch: size=%llu fscrypt_file=%llu, discarding fscrypt_file size.\n",
1053+
info->size, size);
1054+
}
1055+
}
1056+
10441057
queue_trunc = ceph_fill_file_size(inode, issued,
10451058
le32_to_cpu(info->truncate_seq),
10461059
le64_to_cpu(info->truncate_size),
1047-
le64_to_cpu(info->size));
1060+
size);
10481061
/* only update max_size on auth cap */
10491062
if ((info->cap.flags & CEPH_CAP_FLAG_AUTH) &&
10501063
ci->i_max_size != le64_to_cpu(info->max_size)) {
@@ -2388,11 +2401,25 @@ int __ceph_setattr(struct inode *inode, struct iattr *attr,
23882401
}
23892402
} else if ((issued & CEPH_CAP_FILE_SHARED) == 0 ||
23902403
attr->ia_size != isize) {
2391-
req->r_args.setattr.size = cpu_to_le64(attr->ia_size);
2392-
req->r_args.setattr.old_size = cpu_to_le64(isize);
23932404
mask |= CEPH_SETATTR_SIZE;
23942405
release |= CEPH_CAP_FILE_SHARED | CEPH_CAP_FILE_EXCL |
23952406
CEPH_CAP_FILE_RD | CEPH_CAP_FILE_WR;
2407+
if (IS_ENCRYPTED(inode) && attr->ia_size) {
2408+
set_bit(CEPH_MDS_R_FSCRYPT_FILE, &req->r_req_flags);
2409+
mask |= CEPH_SETATTR_FSCRYPT_FILE;
2410+
req->r_args.setattr.size =
2411+
cpu_to_le64(round_up(attr->ia_size,
2412+
CEPH_FSCRYPT_BLOCK_SIZE));
2413+
req->r_args.setattr.old_size =
2414+
cpu_to_le64(round_up(isize,
2415+
CEPH_FSCRYPT_BLOCK_SIZE));
2416+
req->r_fscrypt_file = attr->ia_size;
2417+
/* FIXME: client must zero out any partial blocks! */
2418+
} else {
2419+
req->r_args.setattr.size = cpu_to_le64(attr->ia_size);
2420+
req->r_args.setattr.old_size = cpu_to_le64(isize);
2421+
req->r_fscrypt_file = 0;
2422+
}
23962423
}
23972424
}
23982425
if (ia_valid & ATTR_MTIME) {

fs/ceph/mds_client.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2832,7 +2832,12 @@ static void encode_mclientrequest_tail(void **p,
28322832
} else {
28332833
ceph_encode_32(p, 0);
28342834
}
2835-
ceph_encode_32(p, 0); // fscrypt_file for now
2835+
if (test_bit(CEPH_MDS_R_FSCRYPT_FILE, &req->r_req_flags)) {
2836+
ceph_encode_32(p, sizeof(__le64));
2837+
ceph_encode_64(p, req->r_fscrypt_file);
2838+
} else {
2839+
ceph_encode_32(p, 0);
2840+
}
28362841
}
28372842

28382843
/*
@@ -2922,6 +2927,8 @@ static struct ceph_msg *create_request_message(struct ceph_mds_session *session,
29222927

29232928
/* fscrypt_file */
29242929
len += sizeof(u32);
2930+
if (test_bit(CEPH_MDS_R_FSCRYPT_FILE, &req->r_req_flags))
2931+
len += sizeof(__le64);
29252932

29262933
msg = ceph_msg_new2(CEPH_MSG_CLIENT_REQUEST, len, 1, GFP_NOFS, false);
29272934
if (!msg) {

fs/ceph/mds_client.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,13 +282,15 @@ struct ceph_mds_request {
282282
#define CEPH_MDS_R_DID_PREPOPULATE (6) /* prepopulated readdir */
283283
#define CEPH_MDS_R_PARENT_LOCKED (7) /* is r_parent->i_rwsem wlocked? */
284284
#define CEPH_MDS_R_ASYNC (8) /* async request */
285+
#define CEPH_MDS_R_FSCRYPT_FILE (9) /* must marshal fscrypt_file field */
285286
unsigned long r_req_flags;
286287

287288
struct mutex r_fill_mutex;
288289

289290
union ceph_mds_request_args r_args;
290291

291292
struct ceph_fscrypt_auth *r_fscrypt_auth;
293+
u64 r_fscrypt_file;
292294

293295
u8 *r_altname; /* fscrypt binary crypttext for long filenames */
294296
u32 r_altname_len; /* length of r_altname */

0 commit comments

Comments
 (0)