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

ceph: fscrypt_auth handling for ceph

Most fscrypt-enabled filesystems store the crypto context in an xattr,
but that's problematic for ceph as xatts are governed by the XATTR cap,
but we really want the crypto context as part of the AUTH cap.

Because of this, the MDS has added two new inode metadata fields:
fscrypt_auth and fscrypt_file. The former is used to hold the crypto
context, and the latter is used to track the real file size.

Parse new fscrypt_auth and fscrypt_file fields in inode traces. For now,
we don't use fscrypt_file, but fscrypt_auth is used to hold the fscrypt
context.

Allow the client to use a setattr request for setting the fscrypt_auth
field. Since this is not a standard setattr request from the VFS, we add
a new field to __ceph_setattr that carries ceph-specific inode attrs.

Have the set_context op do a setattr that sets the fscrypt_auth value,
and get_context just return the contents of that field (since it should
always be available).

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>

authored by

Jeff Layton and committed by
Ilya Dryomov
2d332d5b 4de77f25

+385 -35
+1
fs/ceph/Makefile
··· 12 12 13 13 ceph-$(CONFIG_CEPH_FSCACHE) += cache.o 14 14 ceph-$(CONFIG_CEPH_FS_POSIX_ACL) += acl.o 15 + ceph-$(CONFIG_FS_ENCRYPTION) += crypto.o
+2 -2
fs/ceph/acl.c
··· 140 140 newattrs.ia_ctime = current_time(inode); 141 141 newattrs.ia_mode = new_mode; 142 142 newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; 143 - ret = __ceph_setattr(inode, &newattrs); 143 + ret = __ceph_setattr(inode, &newattrs, NULL); 144 144 if (ret) 145 145 goto out_free; 146 146 } ··· 151 151 newattrs.ia_ctime = old_ctime; 152 152 newattrs.ia_mode = old_mode; 153 153 newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; 154 - __ceph_setattr(inode, &newattrs); 154 + __ceph_setattr(inode, &newattrs, NULL); 155 155 } 156 156 goto out_free; 157 157 }
+65 -13
fs/ceph/caps.c
··· 14 14 #include "super.h" 15 15 #include "mds_client.h" 16 16 #include "cache.h" 17 + #include "crypto.h" 17 18 #include <linux/ceph/decode.h> 18 19 #include <linux/ceph/messenger.h> 19 20 ··· 1217 1216 umode_t mode; 1218 1217 bool inline_data; 1219 1218 bool wake; 1219 + u32 fscrypt_auth_len; 1220 + u32 fscrypt_file_len; 1221 + u8 fscrypt_auth[sizeof(struct ceph_fscrypt_auth)]; // for context 1222 + u8 fscrypt_file[sizeof(u64)]; // for size 1220 1223 }; 1221 - 1222 - /* 1223 - * cap struct size + flock buffer size + inline version + inline data size + 1224 - * osd_epoch_barrier + oldest_flush_tid 1225 - */ 1226 - #define CAP_MSG_SIZE (sizeof(struct ceph_mds_caps) + \ 1227 - 4 + 8 + 4 + 4 + 8 + 4 + 4 + 4 + 8 + 8 + 4) 1228 1224 1229 1225 /* Marshal up the cap msg to the MDS */ 1230 1226 static void encode_cap_msg(struct ceph_msg *msg, struct cap_msg_args *arg) ··· 1238 1240 arg->size, arg->max_size, arg->xattr_version, 1239 1241 arg->xattr_buf ? (int)arg->xattr_buf->vec.iov_len : 0); 1240 1242 1241 - msg->hdr.version = cpu_to_le16(10); 1243 + msg->hdr.version = cpu_to_le16(12); 1242 1244 msg->hdr.tid = cpu_to_le64(arg->flush_tid); 1243 1245 1244 1246 fc = msg->front.iov_base; ··· 1309 1311 1310 1312 /* Advisory flags (version 10) */ 1311 1313 ceph_encode_32(&p, arg->flags); 1314 + 1315 + /* dirstats (version 11) - these are r/o on the client */ 1316 + ceph_encode_64(&p, 0); 1317 + ceph_encode_64(&p, 0); 1318 + 1319 + #if IS_ENABLED(CONFIG_FS_ENCRYPTION) 1320 + /* fscrypt_auth and fscrypt_file (version 12) */ 1321 + ceph_encode_32(&p, arg->fscrypt_auth_len); 1322 + ceph_encode_copy(&p, arg->fscrypt_auth, arg->fscrypt_auth_len); 1323 + ceph_encode_32(&p, arg->fscrypt_file_len); 1324 + ceph_encode_copy(&p, arg->fscrypt_file, arg->fscrypt_file_len); 1325 + #else /* CONFIG_FS_ENCRYPTION */ 1326 + ceph_encode_32(&p, 0); 1327 + ceph_encode_32(&p, 0); 1328 + #endif /* CONFIG_FS_ENCRYPTION */ 1312 1329 } 1313 1330 1314 1331 /* ··· 1445 1432 } 1446 1433 } 1447 1434 arg->flags = flags; 1435 + #if IS_ENABLED(CONFIG_FS_ENCRYPTION) 1436 + if (ci->fscrypt_auth_len && 1437 + WARN_ON_ONCE(ci->fscrypt_auth_len > sizeof(struct ceph_fscrypt_auth))) { 1438 + /* Don't set this if it's too big */ 1439 + arg->fscrypt_auth_len = 0; 1440 + } else { 1441 + arg->fscrypt_auth_len = ci->fscrypt_auth_len; 1442 + memcpy(arg->fscrypt_auth, ci->fscrypt_auth, 1443 + min_t(size_t, ci->fscrypt_auth_len, 1444 + sizeof(arg->fscrypt_auth))); 1445 + } 1446 + /* FIXME: use this to track "real" size */ 1447 + arg->fscrypt_file_len = 0; 1448 + #endif /* CONFIG_FS_ENCRYPTION */ 1448 1449 } 1450 + 1451 + #define CAP_MSG_FIXED_FIELDS (sizeof(struct ceph_mds_caps) + \ 1452 + 4 + 8 + 4 + 4 + 8 + 4 + 4 + 4 + 8 + 8 + 4 + 8 + 8 + 4 + 4) 1453 + 1454 + #if IS_ENABLED(CONFIG_FS_ENCRYPTION) 1455 + static inline int cap_msg_size(struct cap_msg_args *arg) 1456 + { 1457 + return CAP_MSG_FIXED_FIELDS + arg->fscrypt_auth_len + 1458 + arg->fscrypt_file_len; 1459 + } 1460 + #else 1461 + static inline int cap_msg_size(struct cap_msg_args *arg) 1462 + { 1463 + return CAP_MSG_FIXED_FIELDS; 1464 + } 1465 + #endif /* CONFIG_FS_ENCRYPTION */ 1449 1466 1450 1467 /* 1451 1468 * Send a cap msg on the given inode. ··· 1487 1444 struct ceph_msg *msg; 1488 1445 struct inode *inode = &ci->netfs.inode; 1489 1446 1490 - msg = ceph_msg_new(CEPH_MSG_CLIENT_CAPS, CAP_MSG_SIZE, GFP_NOFS, false); 1447 + msg = ceph_msg_new(CEPH_MSG_CLIENT_CAPS, cap_msg_size(arg), GFP_NOFS, 1448 + false); 1491 1449 if (!msg) { 1492 1450 pr_err("error allocating cap msg: ino (%llx.%llx) flushing %s tid %llu, requeuing cap.\n", 1493 1451 ceph_vinop(inode), ceph_cap_string(arg->dirty), ··· 1513 1469 { 1514 1470 struct cap_msg_args arg; 1515 1471 struct ceph_msg *msg; 1516 - 1517 - msg = ceph_msg_new(CEPH_MSG_CLIENT_CAPS, CAP_MSG_SIZE, GFP_NOFS, false); 1518 - if (!msg) 1519 - return -ENOMEM; 1520 1472 1521 1473 arg.session = session; 1522 1474 arg.ino = ceph_vino(inode).ino; ··· 1550 1510 arg.inline_data = capsnap->inline_data; 1551 1511 arg.flags = 0; 1552 1512 arg.wake = false; 1513 + 1514 + /* 1515 + * No fscrypt_auth changes from a capsnap. It will need 1516 + * to update fscrypt_file on size changes (TODO). 1517 + */ 1518 + arg.fscrypt_auth_len = 0; 1519 + arg.fscrypt_file_len = 0; 1520 + 1521 + msg = ceph_msg_new(CEPH_MSG_CLIENT_CAPS, cap_msg_size(&arg), 1522 + GFP_NOFS, false); 1523 + if (!msg) 1524 + return -ENOMEM; 1553 1525 1554 1526 encode_cap_msg(msg, &arg); 1555 1527 ceph_con_send(&arg.session->s_con, msg);
+77
fs/ceph/crypto.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include <linux/ceph/ceph_debug.h> 3 + #include <linux/xattr.h> 4 + #include <linux/fscrypt.h> 5 + 6 + #include "super.h" 7 + #include "crypto.h" 8 + 9 + static int ceph_crypt_get_context(struct inode *inode, void *ctx, size_t len) 10 + { 11 + struct ceph_inode_info *ci = ceph_inode(inode); 12 + struct ceph_fscrypt_auth *cfa = (struct ceph_fscrypt_auth *)ci->fscrypt_auth; 13 + u32 ctxlen; 14 + 15 + /* Non existent or too short? */ 16 + if (!cfa || (ci->fscrypt_auth_len < (offsetof(struct ceph_fscrypt_auth, cfa_blob) + 1))) 17 + return -ENOBUFS; 18 + 19 + /* Some format we don't recognize? */ 20 + if (le32_to_cpu(cfa->cfa_version) != CEPH_FSCRYPT_AUTH_VERSION) 21 + return -ENOBUFS; 22 + 23 + ctxlen = le32_to_cpu(cfa->cfa_blob_len); 24 + if (len < ctxlen) 25 + return -ERANGE; 26 + 27 + memcpy(ctx, cfa->cfa_blob, ctxlen); 28 + return ctxlen; 29 + } 30 + 31 + static int ceph_crypt_set_context(struct inode *inode, const void *ctx, 32 + size_t len, void *fs_data) 33 + { 34 + int ret; 35 + struct iattr attr = { }; 36 + struct ceph_iattr cia = { }; 37 + struct ceph_fscrypt_auth *cfa; 38 + 39 + WARN_ON_ONCE(fs_data); 40 + 41 + if (len > FSCRYPT_SET_CONTEXT_MAX_SIZE) 42 + return -EINVAL; 43 + 44 + cfa = kzalloc(sizeof(*cfa), GFP_KERNEL); 45 + if (!cfa) 46 + return -ENOMEM; 47 + 48 + cfa->cfa_version = cpu_to_le32(CEPH_FSCRYPT_AUTH_VERSION); 49 + cfa->cfa_blob_len = cpu_to_le32(len); 50 + memcpy(cfa->cfa_blob, ctx, len); 51 + 52 + cia.fscrypt_auth = cfa; 53 + 54 + ret = __ceph_setattr(inode, &attr, &cia); 55 + if (ret == 0) 56 + inode_set_flags(inode, S_ENCRYPTED, S_ENCRYPTED); 57 + kfree(cia.fscrypt_auth); 58 + return ret; 59 + } 60 + 61 + static bool ceph_crypt_empty_dir(struct inode *inode) 62 + { 63 + struct ceph_inode_info *ci = ceph_inode(inode); 64 + 65 + return ci->i_rsubdirs + ci->i_rfiles == 1; 66 + } 67 + 68 + static struct fscrypt_operations ceph_fscrypt_ops = { 69 + .get_context = ceph_crypt_get_context, 70 + .set_context = ceph_crypt_set_context, 71 + .empty_dir = ceph_crypt_empty_dir, 72 + }; 73 + 74 + void ceph_fscrypt_set_ops(struct super_block *sb) 75 + { 76 + fscrypt_set_ops(sb, &ceph_fscrypt_ops); 77 + }
+36
fs/ceph/crypto.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Ceph fscrypt functionality 4 + */ 5 + 6 + #ifndef _CEPH_CRYPTO_H 7 + #define _CEPH_CRYPTO_H 8 + 9 + #include <linux/fscrypt.h> 10 + 11 + struct ceph_fscrypt_auth { 12 + __le32 cfa_version; 13 + __le32 cfa_blob_len; 14 + u8 cfa_blob[FSCRYPT_SET_CONTEXT_MAX_SIZE]; 15 + } __packed; 16 + 17 + #define CEPH_FSCRYPT_AUTH_VERSION 1 18 + static inline u32 ceph_fscrypt_auth_len(struct ceph_fscrypt_auth *fa) 19 + { 20 + u32 ctxsize = le32_to_cpu(fa->cfa_blob_len); 21 + 22 + return offsetof(struct ceph_fscrypt_auth, cfa_blob) + ctxsize; 23 + } 24 + 25 + #ifdef CONFIG_FS_ENCRYPTION 26 + void ceph_fscrypt_set_ops(struct super_block *sb); 27 + 28 + #else /* CONFIG_FS_ENCRYPTION */ 29 + 30 + static inline void ceph_fscrypt_set_ops(struct super_block *sb) 31 + { 32 + } 33 + 34 + #endif /* CONFIG_FS_ENCRYPTION */ 35 + 36 + #endif
+62 -2
fs/ceph/inode.c
··· 14 14 #include <linux/random.h> 15 15 #include <linux/sort.h> 16 16 #include <linux/iversion.h> 17 + #include <linux/fscrypt.h> 17 18 18 19 #include "super.h" 19 20 #include "mds_client.h" 20 21 #include "cache.h" 22 + #include "crypto.h" 21 23 #include <linux/ceph/decode.h> 22 24 23 25 /* ··· 619 617 INIT_WORK(&ci->i_work, ceph_inode_work); 620 618 ci->i_work_mask = 0; 621 619 memset(&ci->i_btime, '\0', sizeof(ci->i_btime)); 620 + #ifdef CONFIG_FS_ENCRYPTION 621 + ci->fscrypt_auth = NULL; 622 + ci->fscrypt_auth_len = 0; 623 + #endif 622 624 return &ci->netfs.inode; 623 625 } 624 626 ··· 631 625 struct ceph_inode_info *ci = ceph_inode(inode); 632 626 633 627 kfree(ci->i_symlink); 628 + #ifdef CONFIG_FS_ENCRYPTION 629 + kfree(ci->fscrypt_auth); 630 + #endif 634 631 kmem_cache_free(ceph_inode_cachep, ci); 635 632 } 636 633 ··· 654 645 clear_inode(inode); 655 646 656 647 ceph_fscache_unregister_inode_cookie(ci); 648 + fscrypt_put_encryption_info(inode); 657 649 658 650 __ceph_remove_caps(ci); 659 651 ··· 944 934 inode->i_blkbits = CEPH_BLOCK_SHIFT; 945 935 946 936 __ceph_update_quota(ci, iinfo->max_bytes, iinfo->max_files); 937 + 938 + #ifdef CONFIG_FS_ENCRYPTION 939 + if (iinfo->fscrypt_auth_len && (inode->i_state & I_NEW)) { 940 + kfree(ci->fscrypt_auth); 941 + ci->fscrypt_auth_len = iinfo->fscrypt_auth_len; 942 + ci->fscrypt_auth = iinfo->fscrypt_auth; 943 + iinfo->fscrypt_auth = NULL; 944 + iinfo->fscrypt_auth_len = 0; 945 + inode_set_flags(inode, S_ENCRYPTED, S_ENCRYPTED); 946 + } 947 + #endif 947 948 948 949 if ((new_version || (new_issued & CEPH_CAP_AUTH_SHARED)) && 949 950 (issued & CEPH_CAP_AUTH_EXCL) == 0) { ··· 2100 2079 .listxattr = ceph_listxattr, 2101 2080 }; 2102 2081 2103 - int __ceph_setattr(struct inode *inode, struct iattr *attr) 2082 + int __ceph_setattr(struct inode *inode, struct iattr *attr, 2083 + struct ceph_iattr *cia) 2104 2084 { 2105 2085 struct ceph_inode_info *ci = ceph_inode(inode); 2106 2086 unsigned int ia_valid = attr->ia_valid; ··· 2141 2119 } 2142 2120 2143 2121 dout("setattr %p issued %s\n", inode, ceph_cap_string(issued)); 2122 + #if IS_ENABLED(CONFIG_FS_ENCRYPTION) 2123 + if (cia && cia->fscrypt_auth) { 2124 + u32 len = ceph_fscrypt_auth_len(cia->fscrypt_auth); 2125 + 2126 + if (len > sizeof(*cia->fscrypt_auth)) { 2127 + err = -EINVAL; 2128 + spin_unlock(&ci->i_ceph_lock); 2129 + goto out; 2130 + } 2131 + 2132 + dout("setattr %llx:%llx fscrypt_auth len %u to %u)\n", 2133 + ceph_vinop(inode), ci->fscrypt_auth_len, len); 2134 + 2135 + /* It should never be re-set once set */ 2136 + WARN_ON_ONCE(ci->fscrypt_auth); 2137 + 2138 + if (issued & CEPH_CAP_AUTH_EXCL) { 2139 + dirtied |= CEPH_CAP_AUTH_EXCL; 2140 + kfree(ci->fscrypt_auth); 2141 + ci->fscrypt_auth = (u8 *)cia->fscrypt_auth; 2142 + ci->fscrypt_auth_len = len; 2143 + } else if ((issued & CEPH_CAP_AUTH_SHARED) == 0 || 2144 + ci->fscrypt_auth_len != len || 2145 + memcmp(ci->fscrypt_auth, cia->fscrypt_auth, len)) { 2146 + req->r_fscrypt_auth = cia->fscrypt_auth; 2147 + mask |= CEPH_SETATTR_FSCRYPT_AUTH; 2148 + release |= CEPH_CAP_AUTH_SHARED; 2149 + } 2150 + cia->fscrypt_auth = NULL; 2151 + } 2152 + #else 2153 + if (cia && cia->fscrypt_auth) { 2154 + err = -EINVAL; 2155 + spin_unlock(&ci->i_ceph_lock); 2156 + goto out; 2157 + } 2158 + #endif /* CONFIG_FS_ENCRYPTION */ 2144 2159 2145 2160 if (ia_valid & ATTR_UID) { 2146 2161 dout("setattr %p uid %d -> %d\n", inode, ··· 2341 2282 req->r_stamp = attr->ia_ctime; 2342 2283 err = ceph_mdsc_do_request(mdsc, NULL, req); 2343 2284 } 2285 + out: 2344 2286 dout("setattr %p result=%d (%s locally, %d remote)\n", inode, err, 2345 2287 ceph_cap_string(dirtied), mask); 2346 2288 ··· 2382 2322 ceph_quota_is_max_bytes_exceeded(inode, attr->ia_size)) 2383 2323 return -EDQUOT; 2384 2324 2385 - err = __ceph_setattr(inode, attr); 2325 + err = __ceph_setattr(inode, attr, NULL); 2386 2326 2387 2327 if (err >= 0 && (attr->ia_valid & ATTR_MODE)) 2388 2328 err = posix_acl_chmod(&nop_mnt_idmap, dentry, attr->ia_mode);
+105 -9
fs/ceph/mds_client.c
··· 15 15 16 16 #include "super.h" 17 17 #include "mds_client.h" 18 + #include "crypto.h" 18 19 19 20 #include <linux/ceph/ceph_features.h> 20 21 #include <linux/ceph/messenger.h> ··· 185 184 info->rsnaps = 0; 186 185 } 187 186 187 + if (struct_v >= 5) { 188 + u32 alen; 189 + 190 + ceph_decode_32_safe(p, end, alen, bad); 191 + 192 + while (alen--) { 193 + u32 len; 194 + 195 + /* key */ 196 + ceph_decode_32_safe(p, end, len, bad); 197 + ceph_decode_skip_n(p, end, len, bad); 198 + /* value */ 199 + ceph_decode_32_safe(p, end, len, bad); 200 + ceph_decode_skip_n(p, end, len, bad); 201 + } 202 + } 203 + 204 + /* fscrypt flag -- ignore */ 205 + if (struct_v >= 6) 206 + ceph_decode_skip_8(p, end, bad); 207 + 208 + info->fscrypt_auth = NULL; 209 + info->fscrypt_auth_len = 0; 210 + info->fscrypt_file = NULL; 211 + info->fscrypt_file_len = 0; 212 + if (struct_v >= 7) { 213 + ceph_decode_32_safe(p, end, info->fscrypt_auth_len, bad); 214 + if (info->fscrypt_auth_len) { 215 + info->fscrypt_auth = kmalloc(info->fscrypt_auth_len, 216 + GFP_KERNEL); 217 + if (!info->fscrypt_auth) 218 + return -ENOMEM; 219 + ceph_decode_copy_safe(p, end, info->fscrypt_auth, 220 + info->fscrypt_auth_len, bad); 221 + } 222 + ceph_decode_32_safe(p, end, info->fscrypt_file_len, bad); 223 + if (info->fscrypt_file_len) { 224 + info->fscrypt_file = kmalloc(info->fscrypt_file_len, 225 + GFP_KERNEL); 226 + if (!info->fscrypt_file) 227 + return -ENOMEM; 228 + ceph_decode_copy_safe(p, end, info->fscrypt_file, 229 + info->fscrypt_file_len, bad); 230 + } 231 + } 188 232 *p = end; 189 233 } else { 234 + /* legacy (unversioned) struct */ 190 235 if (features & CEPH_FEATURE_MDS_INLINE_DATA) { 191 236 ceph_decode_64_safe(p, end, info->inline_version, bad); 192 237 ceph_decode_32_safe(p, end, info->inline_len, bad); ··· 698 651 699 652 static void destroy_reply_info(struct ceph_mds_reply_info_parsed *info) 700 653 { 654 + int i; 655 + 656 + kfree(info->diri.fscrypt_auth); 657 + kfree(info->diri.fscrypt_file); 658 + kfree(info->targeti.fscrypt_auth); 659 + kfree(info->targeti.fscrypt_file); 701 660 if (!info->dir_entries) 702 661 return; 662 + 663 + for (i = 0; i < info->dir_nr; i++) { 664 + struct ceph_mds_reply_dir_entry *rde = info->dir_entries + i; 665 + 666 + kfree(rde->inode.fscrypt_auth); 667 + kfree(rde->inode.fscrypt_file); 668 + } 703 669 free_pages((unsigned long)info->dir_entries, get_order(info->dir_buf_size)); 704 670 } 705 671 ··· 1026 966 put_cred(req->r_cred); 1027 967 if (req->r_pagelist) 1028 968 ceph_pagelist_release(req->r_pagelist); 969 + kfree(req->r_fscrypt_auth); 1029 970 put_request_session(req); 1030 971 ceph_unreserve_caps(req->r_mdsc, &req->r_caps_reservation); 1031 972 WARN_ON_ONCE(!list_empty(&req->r_wait)); ··· 2604 2543 return r; 2605 2544 } 2606 2545 2607 - static void encode_timestamp_and_gids(void **p, 2608 - const struct ceph_mds_request *req) 2546 + static void encode_mclientrequest_tail(void **p, 2547 + const struct ceph_mds_request *req) 2609 2548 { 2610 2549 struct ceph_timespec ts; 2611 2550 int i; ··· 2618 2557 for (i = 0; i < req->r_cred->group_info->ngroups; i++) 2619 2558 ceph_encode_64(p, from_kgid(&init_user_ns, 2620 2559 req->r_cred->group_info->gid[i])); 2560 + 2561 + /* v5: altname (TODO: skip for now) */ 2562 + ceph_encode_32(p, 0); 2563 + 2564 + /* v6: fscrypt_auth and fscrypt_file */ 2565 + if (req->r_fscrypt_auth) { 2566 + u32 authlen = ceph_fscrypt_auth_len(req->r_fscrypt_auth); 2567 + 2568 + ceph_encode_32(p, authlen); 2569 + ceph_encode_copy(p, req->r_fscrypt_auth, authlen); 2570 + } else { 2571 + ceph_encode_32(p, 0); 2572 + } 2573 + ceph_encode_32(p, 0); // fscrypt_file for now 2621 2574 } 2622 2575 2623 2576 /* ··· 2680 2605 goto out_free1; 2681 2606 } 2682 2607 2608 + /* head */ 2683 2609 len = legacy ? sizeof(*head) : sizeof(struct ceph_mds_request_head); 2684 - len += pathlen1 + pathlen2 + 2*(1 + sizeof(u32) + sizeof(u64)) + 2685 - sizeof(struct ceph_timespec); 2686 - len += sizeof(u32) + (sizeof(u64) * req->r_cred->group_info->ngroups); 2687 2610 2688 - /* calculate (max) length for cap releases */ 2611 + /* filepaths */ 2612 + len += 2 * (1 + sizeof(u32) + sizeof(u64)); 2613 + len += pathlen1 + pathlen2; 2614 + 2615 + /* cap releases */ 2689 2616 len += sizeof(struct ceph_mds_request_release) * 2690 2617 (!!req->r_inode_drop + !!req->r_dentry_drop + 2691 2618 !!req->r_old_inode_drop + !!req->r_old_dentry_drop); ··· 2696 2619 len += pathlen1; 2697 2620 if (req->r_old_dentry_drop) 2698 2621 len += pathlen2; 2622 + 2623 + /* MClientRequest tail */ 2624 + 2625 + /* req->r_stamp */ 2626 + len += sizeof(struct ceph_timespec); 2627 + 2628 + /* gid list */ 2629 + len += sizeof(u32) + (sizeof(u64) * req->r_cred->group_info->ngroups); 2630 + 2631 + /* alternate name */ 2632 + len += sizeof(u32); // TODO 2633 + 2634 + /* fscrypt_auth */ 2635 + len += sizeof(u32); // fscrypt_auth 2636 + if (req->r_fscrypt_auth) 2637 + len += ceph_fscrypt_auth_len(req->r_fscrypt_auth); 2638 + 2639 + /* fscrypt_file */ 2640 + len += sizeof(u32); 2699 2641 2700 2642 msg = ceph_msg_new2(CEPH_MSG_CLIENT_REQUEST, len, 1, GFP_NOFS, false); 2701 2643 if (!msg) { ··· 2735 2639 } else { 2736 2640 struct ceph_mds_request_head *new_head = msg->front.iov_base; 2737 2641 2738 - msg->hdr.version = cpu_to_le16(4); 2642 + msg->hdr.version = cpu_to_le16(6); 2739 2643 new_head->version = cpu_to_le16(CEPH_MDS_REQUEST_HEAD_VERSION); 2740 2644 head = (struct ceph_mds_request_head_old *)&new_head->oldest_client_tid; 2741 2645 p = msg->front.iov_base + sizeof(*new_head); ··· 2786 2690 2787 2691 head->num_releases = cpu_to_le16(releases); 2788 2692 2789 - encode_timestamp_and_gids(&p, req); 2693 + encode_mclientrequest_tail(&p, req); 2790 2694 2791 2695 if (WARN_ON_ONCE(p > end)) { 2792 2696 ceph_msg_put(msg); ··· 2916 2820 rhead->num_releases = 0; 2917 2821 2918 2822 p = msg->front.iov_base + req->r_request_release_offset; 2919 - encode_timestamp_and_gids(&p, req); 2823 + encode_mclientrequest_tail(&p, req); 2920 2824 2921 2825 msg->front.iov_len = p - msg->front.iov_base; 2922 2826 msg->hdr.front_len = cpu_to_le32(msg->front.iov_len);
+7
fs/ceph/mds_client.h
··· 86 86 s32 dir_pin; 87 87 struct ceph_timespec btime; 88 88 struct ceph_timespec snap_btime; 89 + u8 *fscrypt_auth; 90 + u8 *fscrypt_file; 91 + u32 fscrypt_auth_len; 92 + u32 fscrypt_file_len; 89 93 u64 rsnaps; 90 94 u64 change_attr; 91 95 }; ··· 282 278 struct mutex r_fill_mutex; 283 279 284 280 union ceph_mds_request_args r_args; 281 + 282 + struct ceph_fscrypt_auth *r_fscrypt_auth; 283 + 285 284 int r_fmode; /* file mode, if expecting cap */ 286 285 int r_request_release_offset; 287 286 const struct cred *r_cred;
+3
fs/ceph/super.c
··· 20 20 #include "super.h" 21 21 #include "mds_client.h" 22 22 #include "cache.h" 23 + #include "crypto.h" 23 24 24 25 #include <linux/ceph/ceph_features.h> 25 26 #include <linux/ceph/decode.h> ··· 1135 1134 s->s_time_min = 0; 1136 1135 s->s_time_max = U32_MAX; 1137 1136 s->s_flags |= SB_NODIRATIME | SB_NOATIME; 1137 + 1138 + ceph_fscrypt_set_ops(s); 1138 1139 1139 1140 ret = set_anon_super_fc(s, fc); 1140 1141 if (ret != 0)
+14 -1
fs/ceph/super.h
··· 450 450 451 451 struct work_struct i_work; 452 452 unsigned long i_work_mask; 453 + 454 + #ifdef CONFIG_FS_ENCRYPTION 455 + u32 fscrypt_auth_len; 456 + u32 fscrypt_file_len; 457 + u8 *fscrypt_auth; 458 + u8 *fscrypt_file; 459 + #endif 453 460 }; 454 461 455 462 struct ceph_netfs_request_data { ··· 1080 1073 } 1081 1074 extern int ceph_permission(struct mnt_idmap *idmap, 1082 1075 struct inode *inode, int mask); 1083 - extern int __ceph_setattr(struct inode *inode, struct iattr *attr); 1076 + 1077 + struct ceph_iattr { 1078 + struct ceph_fscrypt_auth *fscrypt_auth; 1079 + }; 1080 + 1081 + extern int __ceph_setattr(struct inode *inode, struct iattr *attr, 1082 + struct ceph_iattr *cia); 1084 1083 extern int ceph_setattr(struct mnt_idmap *idmap, 1085 1084 struct dentry *dentry, struct iattr *attr); 1086 1085 extern int ceph_getattr(struct mnt_idmap *idmap,
+13 -8
include/linux/ceph/ceph_fs.h
··· 359 359 360 360 extern const char *ceph_mds_op_name(int op); 361 361 362 - 363 - #define CEPH_SETATTR_MODE 1 364 - #define CEPH_SETATTR_UID 2 365 - #define CEPH_SETATTR_GID 4 366 - #define CEPH_SETATTR_MTIME 8 367 - #define CEPH_SETATTR_ATIME 16 368 - #define CEPH_SETATTR_SIZE 32 369 - #define CEPH_SETATTR_CTIME 64 362 + #define CEPH_SETATTR_MODE (1 << 0) 363 + #define CEPH_SETATTR_UID (1 << 1) 364 + #define CEPH_SETATTR_GID (1 << 2) 365 + #define CEPH_SETATTR_MTIME (1 << 3) 366 + #define CEPH_SETATTR_ATIME (1 << 4) 367 + #define CEPH_SETATTR_SIZE (1 << 5) 368 + #define CEPH_SETATTR_CTIME (1 << 6) 369 + #define CEPH_SETATTR_MTIME_NOW (1 << 7) 370 + #define CEPH_SETATTR_ATIME_NOW (1 << 8) 371 + #define CEPH_SETATTR_BTIME (1 << 9) 372 + #define CEPH_SETATTR_KILL_SGUID (1 << 10) 373 + #define CEPH_SETATTR_FSCRYPT_AUTH (1 << 11) 374 + #define CEPH_SETATTR_FSCRYPT_FILE (1 << 12) 370 375 371 376 /* 372 377 * Ceph setxattr request flags.