Skip to content

Commit d552077

Browse files
jtlaytonidryomov
authored andcommitted
ceph: add encryption support to writepage and writepages
Allow writepage to issue encrypted writes. Extend out the requested size and offset to cover complete blocks, and then encrypt and write them to the OSDs. Add the appropriate machinery to write back dirty data with encryption. Signed-off-by: Jeff Layton <[email protected]> Reviewed-by: Xiubo Li <[email protected]> Reviewed-and-tested-by: Luís Henriques <[email protected]> Reviewed-by: Milind Changire <[email protected]> Signed-off-by: Ilya Dryomov <[email protected]>
1 parent 33a5f17 commit d552077

File tree

2 files changed

+98
-21
lines changed

2 files changed

+98
-21
lines changed

fs/ceph/addr.c

Lines changed: 81 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -565,10 +565,12 @@ static u64 get_writepages_data_length(struct inode *inode,
565565
struct page *page, u64 start)
566566
{
567567
struct ceph_inode_info *ci = ceph_inode(inode);
568-
struct ceph_snap_context *snapc = page_snap_context(page);
568+
struct ceph_snap_context *snapc;
569569
struct ceph_cap_snap *capsnap = NULL;
570570
u64 end = i_size_read(inode);
571+
u64 ret;
571572

573+
snapc = page_snap_context(ceph_fscrypt_pagecache_page(page));
572574
if (snapc != ci->i_head_snapc) {
573575
bool found = false;
574576
spin_lock(&ci->i_ceph_lock);
@@ -583,9 +585,12 @@ static u64 get_writepages_data_length(struct inode *inode,
583585
spin_unlock(&ci->i_ceph_lock);
584586
WARN_ON(!found);
585587
}
586-
if (end > page_offset(page) + thp_size(page))
587-
end = page_offset(page) + thp_size(page);
588-
return end > start ? end - start : 0;
588+
if (end > ceph_fscrypt_page_offset(page) + thp_size(page))
589+
end = ceph_fscrypt_page_offset(page) + thp_size(page);
590+
ret = end > start ? end - start : 0;
591+
if (ret && fscrypt_is_bounce_page(page))
592+
ret = round_up(ret, CEPH_FSCRYPT_BLOCK_SIZE);
593+
return ret;
589594
}
590595

591596
/*
@@ -604,10 +609,12 @@ static int writepage_nounlock(struct page *page, struct writeback_control *wbc)
604609
loff_t page_off = page_offset(page);
605610
int err;
606611
loff_t len = thp_size(page);
612+
loff_t wlen;
607613
struct ceph_writeback_ctl ceph_wbc;
608614
struct ceph_osd_client *osdc = &fsc->client->osdc;
609615
struct ceph_osd_request *req;
610616
bool caching = ceph_is_cache_enabled(inode);
617+
struct page *bounce_page = NULL;
611618

612619
dout("writepage %p idx %lu\n", page, page->index);
613620

@@ -643,39 +650,59 @@ static int writepage_nounlock(struct page *page, struct writeback_control *wbc)
643650
if (ceph_wbc.i_size < page_off + len)
644651
len = ceph_wbc.i_size - page_off;
645652

653+
wlen = IS_ENCRYPTED(inode) ? round_up(len, CEPH_FSCRYPT_BLOCK_SIZE) : len;
646654
dout("writepage %p page %p index %lu on %llu~%llu snapc %p seq %lld\n",
647-
inode, page, page->index, page_off, len, snapc, snapc->seq);
655+
inode, page, page->index, page_off, wlen, snapc, snapc->seq);
648656

649657
if (atomic_long_inc_return(&fsc->writeback_count) >
650658
CONGESTION_ON_THRESH(fsc->mount_options->congestion_kb))
651659
fsc->write_congested = true;
652660

653-
req = ceph_osdc_new_request(osdc, &ci->i_layout, ceph_vino(inode), page_off, &len, 0, 1,
654-
CEPH_OSD_OP_WRITE, CEPH_OSD_FLAG_WRITE, snapc,
655-
ceph_wbc.truncate_seq, ceph_wbc.truncate_size,
656-
true);
661+
req = ceph_osdc_new_request(osdc, &ci->i_layout, ceph_vino(inode),
662+
page_off, &wlen, 0, 1, CEPH_OSD_OP_WRITE,
663+
CEPH_OSD_FLAG_WRITE, snapc,
664+
ceph_wbc.truncate_seq,
665+
ceph_wbc.truncate_size, true);
657666
if (IS_ERR(req)) {
658667
redirty_page_for_writepage(wbc, page);
659668
return PTR_ERR(req);
660669
}
661670

671+
if (wlen < len)
672+
len = wlen;
673+
662674
set_page_writeback(page);
663675
if (caching)
664676
ceph_set_page_fscache(page);
665677
ceph_fscache_write_to_cache(inode, page_off, len, caching);
666678

679+
if (IS_ENCRYPTED(inode)) {
680+
bounce_page = fscrypt_encrypt_pagecache_blocks(page,
681+
CEPH_FSCRYPT_BLOCK_SIZE, 0,
682+
GFP_NOFS);
683+
if (IS_ERR(bounce_page)) {
684+
redirty_page_for_writepage(wbc, page);
685+
end_page_writeback(page);
686+
ceph_osdc_put_request(req);
687+
return PTR_ERR(bounce_page);
688+
}
689+
}
690+
667691
/* it may be a short write due to an object boundary */
668692
WARN_ON_ONCE(len > thp_size(page));
669-
osd_req_op_extent_osd_data_pages(req, 0, &page, len, 0, false, false);
670-
dout("writepage %llu~%llu (%llu bytes)\n", page_off, len, len);
693+
osd_req_op_extent_osd_data_pages(req, 0,
694+
bounce_page ? &bounce_page : &page, wlen, 0,
695+
false, false);
696+
dout("writepage %llu~%llu (%llu bytes, %sencrypted)\n",
697+
page_off, len, wlen, IS_ENCRYPTED(inode) ? "" : "not ");
671698

672699
req->r_mtime = inode->i_mtime;
673700
ceph_osdc_start_request(osdc, req);
674701
err = ceph_osdc_wait_request(osdc, req);
675702

676703
ceph_update_write_metrics(&fsc->mdsc->metric, req->r_start_latency,
677704
req->r_end_latency, len, err);
678-
705+
fscrypt_free_bounce_page(bounce_page);
679706
ceph_osdc_put_request(req);
680707
if (err == 0)
681708
err = len;
@@ -794,6 +821,11 @@ static void writepages_finish(struct ceph_osd_request *req)
794821
total_pages += num_pages;
795822
for (j = 0; j < num_pages; j++) {
796823
page = osd_data->pages[j];
824+
if (fscrypt_is_bounce_page(page)) {
825+
page = fscrypt_pagecache_page(page);
826+
fscrypt_free_bounce_page(osd_data->pages[j]);
827+
osd_data->pages[j] = page;
828+
}
797829
BUG_ON(!page);
798830
WARN_ON(!PageUptodate(page));
799831

@@ -1064,9 +1096,28 @@ static int ceph_writepages_start(struct address_space *mapping,
10641096
fsc->mount_options->congestion_kb))
10651097
fsc->write_congested = true;
10661098

1067-
pages[locked_pages++] = page;
1068-
fbatch.folios[i] = NULL;
1099+
if (IS_ENCRYPTED(inode)) {
1100+
pages[locked_pages] =
1101+
fscrypt_encrypt_pagecache_blocks(page,
1102+
PAGE_SIZE, 0,
1103+
locked_pages ? GFP_NOWAIT : GFP_NOFS);
1104+
if (IS_ERR(pages[locked_pages])) {
1105+
if (PTR_ERR(pages[locked_pages]) == -EINVAL)
1106+
pr_err("%s: inode->i_blkbits=%hhu\n",
1107+
__func__, inode->i_blkbits);
1108+
/* better not fail on first page! */
1109+
BUG_ON(locked_pages == 0);
1110+
pages[locked_pages] = NULL;
1111+
redirty_page_for_writepage(wbc, page);
1112+
unlock_page(page);
1113+
break;
1114+
}
1115+
++locked_pages;
1116+
} else {
1117+
pages[locked_pages++] = page;
1118+
}
10691119

1120+
fbatch.folios[i] = NULL;
10701121
len += thp_size(page);
10711122
}
10721123

@@ -1094,7 +1145,7 @@ static int ceph_writepages_start(struct address_space *mapping,
10941145
}
10951146

10961147
new_request:
1097-
offset = page_offset(pages[0]);
1148+
offset = ceph_fscrypt_page_offset(pages[0]);
10981149
len = wsize;
10991150

11001151
req = ceph_osdc_new_request(&fsc->client->osdc,
@@ -1115,8 +1166,8 @@ static int ceph_writepages_start(struct address_space *mapping,
11151166
ceph_wbc.truncate_size, true);
11161167
BUG_ON(IS_ERR(req));
11171168
}
1118-
BUG_ON(len < page_offset(pages[locked_pages - 1]) +
1119-
thp_size(page) - offset);
1169+
BUG_ON(len < ceph_fscrypt_page_offset(pages[locked_pages - 1]) +
1170+
thp_size(pages[locked_pages - 1]) - offset);
11201171

11211172
req->r_callback = writepages_finish;
11221173
req->r_inode = inode;
@@ -1126,7 +1177,9 @@ static int ceph_writepages_start(struct address_space *mapping,
11261177
data_pages = pages;
11271178
op_idx = 0;
11281179
for (i = 0; i < locked_pages; i++) {
1129-
u64 cur_offset = page_offset(pages[i]);
1180+
struct page *page = ceph_fscrypt_pagecache_page(pages[i]);
1181+
1182+
u64 cur_offset = page_offset(page);
11301183
/*
11311184
* Discontinuity in page range? Ceph can handle that by just passing
11321185
* multiple extents in the write op.
@@ -1155,9 +1208,9 @@ static int ceph_writepages_start(struct address_space *mapping,
11551208
op_idx++;
11561209
}
11571210

1158-
set_page_writeback(pages[i]);
1211+
set_page_writeback(page);
11591212
if (caching)
1160-
ceph_set_page_fscache(pages[i]);
1213+
ceph_set_page_fscache(page);
11611214
len += thp_size(page);
11621215
}
11631216
ceph_fscache_write_to_cache(inode, offset, len, caching);
@@ -1173,8 +1226,16 @@ static int ceph_writepages_start(struct address_space *mapping,
11731226
offset);
11741227
len = max(len, min_len);
11751228
}
1229+
if (IS_ENCRYPTED(inode))
1230+
len = round_up(len, CEPH_FSCRYPT_BLOCK_SIZE);
1231+
11761232
dout("writepages got pages at %llu~%llu\n", offset, len);
11771233

1234+
if (IS_ENCRYPTED(inode) &&
1235+
((offset | len) & ~CEPH_FSCRYPT_BLOCK_MASK))
1236+
pr_warn("%s: bad encrypted write offset=%lld len=%llu\n",
1237+
__func__, offset, len);
1238+
11781239
osd_req_op_extent_osd_data_pages(req, op_idx, data_pages, len,
11791240
0, from_pool, false);
11801241
osd_req_op_extent_update(req, op_idx, len);

fs/ceph/crypto.h

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,12 @@ int ceph_fscrypt_decrypt_extents(struct inode *inode, struct page **page,
164164
u32 ext_cnt);
165165
int ceph_fscrypt_encrypt_pages(struct inode *inode, struct page **page, u64 off,
166166
int len, gfp_t gfp);
167+
168+
static inline struct page *ceph_fscrypt_pagecache_page(struct page *page)
169+
{
170+
return fscrypt_is_bounce_page(page) ? fscrypt_pagecache_page(page) : page;
171+
}
172+
167173
#else /* CONFIG_FS_ENCRYPTION */
168174

169175
static inline void ceph_fscrypt_set_ops(struct super_block *sb)
@@ -267,6 +273,16 @@ static inline int ceph_fscrypt_encrypt_pages(struct inode *inode,
267273
{
268274
return 0;
269275
}
276+
277+
static inline struct page *ceph_fscrypt_pagecache_page(struct page *page)
278+
{
279+
return page;
280+
}
270281
#endif /* CONFIG_FS_ENCRYPTION */
271282

272-
#endif
283+
static inline loff_t ceph_fscrypt_page_offset(struct page *page)
284+
{
285+
return page_offset(ceph_fscrypt_pagecache_page(page));
286+
}
287+
288+
#endif /* _CEPH_CRYPTO_H */

0 commit comments

Comments
 (0)