Skip to content

Commit 7684392

Browse files
committed
Merge tag 'ceph-for-6.13-rc4' of https://github.com/ceph/ceph-client
Pull ceph fixes from Ilya Dryomov: "A handful of important CephFS fixes from Max, Alex and myself: memory corruption due to a buffer overrun, potential infinite loop and several memory leaks on the error paths. All but one marked for stable" * tag 'ceph-for-6.13-rc4' of https://github.com/ceph/ceph-client: ceph: allocate sparse_ext map only for sparse reads ceph: fix memory leak in ceph_direct_read_write() ceph: improve error handling and short/overflow-read logic in __ceph_sync_read() ceph: validate snapdirname option length when mounting ceph: give up on paths longer than PATH_MAX ceph: fix memory leaks in __ceph_sync_read()
2 parents 4995512 + 18d44c5 commit 7684392

File tree

4 files changed

+46
-44
lines changed

4 files changed

+46
-44
lines changed

fs/ceph/file.c

Lines changed: 38 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1066,7 +1066,7 @@ ssize_t __ceph_sync_read(struct inode *inode, loff_t *ki_pos,
10661066
if (ceph_inode_is_shutdown(inode))
10671067
return -EIO;
10681068

1069-
if (!len)
1069+
if (!len || !i_size)
10701070
return 0;
10711071
/*
10721072
* flush any page cache pages in this range. this
@@ -1086,7 +1086,7 @@ ssize_t __ceph_sync_read(struct inode *inode, loff_t *ki_pos,
10861086
int num_pages;
10871087
size_t page_off;
10881088
bool more;
1089-
int idx;
1089+
int idx = 0;
10901090
size_t left;
10911091
struct ceph_osd_req_op *op;
10921092
u64 read_off = off;
@@ -1116,6 +1116,16 @@ ssize_t __ceph_sync_read(struct inode *inode, loff_t *ki_pos,
11161116
len = read_off + read_len - off;
11171117
more = len < iov_iter_count(to);
11181118

1119+
op = &req->r_ops[0];
1120+
if (sparse) {
1121+
extent_cnt = __ceph_sparse_read_ext_count(inode, read_len);
1122+
ret = ceph_alloc_sparse_ext_map(op, extent_cnt);
1123+
if (ret) {
1124+
ceph_osdc_put_request(req);
1125+
break;
1126+
}
1127+
}
1128+
11191129
num_pages = calc_pages_for(read_off, read_len);
11201130
page_off = offset_in_page(off);
11211131
pages = ceph_alloc_page_vector(num_pages, GFP_KERNEL);
@@ -1127,17 +1137,7 @@ ssize_t __ceph_sync_read(struct inode *inode, loff_t *ki_pos,
11271137

11281138
osd_req_op_extent_osd_data_pages(req, 0, pages, read_len,
11291139
offset_in_page(read_off),
1130-
false, false);
1131-
1132-
op = &req->r_ops[0];
1133-
if (sparse) {
1134-
extent_cnt = __ceph_sparse_read_ext_count(inode, read_len);
1135-
ret = ceph_alloc_sparse_ext_map(op, extent_cnt);
1136-
if (ret) {
1137-
ceph_osdc_put_request(req);
1138-
break;
1139-
}
1140-
}
1140+
false, true);
11411141

11421142
ceph_osdc_start_request(osdc, req);
11431143
ret = ceph_osdc_wait_request(osdc, req);
@@ -1160,7 +1160,14 @@ ssize_t __ceph_sync_read(struct inode *inode, loff_t *ki_pos,
11601160
else if (ret == -ENOENT)
11611161
ret = 0;
11621162

1163-
if (ret > 0 && IS_ENCRYPTED(inode)) {
1163+
if (ret < 0) {
1164+
ceph_osdc_put_request(req);
1165+
if (ret == -EBLOCKLISTED)
1166+
fsc->blocklisted = true;
1167+
break;
1168+
}
1169+
1170+
if (IS_ENCRYPTED(inode)) {
11641171
int fret;
11651172

11661173
fret = ceph_fscrypt_decrypt_extents(inode, pages,
@@ -1186,10 +1193,8 @@ ssize_t __ceph_sync_read(struct inode *inode, loff_t *ki_pos,
11861193
ret = min_t(ssize_t, fret, len);
11871194
}
11881195

1189-
ceph_osdc_put_request(req);
1190-
11911196
/* Short read but not EOF? Zero out the remainder. */
1192-
if (ret >= 0 && ret < len && (off + ret < i_size)) {
1197+
if (ret < len && (off + ret < i_size)) {
11931198
int zlen = min(len - ret, i_size - off - ret);
11941199
int zoff = page_off + ret;
11951200

@@ -1199,13 +1204,11 @@ ssize_t __ceph_sync_read(struct inode *inode, loff_t *ki_pos,
11991204
ret += zlen;
12001205
}
12011206

1202-
idx = 0;
1203-
if (ret <= 0)
1204-
left = 0;
1205-
else if (off + ret > i_size)
1206-
left = i_size - off;
1207+
if (off + ret > i_size)
1208+
left = (i_size > off) ? i_size - off : 0;
12071209
else
12081210
left = ret;
1211+
12091212
while (left > 0) {
12101213
size_t plen, copied;
12111214

@@ -1221,13 +1224,8 @@ ssize_t __ceph_sync_read(struct inode *inode, loff_t *ki_pos,
12211224
break;
12221225
}
12231226
}
1224-
ceph_release_page_vector(pages, num_pages);
12251227

1226-
if (ret < 0) {
1227-
if (ret == -EBLOCKLISTED)
1228-
fsc->blocklisted = true;
1229-
break;
1230-
}
1228+
ceph_osdc_put_request(req);
12311229

12321230
if (off >= i_size || !more)
12331231
break;
@@ -1553,6 +1551,16 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter,
15531551
break;
15541552
}
15551553

1554+
op = &req->r_ops[0];
1555+
if (!write && sparse) {
1556+
extent_cnt = __ceph_sparse_read_ext_count(inode, size);
1557+
ret = ceph_alloc_sparse_ext_map(op, extent_cnt);
1558+
if (ret) {
1559+
ceph_osdc_put_request(req);
1560+
break;
1561+
}
1562+
}
1563+
15561564
len = iter_get_bvecs_alloc(iter, size, &bvecs, &num_pages);
15571565
if (len < 0) {
15581566
ceph_osdc_put_request(req);
@@ -1562,6 +1570,8 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter,
15621570
if (len != size)
15631571
osd_req_op_extent_update(req, 0, len);
15641572

1573+
osd_req_op_extent_osd_data_bvecs(req, 0, bvecs, num_pages, len);
1574+
15651575
/*
15661576
* To simplify error handling, allow AIO when IO within i_size
15671577
* or IO can be satisfied by single OSD request.
@@ -1593,17 +1603,6 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter,
15931603
req->r_mtime = mtime;
15941604
}
15951605

1596-
osd_req_op_extent_osd_data_bvecs(req, 0, bvecs, num_pages, len);
1597-
op = &req->r_ops[0];
1598-
if (sparse) {
1599-
extent_cnt = __ceph_sparse_read_ext_count(inode, size);
1600-
ret = ceph_alloc_sparse_ext_map(op, extent_cnt);
1601-
if (ret) {
1602-
ceph_osdc_put_request(req);
1603-
break;
1604-
}
1605-
}
1606-
16071606
if (aio_req) {
16081607
aio_req->total_len += len;
16091608
aio_req->num_reqs++;

fs/ceph/mds_client.c

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2800,12 +2800,11 @@ char *ceph_mdsc_build_path(struct ceph_mds_client *mdsc, struct dentry *dentry,
28002800

28012801
if (pos < 0) {
28022802
/*
2803-
* A rename didn't occur, but somehow we didn't end up where
2804-
* we thought we would. Throw a warning and try again.
2803+
* The path is longer than PATH_MAX and this function
2804+
* cannot ever succeed. Creating paths that long is
2805+
* possible with Ceph, but Linux cannot use them.
28052806
*/
2806-
pr_warn_client(cl, "did not end path lookup where expected (pos = %d)\n",
2807-
pos);
2808-
goto retry;
2807+
return ERR_PTR(-ENAMETOOLONG);
28092808
}
28102809

28112810
*pbase = base;

fs/ceph/super.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,8 @@ static int ceph_parse_mount_param(struct fs_context *fc,
431431

432432
switch (token) {
433433
case Opt_snapdirname:
434+
if (strlen(param->string) > NAME_MAX)
435+
return invalfc(fc, "snapdirname too long");
434436
kfree(fsopt->snapdir_name);
435437
fsopt->snapdir_name = param->string;
436438
param->string = NULL;

net/ceph/osd_client.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1173,6 +1173,8 @@ EXPORT_SYMBOL(ceph_osdc_new_request);
11731173

11741174
int __ceph_alloc_sparse_ext_map(struct ceph_osd_req_op *op, int cnt)
11751175
{
1176+
WARN_ON(op->op != CEPH_OSD_OP_SPARSE_READ);
1177+
11761178
op->extent.sparse_ext_cnt = cnt;
11771179
op->extent.sparse_ext = kmalloc_array(cnt,
11781180
sizeof(*op->extent.sparse_ext),

0 commit comments

Comments
 (0)