Commit 3fa84bf9 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'ceph-for-5.7-rc2' of git://github.com/ceph/ceph-client

Pull ceph fixes from Ilya Dryomov:

 - a set of patches for a deadlock on "rbd map" error path

 - a fix for invalid pointer dereference and uninitialized variable use
   on asynchronous create and unlink error paths.

* tag 'ceph-for-5.7-rc2' of git://github.com/ceph/ceph-client:
  ceph: fix potential bad pointer deref in async dirops cb's
  rbd: don't mess with a page vector in rbd_notify_op_lock()
  rbd: don't test rbd_dev->opts in rbd_dev_image_release()
  rbd: call rbd_dev_unprobe() after unwatching and flushing notifies
  rbd: avoid a deadlock on header_rwsem when flushing notifies
parents 4ede1259 2a575f13
Loading
Loading
Loading
Loading
+19 −14
Original line number Diff line number Diff line
@@ -3754,11 +3754,7 @@ static int __rbd_notify_op_lock(struct rbd_device *rbd_dev,
static void rbd_notify_op_lock(struct rbd_device *rbd_dev,
			       enum rbd_notify_op notify_op)
{
	struct page **reply_pages;
	size_t reply_len;

	__rbd_notify_op_lock(rbd_dev, notify_op, &reply_pages, &reply_len);
	ceph_release_page_vector(reply_pages, calc_pages_for(0, reply_len));
	__rbd_notify_op_lock(rbd_dev, notify_op, NULL, NULL);
}

static void rbd_notify_acquired_lock(struct work_struct *work)
@@ -4527,6 +4523,10 @@ static void cancel_tasks_sync(struct rbd_device *rbd_dev)
	cancel_work_sync(&rbd_dev->unlock_work);
}

/*
 * header_rwsem must not be held to avoid a deadlock with
 * rbd_dev_refresh() when flushing notifies.
 */
static void rbd_unregister_watch(struct rbd_device *rbd_dev)
{
	cancel_tasks_sync(rbd_dev);
@@ -6894,9 +6894,10 @@ static void rbd_print_dne(struct rbd_device *rbd_dev, bool is_snap)

static void rbd_dev_image_release(struct rbd_device *rbd_dev)
{
	rbd_dev_unprobe(rbd_dev);
	if (rbd_dev->opts)
	if (!rbd_is_ro(rbd_dev))
		rbd_unregister_watch(rbd_dev);

	rbd_dev_unprobe(rbd_dev);
	rbd_dev->image_format = 0;
	kfree(rbd_dev->spec->image_id);
	rbd_dev->spec->image_id = NULL;
@@ -6907,6 +6908,9 @@ static void rbd_dev_image_release(struct rbd_device *rbd_dev)
 * device.  If this image is the one being mapped (i.e., not a
 * parent), initiate a watch on its header object before using that
 * object to get detailed information about the rbd image.
 *
 * On success, returns with header_rwsem held for write if called
 * with @depth == 0.
 */
static int rbd_dev_image_probe(struct rbd_device *rbd_dev, int depth)
{
@@ -6936,11 +6940,14 @@ static int rbd_dev_image_probe(struct rbd_device *rbd_dev, int depth)
		}
	}

	if (!depth)
		down_write(&rbd_dev->header_rwsem);

	ret = rbd_dev_header_info(rbd_dev);
	if (ret) {
		if (ret == -ENOENT && !need_watch)
			rbd_print_dne(rbd_dev, false);
		goto err_out_watch;
		goto err_out_probe;
	}

	/*
@@ -6985,10 +6992,11 @@ static int rbd_dev_image_probe(struct rbd_device *rbd_dev, int depth)
	return 0;

err_out_probe:
	rbd_dev_unprobe(rbd_dev);
err_out_watch:
	if (!depth)
		up_write(&rbd_dev->header_rwsem);
	if (need_watch)
		rbd_unregister_watch(rbd_dev);
	rbd_dev_unprobe(rbd_dev);
err_out_format:
	rbd_dev->image_format = 0;
	kfree(rbd_dev->spec->image_id);
@@ -7050,12 +7058,9 @@ static ssize_t do_rbd_add(struct bus_type *bus,
		goto err_out_rbd_dev;
	}

	down_write(&rbd_dev->header_rwsem);
	rc = rbd_dev_image_probe(rbd_dev, 0);
	if (rc < 0) {
		up_write(&rbd_dev->header_rwsem);
	if (rc < 0)
		goto err_out_rbd_dev;
	}

	if (rbd_dev->opts->alloc_size > rbd_dev->layout.object_size) {
		rbd_warn(rbd_dev, "alloc_size adjusted to %u",
+2 −2
Original line number Diff line number Diff line
@@ -1051,8 +1051,8 @@ static void ceph_async_unlink_cb(struct ceph_mds_client *mdsc,

	/* If op failed, mark everyone involved for errors */
	if (result) {
		int pathlen;
		u64 base;
		int pathlen = 0;
		u64 base = 0;
		char *path = ceph_mdsc_build_path(req->r_dentry, &pathlen,
						  &base, 0);

+2 −2
Original line number Diff line number Diff line
@@ -527,8 +527,8 @@ static void ceph_async_create_cb(struct ceph_mds_client *mdsc,

	if (result) {
		struct dentry *dentry = req->r_dentry;
		int pathlen;
		u64 base;
		int pathlen = 0;
		u64 base = 0;
		char *path = ceph_mdsc_build_path(req->r_dentry, &pathlen,
						  &base, 0);

+1 −1
Original line number Diff line number Diff line
@@ -521,7 +521,7 @@ extern void ceph_mdsc_pre_umount(struct ceph_mds_client *mdsc);

static inline void ceph_mdsc_free_path(char *path, int len)
{
	if (path)
	if (!IS_ERR_OR_NULL(path))
		__putname(path - (PATH_MAX - 1 - len));
}