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,
|
static void rbd_notify_op_lock(struct rbd_device *rbd_dev,
|
||||||
enum rbd_notify_op notify_op)
|
enum rbd_notify_op notify_op)
|
||||||
{
|
{
|
||||||
struct page **reply_pages;
|
__rbd_notify_op_lock(rbd_dev, notify_op, NULL, NULL);
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rbd_notify_acquired_lock(struct work_struct *work)
|
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);
|
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)
|
static void rbd_unregister_watch(struct rbd_device *rbd_dev)
|
||||||
{
|
{
|
||||||
cancel_tasks_sync(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)
|
static void rbd_dev_image_release(struct rbd_device *rbd_dev)
|
||||||
{
|
{
|
||||||
rbd_dev_unprobe(rbd_dev);
|
if (!rbd_is_ro(rbd_dev))
|
||||||
if (rbd_dev->opts)
|
|
||||||
rbd_unregister_watch(rbd_dev);
|
rbd_unregister_watch(rbd_dev);
|
||||||
|
|
||||||
|
rbd_dev_unprobe(rbd_dev);
|
||||||
rbd_dev->image_format = 0;
|
rbd_dev->image_format = 0;
|
||||||
kfree(rbd_dev->spec->image_id);
|
kfree(rbd_dev->spec->image_id);
|
||||||
rbd_dev->spec->image_id = NULL;
|
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
|
* device. If this image is the one being mapped (i.e., not a
|
||||||
* parent), initiate a watch on its header object before using that
|
* parent), initiate a watch on its header object before using that
|
||||||
* object to get detailed information about the rbd image.
|
* 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)
|
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);
|
ret = rbd_dev_header_info(rbd_dev);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
if (ret == -ENOENT && !need_watch)
|
if (ret == -ENOENT && !need_watch)
|
||||||
rbd_print_dne(rbd_dev, false);
|
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;
|
return 0;
|
||||||
|
|
||||||
err_out_probe:
|
err_out_probe:
|
||||||
rbd_dev_unprobe(rbd_dev);
|
if (!depth)
|
||||||
err_out_watch:
|
up_write(&rbd_dev->header_rwsem);
|
||||||
if (need_watch)
|
if (need_watch)
|
||||||
rbd_unregister_watch(rbd_dev);
|
rbd_unregister_watch(rbd_dev);
|
||||||
|
rbd_dev_unprobe(rbd_dev);
|
||||||
err_out_format:
|
err_out_format:
|
||||||
rbd_dev->image_format = 0;
|
rbd_dev->image_format = 0;
|
||||||
kfree(rbd_dev->spec->image_id);
|
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;
|
goto err_out_rbd_dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
down_write(&rbd_dev->header_rwsem);
|
|
||||||
rc = rbd_dev_image_probe(rbd_dev, 0);
|
rc = rbd_dev_image_probe(rbd_dev, 0);
|
||||||
if (rc < 0) {
|
if (rc < 0)
|
||||||
up_write(&rbd_dev->header_rwsem);
|
|
||||||
goto err_out_rbd_dev;
|
goto err_out_rbd_dev;
|
||||||
}
|
|
||||||
|
|
||||||
if (rbd_dev->opts->alloc_size > rbd_dev->layout.object_size) {
|
if (rbd_dev->opts->alloc_size > rbd_dev->layout.object_size) {
|
||||||
rbd_warn(rbd_dev, "alloc_size adjusted to %u",
|
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 op failed, mark everyone involved for errors */
|
||||||
if (result) {
|
if (result) {
|
||||||
int pathlen;
|
int pathlen = 0;
|
||||||
u64 base;
|
u64 base = 0;
|
||||||
char *path = ceph_mdsc_build_path(req->r_dentry, &pathlen,
|
char *path = ceph_mdsc_build_path(req->r_dentry, &pathlen,
|
||||||
&base, 0);
|
&base, 0);
|
||||||
|
|
||||||
|
|
|
@ -527,8 +527,8 @@ static void ceph_async_create_cb(struct ceph_mds_client *mdsc,
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
struct dentry *dentry = req->r_dentry;
|
struct dentry *dentry = req->r_dentry;
|
||||||
int pathlen;
|
int pathlen = 0;
|
||||||
u64 base;
|
u64 base = 0;
|
||||||
char *path = ceph_mdsc_build_path(req->r_dentry, &pathlen,
|
char *path = ceph_mdsc_build_path(req->r_dentry, &pathlen,
|
||||||
&base, 0);
|
&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)
|
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));
|
__putname(path - (PATH_MAX - 1 - len));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue