Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/fs/ceph/crypto.c
29265 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* The base64 encode/decode code was copied from fscrypt:
4
* Copyright (C) 2015, Google, Inc.
5
* Copyright (C) 2015, Motorola Mobility
6
* Written by Uday Savagaonkar, 2014.
7
* Modified by Jaegeuk Kim, 2015.
8
*/
9
#include <linux/ceph/ceph_debug.h>
10
#include <linux/xattr.h>
11
#include <linux/fscrypt.h>
12
#include <linux/ceph/striper.h>
13
14
#include "super.h"
15
#include "mds_client.h"
16
#include "crypto.h"
17
18
/*
19
* The base64url encoding used by fscrypt includes the '_' character, which may
20
* cause problems in snapshot names (which can not start with '_'). Thus, we
21
* used the base64 encoding defined for IMAP mailbox names (RFC 3501) instead,
22
* which replaces '-' and '_' by '+' and ','.
23
*/
24
static const char base64_table[65] =
25
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,";
26
27
int ceph_base64_encode(const u8 *src, int srclen, char *dst)
28
{
29
u32 ac = 0;
30
int bits = 0;
31
int i;
32
char *cp = dst;
33
34
for (i = 0; i < srclen; i++) {
35
ac = (ac << 8) | src[i];
36
bits += 8;
37
do {
38
bits -= 6;
39
*cp++ = base64_table[(ac >> bits) & 0x3f];
40
} while (bits >= 6);
41
}
42
if (bits)
43
*cp++ = base64_table[(ac << (6 - bits)) & 0x3f];
44
return cp - dst;
45
}
46
47
int ceph_base64_decode(const char *src, int srclen, u8 *dst)
48
{
49
u32 ac = 0;
50
int bits = 0;
51
int i;
52
u8 *bp = dst;
53
54
for (i = 0; i < srclen; i++) {
55
const char *p = strchr(base64_table, src[i]);
56
57
if (p == NULL || src[i] == 0)
58
return -1;
59
ac = (ac << 6) | (p - base64_table);
60
bits += 6;
61
if (bits >= 8) {
62
bits -= 8;
63
*bp++ = (u8)(ac >> bits);
64
}
65
}
66
if (ac & ((1 << bits) - 1))
67
return -1;
68
return bp - dst;
69
}
70
71
static int ceph_crypt_get_context(struct inode *inode, void *ctx, size_t len)
72
{
73
struct ceph_inode_info *ci = ceph_inode(inode);
74
struct ceph_fscrypt_auth *cfa = (struct ceph_fscrypt_auth *)ci->fscrypt_auth;
75
u32 ctxlen;
76
77
/* Non existent or too short? */
78
if (!cfa || (ci->fscrypt_auth_len < (offsetof(struct ceph_fscrypt_auth, cfa_blob) + 1)))
79
return -ENOBUFS;
80
81
/* Some format we don't recognize? */
82
if (le32_to_cpu(cfa->cfa_version) != CEPH_FSCRYPT_AUTH_VERSION)
83
return -ENOBUFS;
84
85
ctxlen = le32_to_cpu(cfa->cfa_blob_len);
86
if (len < ctxlen)
87
return -ERANGE;
88
89
memcpy(ctx, cfa->cfa_blob, ctxlen);
90
return ctxlen;
91
}
92
93
static int ceph_crypt_set_context(struct inode *inode, const void *ctx,
94
size_t len, void *fs_data)
95
{
96
int ret;
97
struct iattr attr = { };
98
struct ceph_iattr cia = { };
99
struct ceph_fscrypt_auth *cfa;
100
101
WARN_ON_ONCE(fs_data);
102
103
if (len > FSCRYPT_SET_CONTEXT_MAX_SIZE)
104
return -EINVAL;
105
106
cfa = kzalloc(sizeof(*cfa), GFP_KERNEL);
107
if (!cfa)
108
return -ENOMEM;
109
110
cfa->cfa_version = cpu_to_le32(CEPH_FSCRYPT_AUTH_VERSION);
111
cfa->cfa_blob_len = cpu_to_le32(len);
112
memcpy(cfa->cfa_blob, ctx, len);
113
114
cia.fscrypt_auth = cfa;
115
116
ret = __ceph_setattr(&nop_mnt_idmap, inode, &attr, &cia);
117
if (ret == 0)
118
inode_set_flags(inode, S_ENCRYPTED, S_ENCRYPTED);
119
kfree(cia.fscrypt_auth);
120
return ret;
121
}
122
123
static bool ceph_crypt_empty_dir(struct inode *inode)
124
{
125
struct ceph_inode_info *ci = ceph_inode(inode);
126
127
return ci->i_rsubdirs + ci->i_rfiles == 1;
128
}
129
130
static const union fscrypt_policy *ceph_get_dummy_policy(struct super_block *sb)
131
{
132
return ceph_sb_to_fs_client(sb)->fsc_dummy_enc_policy.policy;
133
}
134
135
static struct fscrypt_operations ceph_fscrypt_ops = {
136
.inode_info_offs = (int)offsetof(struct ceph_inode_info, i_crypt_info) -
137
(int)offsetof(struct ceph_inode_info, netfs.inode),
138
.needs_bounce_pages = 1,
139
.get_context = ceph_crypt_get_context,
140
.set_context = ceph_crypt_set_context,
141
.get_dummy_policy = ceph_get_dummy_policy,
142
.empty_dir = ceph_crypt_empty_dir,
143
};
144
145
void ceph_fscrypt_set_ops(struct super_block *sb)
146
{
147
fscrypt_set_ops(sb, &ceph_fscrypt_ops);
148
}
149
150
void ceph_fscrypt_free_dummy_policy(struct ceph_fs_client *fsc)
151
{
152
fscrypt_free_dummy_policy(&fsc->fsc_dummy_enc_policy);
153
}
154
155
int ceph_fscrypt_prepare_context(struct inode *dir, struct inode *inode,
156
struct ceph_acl_sec_ctx *as)
157
{
158
int ret, ctxsize;
159
bool encrypted = false;
160
struct ceph_inode_info *ci = ceph_inode(inode);
161
162
ret = fscrypt_prepare_new_inode(dir, inode, &encrypted);
163
if (ret)
164
return ret;
165
if (!encrypted)
166
return 0;
167
168
as->fscrypt_auth = kzalloc(sizeof(*as->fscrypt_auth), GFP_KERNEL);
169
if (!as->fscrypt_auth)
170
return -ENOMEM;
171
172
ctxsize = fscrypt_context_for_new_inode(as->fscrypt_auth->cfa_blob,
173
inode);
174
if (ctxsize < 0)
175
return ctxsize;
176
177
as->fscrypt_auth->cfa_version = cpu_to_le32(CEPH_FSCRYPT_AUTH_VERSION);
178
as->fscrypt_auth->cfa_blob_len = cpu_to_le32(ctxsize);
179
180
WARN_ON_ONCE(ci->fscrypt_auth);
181
kfree(ci->fscrypt_auth);
182
ci->fscrypt_auth_len = ceph_fscrypt_auth_len(as->fscrypt_auth);
183
ci->fscrypt_auth = kmemdup(as->fscrypt_auth, ci->fscrypt_auth_len,
184
GFP_KERNEL);
185
if (!ci->fscrypt_auth)
186
return -ENOMEM;
187
188
inode->i_flags |= S_ENCRYPTED;
189
190
return 0;
191
}
192
193
void ceph_fscrypt_as_ctx_to_req(struct ceph_mds_request *req,
194
struct ceph_acl_sec_ctx *as)
195
{
196
swap(req->r_fscrypt_auth, as->fscrypt_auth);
197
}
198
199
/*
200
* User-created snapshots can't start with '_'. Snapshots that start with this
201
* character are special (hint: there aren't real snapshots) and use the
202
* following format:
203
*
204
* _<SNAPSHOT-NAME>_<INODE-NUMBER>
205
*
206
* where:
207
* - <SNAPSHOT-NAME> - the real snapshot name that may need to be decrypted,
208
* - <INODE-NUMBER> - the inode number (in decimal) for the actual snapshot
209
*
210
* This function parses these snapshot names and returns the inode
211
* <INODE-NUMBER>. 'name_len' will also bet set with the <SNAPSHOT-NAME>
212
* length.
213
*/
214
static struct inode *parse_longname(const struct inode *parent,
215
const char *name, int *name_len)
216
{
217
struct ceph_client *cl = ceph_inode_to_client(parent);
218
struct inode *dir = NULL;
219
struct ceph_vino vino = { .snap = CEPH_NOSNAP };
220
char *name_end, *inode_number;
221
int ret = -EIO;
222
/* NUL-terminate */
223
char *str __free(kfree) = kmemdup_nul(name, *name_len, GFP_KERNEL);
224
if (!str)
225
return ERR_PTR(-ENOMEM);
226
/* Skip initial '_' */
227
str++;
228
name_end = strrchr(str, '_');
229
if (!name_end) {
230
doutc(cl, "failed to parse long snapshot name: %s\n", str);
231
return ERR_PTR(-EIO);
232
}
233
*name_len = (name_end - str);
234
if (*name_len <= 0) {
235
pr_err_client(cl, "failed to parse long snapshot name\n");
236
return ERR_PTR(-EIO);
237
}
238
239
/* Get the inode number */
240
inode_number = name_end + 1;
241
ret = kstrtou64(inode_number, 10, &vino.ino);
242
if (ret) {
243
doutc(cl, "failed to parse inode number: %s\n", str);
244
return ERR_PTR(ret);
245
}
246
247
/* And finally the inode */
248
dir = ceph_find_inode(parent->i_sb, vino);
249
if (!dir) {
250
/* This can happen if we're not mounting cephfs on the root */
251
dir = ceph_get_inode(parent->i_sb, vino, NULL);
252
if (IS_ERR(dir))
253
doutc(cl, "can't find inode %s (%s)\n", inode_number, name);
254
}
255
return dir;
256
}
257
258
int ceph_encode_encrypted_dname(struct inode *parent, char *buf, int elen)
259
{
260
struct ceph_client *cl = ceph_inode_to_client(parent);
261
struct inode *dir = parent;
262
char *p = buf;
263
u32 len;
264
int name_len = elen;
265
int ret;
266
u8 *cryptbuf = NULL;
267
268
/* Handle the special case of snapshot names that start with '_' */
269
if (ceph_snap(dir) == CEPH_SNAPDIR && *p == '_') {
270
dir = parse_longname(parent, p, &name_len);
271
if (IS_ERR(dir))
272
return PTR_ERR(dir);
273
p++; /* skip initial '_' */
274
}
275
276
if (!fscrypt_has_encryption_key(dir))
277
goto out;
278
279
/*
280
* Convert cleartext d_name to ciphertext. If result is longer than
281
* CEPH_NOHASH_NAME_MAX, sha256 the remaining bytes
282
*
283
* See: fscrypt_setup_filename
284
*/
285
if (!fscrypt_fname_encrypted_size(dir, name_len, NAME_MAX, &len)) {
286
elen = -ENAMETOOLONG;
287
goto out;
288
}
289
290
/* Allocate a buffer appropriate to hold the result */
291
cryptbuf = kmalloc(len > CEPH_NOHASH_NAME_MAX ? NAME_MAX : len,
292
GFP_KERNEL);
293
if (!cryptbuf) {
294
elen = -ENOMEM;
295
goto out;
296
}
297
298
ret = fscrypt_fname_encrypt(dir,
299
&(struct qstr)QSTR_INIT(p, name_len),
300
cryptbuf, len);
301
if (ret) {
302
elen = ret;
303
goto out;
304
}
305
306
/* hash the end if the name is long enough */
307
if (len > CEPH_NOHASH_NAME_MAX) {
308
u8 hash[SHA256_DIGEST_SIZE];
309
u8 *extra = cryptbuf + CEPH_NOHASH_NAME_MAX;
310
311
/*
312
* hash the extra bytes and overwrite crypttext beyond that
313
* point with it
314
*/
315
sha256(extra, len - CEPH_NOHASH_NAME_MAX, hash);
316
memcpy(extra, hash, SHA256_DIGEST_SIZE);
317
len = CEPH_NOHASH_NAME_MAX + SHA256_DIGEST_SIZE;
318
}
319
320
/* base64 encode the encrypted name */
321
elen = ceph_base64_encode(cryptbuf, len, p);
322
doutc(cl, "base64-encoded ciphertext name = %.*s\n", elen, p);
323
324
/* To understand the 240 limit, see CEPH_NOHASH_NAME_MAX comments */
325
WARN_ON(elen > 240);
326
if (dir != parent) // leading _ is already there; append _<inum>
327
elen += 1 + sprintf(p + elen, "_%ld", dir->i_ino);
328
329
out:
330
kfree(cryptbuf);
331
if (dir != parent) {
332
if ((dir->i_state & I_NEW))
333
discard_new_inode(dir);
334
else
335
iput(dir);
336
}
337
return elen;
338
}
339
340
/**
341
* ceph_fname_to_usr - convert a filename for userland presentation
342
* @fname: ceph_fname to be converted
343
* @tname: temporary name buffer to use for conversion (may be NULL)
344
* @oname: where converted name should be placed
345
* @is_nokey: set to true if key wasn't available during conversion (may be NULL)
346
*
347
* Given a filename (usually from the MDS), format it for presentation to
348
* userland. If @parent is not encrypted, just pass it back as-is.
349
*
350
* Otherwise, base64 decode the string, and then ask fscrypt to format it
351
* for userland presentation.
352
*
353
* Returns 0 on success or negative error code on error.
354
*/
355
int ceph_fname_to_usr(const struct ceph_fname *fname, struct fscrypt_str *tname,
356
struct fscrypt_str *oname, bool *is_nokey)
357
{
358
struct inode *dir = fname->dir;
359
struct fscrypt_str _tname = FSTR_INIT(NULL, 0);
360
struct fscrypt_str iname;
361
char *name = fname->name;
362
int name_len = fname->name_len;
363
int ret;
364
365
/* Sanity check that the resulting name will fit in the buffer */
366
if (fname->name_len > NAME_MAX || fname->ctext_len > NAME_MAX)
367
return -EIO;
368
369
/* Handle the special case of snapshot names that start with '_' */
370
if ((ceph_snap(dir) == CEPH_SNAPDIR) && (name_len > 0) &&
371
(name[0] == '_')) {
372
dir = parse_longname(dir, name, &name_len);
373
if (IS_ERR(dir))
374
return PTR_ERR(dir);
375
name++; /* skip initial '_' */
376
}
377
378
if (!IS_ENCRYPTED(dir)) {
379
oname->name = fname->name;
380
oname->len = fname->name_len;
381
ret = 0;
382
goto out_inode;
383
}
384
385
ret = ceph_fscrypt_prepare_readdir(dir);
386
if (ret)
387
goto out_inode;
388
389
/*
390
* Use the raw dentry name as sent by the MDS instead of
391
* generating a nokey name via fscrypt.
392
*/
393
if (!fscrypt_has_encryption_key(dir)) {
394
if (fname->no_copy)
395
oname->name = fname->name;
396
else
397
memcpy(oname->name, fname->name, fname->name_len);
398
oname->len = fname->name_len;
399
if (is_nokey)
400
*is_nokey = true;
401
ret = 0;
402
goto out_inode;
403
}
404
405
if (fname->ctext_len == 0) {
406
int declen;
407
408
if (!tname) {
409
ret = fscrypt_fname_alloc_buffer(NAME_MAX, &_tname);
410
if (ret)
411
goto out_inode;
412
tname = &_tname;
413
}
414
415
declen = ceph_base64_decode(name, name_len, tname->name);
416
if (declen <= 0) {
417
ret = -EIO;
418
goto out;
419
}
420
iname.name = tname->name;
421
iname.len = declen;
422
} else {
423
iname.name = fname->ctext;
424
iname.len = fname->ctext_len;
425
}
426
427
ret = fscrypt_fname_disk_to_usr(dir, 0, 0, &iname, oname);
428
if (!ret && (dir != fname->dir)) {
429
char tmp_buf[CEPH_BASE64_CHARS(NAME_MAX)];
430
431
name_len = snprintf(tmp_buf, sizeof(tmp_buf), "_%.*s_%ld",
432
oname->len, oname->name, dir->i_ino);
433
memcpy(oname->name, tmp_buf, name_len);
434
oname->len = name_len;
435
}
436
437
out:
438
fscrypt_fname_free_buffer(&_tname);
439
out_inode:
440
if (dir != fname->dir) {
441
if ((dir->i_state & I_NEW))
442
discard_new_inode(dir);
443
else
444
iput(dir);
445
}
446
return ret;
447
}
448
449
/**
450
* ceph_fscrypt_prepare_readdir - simple __fscrypt_prepare_readdir() wrapper
451
* @dir: directory inode for readdir prep
452
*
453
* Simple wrapper around __fscrypt_prepare_readdir() that will mark directory as
454
* non-complete if this call results in having the directory unlocked.
455
*
456
* Returns:
457
* 1 - if directory was locked and key is now loaded (i.e. dir is unlocked)
458
* 0 - if directory is still locked
459
* < 0 - if __fscrypt_prepare_readdir() fails
460
*/
461
int ceph_fscrypt_prepare_readdir(struct inode *dir)
462
{
463
bool had_key = fscrypt_has_encryption_key(dir);
464
int err;
465
466
if (!IS_ENCRYPTED(dir))
467
return 0;
468
469
err = __fscrypt_prepare_readdir(dir);
470
if (err)
471
return err;
472
if (!had_key && fscrypt_has_encryption_key(dir)) {
473
/* directory just got unlocked, mark it as not complete */
474
ceph_dir_clear_complete(dir);
475
return 1;
476
}
477
return 0;
478
}
479
480
int ceph_fscrypt_decrypt_block_inplace(const struct inode *inode,
481
struct page *page, unsigned int len,
482
unsigned int offs, u64 lblk_num)
483
{
484
struct ceph_client *cl = ceph_inode_to_client(inode);
485
486
doutc(cl, "%p %llx.%llx len %u offs %u blk %llu\n", inode,
487
ceph_vinop(inode), len, offs, lblk_num);
488
return fscrypt_decrypt_block_inplace(inode, page, len, offs, lblk_num);
489
}
490
491
int ceph_fscrypt_encrypt_block_inplace(const struct inode *inode,
492
struct page *page, unsigned int len,
493
unsigned int offs, u64 lblk_num)
494
{
495
struct ceph_client *cl = ceph_inode_to_client(inode);
496
497
doutc(cl, "%p %llx.%llx len %u offs %u blk %llu\n", inode,
498
ceph_vinop(inode), len, offs, lblk_num);
499
return fscrypt_encrypt_block_inplace(inode, page, len, offs, lblk_num);
500
}
501
502
/**
503
* ceph_fscrypt_decrypt_pages - decrypt an array of pages
504
* @inode: pointer to inode associated with these pages
505
* @page: pointer to page array
506
* @off: offset into the file that the read data starts
507
* @len: max length to decrypt
508
*
509
* Decrypt an array of fscrypt'ed pages and return the amount of
510
* data decrypted. Any data in the page prior to the start of the
511
* first complete block in the read is ignored. Any incomplete
512
* crypto blocks at the end of the array are ignored (and should
513
* probably be zeroed by the caller).
514
*
515
* Returns the length of the decrypted data or a negative errno.
516
*/
517
int ceph_fscrypt_decrypt_pages(struct inode *inode, struct page **page,
518
u64 off, int len)
519
{
520
int i, num_blocks;
521
u64 baseblk = off >> CEPH_FSCRYPT_BLOCK_SHIFT;
522
int ret = 0;
523
524
/*
525
* We can't deal with partial blocks on an encrypted file, so mask off
526
* the last bit.
527
*/
528
num_blocks = ceph_fscrypt_blocks(off, len & CEPH_FSCRYPT_BLOCK_MASK);
529
530
/* Decrypt each block */
531
for (i = 0; i < num_blocks; ++i) {
532
int blkoff = i << CEPH_FSCRYPT_BLOCK_SHIFT;
533
int pgidx = blkoff >> PAGE_SHIFT;
534
unsigned int pgoffs = offset_in_page(blkoff);
535
int fret;
536
537
fret = ceph_fscrypt_decrypt_block_inplace(inode, page[pgidx],
538
CEPH_FSCRYPT_BLOCK_SIZE, pgoffs,
539
baseblk + i);
540
if (fret < 0) {
541
if (ret == 0)
542
ret = fret;
543
break;
544
}
545
ret += CEPH_FSCRYPT_BLOCK_SIZE;
546
}
547
return ret;
548
}
549
550
/**
551
* ceph_fscrypt_decrypt_extents: decrypt received extents in given buffer
552
* @inode: inode associated with pages being decrypted
553
* @page: pointer to page array
554
* @off: offset into the file that the data in page[0] starts
555
* @map: pointer to extent array
556
* @ext_cnt: length of extent array
557
*
558
* Given an extent map and a page array, decrypt the received data in-place,
559
* skipping holes. Returns the offset into buffer of end of last decrypted
560
* block.
561
*/
562
int ceph_fscrypt_decrypt_extents(struct inode *inode, struct page **page,
563
u64 off, struct ceph_sparse_extent *map,
564
u32 ext_cnt)
565
{
566
struct ceph_client *cl = ceph_inode_to_client(inode);
567
int i, ret = 0;
568
struct ceph_inode_info *ci = ceph_inode(inode);
569
u64 objno, objoff;
570
u32 xlen;
571
572
/* Nothing to do for empty array */
573
if (ext_cnt == 0) {
574
doutc(cl, "%p %llx.%llx empty array, ret 0\n", inode,
575
ceph_vinop(inode));
576
return 0;
577
}
578
579
ceph_calc_file_object_mapping(&ci->i_layout, off, map[0].len,
580
&objno, &objoff, &xlen);
581
582
for (i = 0; i < ext_cnt; ++i) {
583
struct ceph_sparse_extent *ext = &map[i];
584
int pgsoff = ext->off - objoff;
585
int pgidx = pgsoff >> PAGE_SHIFT;
586
int fret;
587
588
if ((ext->off | ext->len) & ~CEPH_FSCRYPT_BLOCK_MASK) {
589
pr_warn_client(cl,
590
"%p %llx.%llx bad encrypted sparse extent "
591
"idx %d off %llx len %llx\n",
592
inode, ceph_vinop(inode), i, ext->off,
593
ext->len);
594
return -EIO;
595
}
596
fret = ceph_fscrypt_decrypt_pages(inode, &page[pgidx],
597
off + pgsoff, ext->len);
598
doutc(cl, "%p %llx.%llx [%d] 0x%llx~0x%llx fret %d\n", inode,
599
ceph_vinop(inode), i, ext->off, ext->len, fret);
600
if (fret < 0) {
601
if (ret == 0)
602
ret = fret;
603
break;
604
}
605
ret = pgsoff + fret;
606
}
607
doutc(cl, "ret %d\n", ret);
608
return ret;
609
}
610
611
/**
612
* ceph_fscrypt_encrypt_pages - encrypt an array of pages
613
* @inode: pointer to inode associated with these pages
614
* @page: pointer to page array
615
* @off: offset into the file that the data starts
616
* @len: max length to encrypt
617
*
618
* Encrypt an array of cleartext pages and return the amount of
619
* data encrypted. Any data in the page prior to the start of the
620
* first complete block in the read is ignored. Any incomplete
621
* crypto blocks at the end of the array are ignored.
622
*
623
* Returns the length of the encrypted data or a negative errno.
624
*/
625
int ceph_fscrypt_encrypt_pages(struct inode *inode, struct page **page, u64 off,
626
int len)
627
{
628
int i, num_blocks;
629
u64 baseblk = off >> CEPH_FSCRYPT_BLOCK_SHIFT;
630
int ret = 0;
631
632
/*
633
* We can't deal with partial blocks on an encrypted file, so mask off
634
* the last bit.
635
*/
636
num_blocks = ceph_fscrypt_blocks(off, len & CEPH_FSCRYPT_BLOCK_MASK);
637
638
/* Encrypt each block */
639
for (i = 0; i < num_blocks; ++i) {
640
int blkoff = i << CEPH_FSCRYPT_BLOCK_SHIFT;
641
int pgidx = blkoff >> PAGE_SHIFT;
642
unsigned int pgoffs = offset_in_page(blkoff);
643
int fret;
644
645
fret = ceph_fscrypt_encrypt_block_inplace(inode, page[pgidx],
646
CEPH_FSCRYPT_BLOCK_SIZE, pgoffs,
647
baseblk + i);
648
if (fret < 0) {
649
if (ret == 0)
650
ret = fret;
651
break;
652
}
653
ret += CEPH_FSCRYPT_BLOCK_SIZE;
654
}
655
return ret;
656
}
657
658