Skip to content

Commit 7e8c948

Browse files
committed
Merge tag 'ceph-for-6.4-rc6' of https://github.com/ceph/ceph-client
Pull ceph fixes from Ilya Dryomov: "A fix for a potential data corruption in differential backup and snapshot-based mirroring scenarios in RBD and a reference counting fixup to avoid use-after-free in CephFS, all marked for stable" * tag 'ceph-for-6.4-rc6' of https://github.com/ceph/ceph-client: ceph: fix use-after-free bug for inodes when flushing capsnaps rbd: get snapshot context after exclusive lock is ensured to be held rbd: move RBD_OBJ_FLAG_COPYUP_ENABLED flag setting
2 parents 0f506c7 + 409e873 commit 7e8c948

File tree

3 files changed

+53
-19
lines changed

3 files changed

+53
-19
lines changed

drivers/block/rbd.c

Lines changed: 44 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1334,14 +1334,30 @@ static bool rbd_obj_is_tail(struct rbd_obj_request *obj_req)
13341334
/*
13351335
* Must be called after rbd_obj_calc_img_extents().
13361336
*/
1337-
static bool rbd_obj_copyup_enabled(struct rbd_obj_request *obj_req)
1337+
static void rbd_obj_set_copyup_enabled(struct rbd_obj_request *obj_req)
13381338
{
1339-
if (!obj_req->num_img_extents ||
1340-
(rbd_obj_is_entire(obj_req) &&
1341-
!obj_req->img_request->snapc->num_snaps))
1342-
return false;
1339+
rbd_assert(obj_req->img_request->snapc);
13431340

1344-
return true;
1341+
if (obj_req->img_request->op_type == OBJ_OP_DISCARD) {
1342+
dout("%s %p objno %llu discard\n", __func__, obj_req,
1343+
obj_req->ex.oe_objno);
1344+
return;
1345+
}
1346+
1347+
if (!obj_req->num_img_extents) {
1348+
dout("%s %p objno %llu not overlapping\n", __func__, obj_req,
1349+
obj_req->ex.oe_objno);
1350+
return;
1351+
}
1352+
1353+
if (rbd_obj_is_entire(obj_req) &&
1354+
!obj_req->img_request->snapc->num_snaps) {
1355+
dout("%s %p objno %llu entire\n", __func__, obj_req,
1356+
obj_req->ex.oe_objno);
1357+
return;
1358+
}
1359+
1360+
obj_req->flags |= RBD_OBJ_FLAG_COPYUP_ENABLED;
13451361
}
13461362

13471363
static u64 rbd_obj_img_extents_bytes(struct rbd_obj_request *obj_req)
@@ -1442,6 +1458,7 @@ __rbd_obj_add_osd_request(struct rbd_obj_request *obj_req,
14421458
static struct ceph_osd_request *
14431459
rbd_obj_add_osd_request(struct rbd_obj_request *obj_req, int num_ops)
14441460
{
1461+
rbd_assert(obj_req->img_request->snapc);
14451462
return __rbd_obj_add_osd_request(obj_req, obj_req->img_request->snapc,
14461463
num_ops);
14471464
}
@@ -1578,15 +1595,18 @@ static void rbd_img_request_init(struct rbd_img_request *img_request,
15781595
mutex_init(&img_request->state_mutex);
15791596
}
15801597

1598+
/*
1599+
* Only snap_id is captured here, for reads. For writes, snapshot
1600+
* context is captured in rbd_img_object_requests() after exclusive
1601+
* lock is ensured to be held.
1602+
*/
15811603
static void rbd_img_capture_header(struct rbd_img_request *img_req)
15821604
{
15831605
struct rbd_device *rbd_dev = img_req->rbd_dev;
15841606

15851607
lockdep_assert_held(&rbd_dev->header_rwsem);
15861608

1587-
if (rbd_img_is_write(img_req))
1588-
img_req->snapc = ceph_get_snap_context(rbd_dev->header.snapc);
1589-
else
1609+
if (!rbd_img_is_write(img_req))
15901610
img_req->snap_id = rbd_dev->spec->snap_id;
15911611

15921612
if (rbd_dev_parent_get(rbd_dev))
@@ -2233,9 +2253,6 @@ static int rbd_obj_init_write(struct rbd_obj_request *obj_req)
22332253
if (ret)
22342254
return ret;
22352255

2236-
if (rbd_obj_copyup_enabled(obj_req))
2237-
obj_req->flags |= RBD_OBJ_FLAG_COPYUP_ENABLED;
2238-
22392256
obj_req->write_state = RBD_OBJ_WRITE_START;
22402257
return 0;
22412258
}
@@ -2341,8 +2358,6 @@ static int rbd_obj_init_zeroout(struct rbd_obj_request *obj_req)
23412358
if (ret)
23422359
return ret;
23432360

2344-
if (rbd_obj_copyup_enabled(obj_req))
2345-
obj_req->flags |= RBD_OBJ_FLAG_COPYUP_ENABLED;
23462361
if (!obj_req->num_img_extents) {
23472362
obj_req->flags |= RBD_OBJ_FLAG_NOOP_FOR_NONEXISTENT;
23482363
if (rbd_obj_is_entire(obj_req))
@@ -3286,6 +3301,7 @@ static bool rbd_obj_advance_write(struct rbd_obj_request *obj_req, int *result)
32863301
case RBD_OBJ_WRITE_START:
32873302
rbd_assert(!*result);
32883303

3304+
rbd_obj_set_copyup_enabled(obj_req);
32893305
if (rbd_obj_write_is_noop(obj_req))
32903306
return true;
32913307

@@ -3472,9 +3488,19 @@ static int rbd_img_exclusive_lock(struct rbd_img_request *img_req)
34723488

34733489
static void rbd_img_object_requests(struct rbd_img_request *img_req)
34743490
{
3491+
struct rbd_device *rbd_dev = img_req->rbd_dev;
34753492
struct rbd_obj_request *obj_req;
34763493

34773494
rbd_assert(!img_req->pending.result && !img_req->pending.num_pending);
3495+
rbd_assert(!need_exclusive_lock(img_req) ||
3496+
__rbd_is_lock_owner(rbd_dev));
3497+
3498+
if (rbd_img_is_write(img_req)) {
3499+
rbd_assert(!img_req->snapc);
3500+
down_read(&rbd_dev->header_rwsem);
3501+
img_req->snapc = ceph_get_snap_context(rbd_dev->header.snapc);
3502+
up_read(&rbd_dev->header_rwsem);
3503+
}
34783504

34793505
for_each_obj_request(img_req, obj_req) {
34803506
int result = 0;
@@ -3492,7 +3518,6 @@ static void rbd_img_object_requests(struct rbd_img_request *img_req)
34923518

34933519
static bool rbd_img_advance(struct rbd_img_request *img_req, int *result)
34943520
{
3495-
struct rbd_device *rbd_dev = img_req->rbd_dev;
34963521
int ret;
34973522

34983523
again:
@@ -3513,9 +3538,6 @@ static bool rbd_img_advance(struct rbd_img_request *img_req, int *result)
35133538
if (*result)
35143539
return true;
35153540

3516-
rbd_assert(!need_exclusive_lock(img_req) ||
3517-
__rbd_is_lock_owner(rbd_dev));
3518-
35193541
rbd_img_object_requests(img_req);
35203542
if (!img_req->pending.num_pending) {
35213543
*result = img_req->pending.result;
@@ -3977,6 +3999,10 @@ static int rbd_post_acquire_action(struct rbd_device *rbd_dev)
39773999
{
39784000
int ret;
39794001

4002+
ret = rbd_dev_refresh(rbd_dev);
4003+
if (ret)
4004+
return ret;
4005+
39804006
if (rbd_dev->header.features & RBD_FEATURE_OBJECT_MAP) {
39814007
ret = rbd_object_map_open(rbd_dev);
39824008
if (ret)

fs/ceph/caps.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1627,6 +1627,7 @@ void ceph_flush_snaps(struct ceph_inode_info *ci,
16271627
struct inode *inode = &ci->netfs.inode;
16281628
struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc;
16291629
struct ceph_mds_session *session = NULL;
1630+
bool need_put = false;
16301631
int mds;
16311632

16321633
dout("ceph_flush_snaps %p\n", inode);
@@ -1671,8 +1672,13 @@ void ceph_flush_snaps(struct ceph_inode_info *ci,
16711672
ceph_put_mds_session(session);
16721673
/* we flushed them all; remove this inode from the queue */
16731674
spin_lock(&mdsc->snap_flush_lock);
1675+
if (!list_empty(&ci->i_snap_flush_item))
1676+
need_put = true;
16741677
list_del_init(&ci->i_snap_flush_item);
16751678
spin_unlock(&mdsc->snap_flush_lock);
1679+
1680+
if (need_put)
1681+
iput(inode);
16761682
}
16771683

16781684
/*

fs/ceph/snap.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -693,8 +693,10 @@ int __ceph_finish_cap_snap(struct ceph_inode_info *ci,
693693
capsnap->size);
694694

695695
spin_lock(&mdsc->snap_flush_lock);
696-
if (list_empty(&ci->i_snap_flush_item))
696+
if (list_empty(&ci->i_snap_flush_item)) {
697+
ihold(inode);
697698
list_add_tail(&ci->i_snap_flush_item, &mdsc->snap_flush_list);
699+
}
698700
spin_unlock(&mdsc->snap_flush_lock);
699701
return 1; /* caller may want to ceph_flush_snaps */
700702
}

0 commit comments

Comments
 (0)