forked from Minki/linux
A set of patches for a deadlock on "rbd map" error path and a fix
for invalid pointer dereference and uninitialized variable use on asynchronous create and unlink error paths. -----BEGIN PGP SIGNATURE----- iQFHBAABCAAxFiEEydHwtzie9C7TfviiSn/eOAIR84sFAl6YkKMTHGlkcnlvbW92 QGdtYWlsLmNvbQAKCRBKf944AhHzi9mfCACM7yEZA3rYEUzoUVO2MfaZOnbPVyFe 0tRZB2Fcu5nzJLibeTMX8e0OKb0KtEpPcJXw8EMIe/IRA4ahUUCHp7cCe+jIoPuX OB9JLOD0tgQJ1jt7hAd7SZFkN/iCJ/jpF/9kSD/8cLHUmPy2g2QzUtSeEtuRfsXD 8jOxW9heOIFVpysUC8HHsRO+b7yPL8AguG8WXNoDItL9uB1DmrgkxOhh/ijqPxVz F9Du3WlEPzdOTheU6pxtTAMdds4mq3ltBnUElCevR4qY0og4YaqDwnGf0pJlzSuN nVvAhSSOGbVdvkjzTaPo2BF5rEYXNm6Hln0HGHsUubnDlFZ200GbFEJk =b1jf -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
3fa84bf926
@ -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",
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user