ceph: re-post of bug fixes
Subsystems (3)
cover ceph: re-post of bug fixes
I've pulled out most of the more important patches from the backlog I posted the other day and am reposting then here so they can hopefully get some needed attention.
I'm in the midst of rearranging the patches in the testing branch so reviewed patches are all before those that are not yet reviewed. As a result it may not be very clear what these patches are based on. However I think they all are pretty clear, and pretty simple, so I'm posting them now anyway in hopes I can get them reviewed.
None of these has been changed (other than rebasing) from when they were posted previously.
-Alex
[PATCH 1/9] rbd: do not allow remove of mounted-on image [PATCH 2/9] ceph: don't reference req after put
[PATCH 3/9] libceph: avoid using freed osd in __kick_osd_requests() [PATCH 4/9] rbd: get rid of RBD_MAX_SEG_NAME_LEN
[PATCH 5/9] libceph: init osd->o_node in create_osd() [PATCH 6/9] rbd: remove linger unconditionally
[PATCH 7/9] rbd: don't use ENOTSUPP
[PATCH 8/9] rbd: fix ceph_pg_poolid_by_name()
[PATCH 9/9] libceph: socket can close in any connection state
PATCH 1/9 rbd: do not allow remove of mounted-on image
There is no check in rbd_remove() to see if anybody holds open the image being removed. That's not cool.
Add a simple open count that goes up and down with opens and closes (releases) of the device, and don't allow an rbd image to be removed if the count is non-zero.
Protect the updates of the open count value with ctl_mutex to ensure the underlying rbd device doesn't get removed while concurrently being opened.
--- drivers/block/rbd.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
drivers/block/rbd.c +1 -0
@@ -235,6 +235,7 @@ struct rbd_device {/* sysfs related */ struct device dev; +unsigned long open_count; };static DEFINE_MUTEX (ctl_mutex);/* Serialize open/close/setup/teardown */
@@ -309,8 +310,11 @@ static int rbd_open(struct block_device *bdev,
fmode_t mode)
if ((mode & FMODE_WRITE) && rbd_dev->mapping.read_only)
return -EROFS;
+ mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
rbd_get_dev(rbd_dev); set_device_ro(bdev, rbd_dev->mapping.read_only);
+ rbd_dev->open_count++;
+ mutex_unlock(&ctl_mutex);
return 0;
}
@@ -319,7 +323,11 @@ static int rbd_release(struct gendisk *disk, fmode_t mode)
{
struct rbd_device *rbd_dev = disk->private_data;
+ mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
+ rbd_assert(rbd_dev->open_count > 0);
+ rbd_dev->open_count--;
rbd_put_dev(rbd_dev);
+ mutex_unlock(&ctl_mutex);
return 0;
}
@@ -3745,6 +3753,11 @@ static ssize_t rbd_remove(struct bus_type *bus,
goto done;
}
+ if (rbd_dev->open_count) {
+ ret = -EBUSY;
+ goto done;
+ }
+
rbd_remove_all_snaps(rbd_dev);
rbd_bus_del_dev(rbd_dev);
Signature · 1 line
1.7.9.5
Re: [PATCH 1/9] rbd: do not allow remove of mounted-on image
Quoted 75 lines · Alex Elder
There is no check in
rbd_remove()to see if anybody holds open the image being removed. That's not cool.Add a simple open count that goes up and down with opens and closes (releases) of the device, and don't allow an rbd image to be removed if the count is non-zero.
Protect the updates of the open count value with
ctl_mutexto ensure the underlying rbd device doesn't get removed while concurrently being opened.Signed-off-by Alex Elder <[email protected]>--- drivers/block/rbd.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)drivers/block/rbd.c +4
-0@@ -235,6 +235,7 @@ struct rbd_device {/* sysfs related */ struct device dev; +unsigned long open_count; };static DEFINE_MUTEX (ctl_mutex);/* Serialize open/close/setup/teardown */ @@ -309,8 +310,11 @@ static int rbd_open(struct block_device *bdev, fmode_t mode)if ((mode &FMODE_WRITE ) && rbd_dev->mapping.read_only)return -EROFS ; +mutex_lock_nested (&ctl_mutex,SINGLE_DEPTH_NESTING );rbd_get_dev (rbd_dev);set_device_ro (bdev, rbd_dev->mapping.read_only); + rbd_dev->open_count++; +mutex_unlock (&ctl_mutex);return 0 ;}
drivers/block/rbd.c +4
-0@@ -319,7 +323,11 @@ static int rbd_release(struct gendisk *disk, fmode_t mode) {struct rbd_device *rbd_dev = disk->private_data; +mutex_lock_nested (&ctl_mutex,SINGLE_DEPTH_NESTING ); +rbd_assert (rbd_dev->open_count >0 ); + rbd_dev->open_count--;rbd_put_dev (rbd_dev); +mutex_unlock (&ctl_mutex);return 0 ;}
drivers/block/rbd.c +5
-0@@ -3745,6 +3753,11 @@ static ssize_t rbd_remove(struct bus_type *bus, goto done; } +if (rbd_dev->open_count) { + ret = -EBUSY ; + goto done; + } +rbd_remove_all_snaps (rbd_dev);rbd_bus_del_dev (rbd_dev);Signature · 6 lines
1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe ceph-devel" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 2/9 ceph: don't reference req after put
In reply to Alex ElderIn __unregister_request(), there is a call to list_del_init() referencing a request that was the subject of a call to ceph_osdc_put_request() on the previous line. This is not safe, because the request structure could have been freed by the time we reach the list_del_init().
Fix this by reversing the order of these lines.
--- net/ceph/osd_client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/ceph/osd_client.c +0 -0
@@ -871,9 +871,9 @@ static void __unregister_request(struct
ceph_osd_client *osdc,
req->r_osd = NULL;
}
+ list_del_init(&req->r_req_lru_item);
ceph_osdc_put_request(req);
- list_del_init(&req->r_req_lru_item);
if (osdc->num_requests == 0) {
dout(" no requests, canceling timeout\n"); __cancel_osd_timeout(osdc);
Signature · 1 line
1.7.9.5
PATCH 3/9 libceph: avoid using freed osd in __kick_osd_requests()
In reply to Alex ElderIf an osd has no requests and no linger requests, __reset_osd() will just remove it with a call to __remove_osd(). That drops a reference to the osd, and therefore the osd may have been free by the time __reset_osd() returns. That function offers no indication this may have occurred, and as a result the osd will continue to be used even when it's no longer valid.
Change__reset_osd() so it returns an error (ENODEV) when it deletes the osd being reset. And change __kick_osd_requests() so it returns immediately (before referencing osd again) if __reset_osd() returns *any* error.
--- net/ceph/osd_client.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
net/ceph/osd_client.c +0 -0
@@ -581,7 +581,7 @@ static void __kick_osd_requests(struct
ceph_osd_client *osdc,
dout("__kick_osd_requests osd%d\n", osd->o_osd); err = __reset_osd(osdc, osd);
- if (err == -EAGAIN)
+ if (err)
return;
list_for_each_entry(req, &osd->o_requests, r_osd_item) {
@@ -745,6 +745,7 @@ static int __reset_osd(struct ceph_osd_client *osdc, struct ceph_osd *osd)
if (list_empty(&osd->o_requests) &&
list_empty(&osd->o_linger_requests)) {
__remove_osd(osdc, osd);
+ ret = -ENODEV;
} else if (memcmp(&osdc->osdmap->osd_addr[osd->o_osd],
&osd->o_con.peer_addr, sizeof(osd->o_con.peer_addr)) == 0 &&
Signature · 1 line
1.7.9.5
Re: [PATCH 3/9] libceph: avoid using freed osd in __kick_osd_requests()
Quoted 49 lines · Alex Elder
If an osd has no requests and no linger requests,
__reset_osd()will just remove it with a call to__remove_osd(). That drops a reference to the osd, and therefore the osd may have been free by the time__reset_osd()returns. That function offers no indication this may have occurred, and as a result the osd will continue to be used even when it's no longer valid.
Change__reset_osd()so it returns an error (ENODEV) when it deletes the osd being reset. And change__kick_osd_requests()so it returns immediately (before referencing osd again) if__reset_osd()returns *any* error.Signed-off-by Alex Elder <[email protected]>--- net/ceph/osd_client.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)net/ceph/osd_client.c +1
-1@@ -581,7 +581,7 @@ static void __kick_osd_requests(struct ceph_osd_client *osdc,dout ("__kick_osd_requests osd%d\n" , osd->o_osd); err =__reset_osd (osdc, osd); -if (err == -EAGAIN ) +if (err)return ;net/ceph/osd_client.c +1
-0list_for_each_entry (req, &osd->o_requests, r_osd_item) {@@ -745,6 +745,7 @@ static int __reset_osd(struct ceph_osd_client *osdc, struct ceph_osd *osd)if (list_empty (&osd->o_requests) &&list_empty (&osd->o_linger_requests)) {__remove_osd (osdc, osd); + ret = -ENODEV ; } else if (memcmp(&osdc->osdmap->osd_addr[osd->o_osd], &osd->o_con.peer_addr,
sizeof(osd->o_con.peer_addr)) == 0 &&Signature · 6 lines
1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe ceph-devel" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 4/9 rbd: get rid of RBD_MAX_SEG_NAME_LEN
In reply to Alex ElderRBD_MAX_SEG_NAME_LEN represents the maximum length of an rbd object name (i.e., one of the objects providing storage backing an rbd image).
Another symbol, MAX_OBJ_NAME_SIZE, is used in the osd client code to define the maximum length of any object name in an osd request.
Right now they disagree, with RBD_MAX_SEG_NAME_LEN being too big.
There's no real benefit at this point to defining the rbd object name length limit separate from any other object name, so just get rid of RBD_MAX_SEG_NAME_LEN and use MAX_OBJ_NAME_SIZE in its place.
--- drivers/block/rbd.c | 6 +++--- drivers/block/rbd_types.h | 2 -- 2 files changed, 3 insertions(+), 5 deletions(-)
drivers/block/rbd.c +0 -0
@@ -740,13 +740,13 @@ static char *rbd_segment_name(struct rbd_device
*rbd_dev, u64 offset)
u64 segment;
int ret;
- name = kmalloc(RBD_MAX_SEG_NAME_LEN + 1, GFP_NOIO);
+ name = kmalloc(MAX_OBJ_NAME_SIZE + 1, GFP_NOIO);
if (!name)
return NULL;
segment = offset >> rbd_dev->header.obj_order;
- ret = snprintf(name, RBD_MAX_SEG_NAME_LEN, "%s.%012llx",
+ ret = snprintf(name, MAX_OBJ_NAME_SIZE + 1, "%s.%012llx",
rbd_dev->header.object_prefix, segment);
- if (ret < 0 || ret >= RBD_MAX_SEG_NAME_LEN) {
+ if (ret < 0 || ret > MAX_OBJ_NAME_SIZE) { pr_err("error formatting segment name for #%llu (%d)\n",
segment, ret);
kfree(name);
drivers/block/rbd_types.h +0 -2
@@ -46,8 +46,6 @@#define RBD_MIN_OBJ_ORDER 16#define RBD_MAX_OBJ_ORDER 30 -#define RBD_MAX_SEG_NAME_LEN 128 -#define RBD_COMP_NONE 0#define RBD_CRYPT_NONE 0
Signature · 1 line
1.7.9.5
Re: [PATCH 4/9] rbd: get rid of RBD_MAX_SEG_NAME_LEN
Quoted 64 lines · Alex Elder
RBD_MAX_SEG_NAME_LENrepresents the maximum length of an rbd object name (i.e., one of the objects providing storage backing an rbd image).Another symbol,
MAX_OBJ_NAME_SIZE, is used in the osd client code to define the maximum length of any object name in an osd request.Right now they disagree, with
RBD_MAX_SEG_NAME_LENbeing too big.There's no real benefit at this point to defining the rbd object name length limit separate from any other object name, so just get rid of
RBD_MAX_SEG_NAME_LENand useMAX_OBJ_NAME_SIZEin its place.Signed-off-by Alex Elder <[email protected]>--- drivers/block/rbd.c | 6 +++--- drivers/block/rbd_types.h | 2 -- 2 files changed, 3 insertions(+), 5 deletions(-)drivers/block/rbd.c +3
-3@@ -740,13 +740,13 @@ static char *rbd_segment_name(struct rbd_device *rbd_dev, u64 offset) u64 segment;int ret; - name =kmalloc (RBD_MAX_SEG_NAME_LEN +1 ,GFP_NOIO ); + name =kmalloc (MAX_OBJ_NAME_SIZE +1 ,GFP_NOIO );if (!name)return NULL ; segment = offset >> rbd_dev->header.obj_order; - ret =snprintf (name,RBD_MAX_SEG_NAME_LEN ,"%s.%012llx" , + ret =snprintf (name,MAX_OBJ_NAME_SIZE +1 ,"%s.%012llx" , rbd_dev->header.object_prefix, segment); -if (ret <0 || ret >=RBD_MAX_SEG_NAME_LEN ) { +if (ret <0 || ret >MAX_OBJ_NAME_SIZE ) {pr_err ("error formatting segment name for #%llu (%d)\n" , segment, ret);drivers/block/rbd.c +0
-0kfree (name);drivers/block/rbd_types.h +0
-2@@ -46,8 +46,6 @@#define RBD_MIN_OBJ_ORDER 16#define RBD_MAX_OBJ_ORDER 30 -#define RBD_MAX_SEG_NAME_LEN 128 -#define RBD_COMP_NONE 0#define RBD_CRYPT_NONE 0Signature · 6 lines
1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe ceph-devel" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 5/9 libceph: init osd->o_node in create_osd()
In reply to Alex ElderIt turns out to be harmless but the red-black node o_node in the ceph osd structure is not initialized in create_osd(). Add a call to rb_init_node() initialize it.
--- net/ceph/osd_client.c | 1 + 1 file changed, 1 insertion(+)
net/ceph/osd_client.c +0 -0
@@ -642,6 +642,7 @@ static struct ceph_osd *create_osd(struct
ceph_osd_client *osdc, int onum)
atomic_set(&osd->o_ref, 1);
osd->o_osdc = osdc;
osd->o_osd = onum;
+ rb_init_node(&osd->o_node);
INIT_LIST_HEAD(&osd->o_requests);
INIT_LIST_HEAD(&osd->o_linger_requests);
INIT_LIST_HEAD(&osd->o_osd_lru);
Signature · 1 line
1.7.9.5
Re: [PATCH 5/9] libceph: init osd->o_node in create_osd()
We should drop this one, I think. See upstream commit 4c199a93a2d36b277a9fd209a0f2793f8460a215. When we added the similar call on teh request tree it caused some noise in linux-next and then got removed.
sage
Quoted 31 lines · Alex Elder
It turns out to be harmless but the red-black node
o_nodein the ceph osd structure is not initialized increate_osd(). Add a call torb_init_node()initialize it.Signed-off-by Alex Elder <[email protected]>--- net/ceph/osd_client.c | 1 + 1 file changed, 1 insertion(+)net/ceph/osd_client.c +1
-0@@ -642,6 +642,7 @@ static struct ceph_osd *create_osd(struct ceph_osd_client *osdc, int onum) atomic_set(&osd->o_ref, 1); osd->o_osdc = osdc; osd->o_osd = onum; +rb_init_node (&osd->o_node);INIT_LIST_HEAD (&osd->o_requests);INIT_LIST_HEAD (&osd->o_linger_requests);
INIT_LIST_HEAD(&osd->o_osd_lru);Signature · 6 lines
1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe ceph-devel" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 5/9] libceph: init osd->o_node in create_osd()
Quoted 4 lines · Sage Weil
We should drop this one, I think. See upstream commit
4c199a93a2d36b277a9fd209a0f2793f8460a215. When we added the similar call on teh request tree it caused some noise in linux-next and then got removed.
Well, we need to initialize it. In particular, there is a call to RB_EMPTY_NODE() in __unregister_request() which assumes that if a node is not in the tree, it has been initialized as it is in RB_CLEAR_NODE(). Even if that's not a normal path (and even if no current code path allows that condition), if we're using RB_EMPTY_NODE() we need to be sure any node we'll pass is properly set up or it's broken code.
So it's fine with me if we use RB_CLEAR_NODE() instead. Or, we could stop using RB_EMPTY_NODE() (but that's more work to verify).
The same goes for the event passed to __remove_event(), but that should be fixed in a separate patch.
Please let me know what you think.
-Alex
Quoted 35 lines
sage
Quoted 31 lines · Alex Elder
It turns out to be harmless but the red-black node
o_nodein the ceph osd structure is not initialized increate_osd(). Add a call torb_init_node()initialize it.Signed-off-by Alex Elder <[email protected]>--- net/ceph/osd_client.c | 1 + 1 file changed, 1 insertion(+)net/ceph/osd_client.c +1
-0@@ -642,6 +642,7 @@ static struct ceph_osd *create_osd(struct ceph_osd_client *osdc, int onum) atomic_set(&osd->o_ref, 1); osd->o_osdc = osdc; osd->o_osd = onum; +rb_init_node (&osd->o_node);INIT_LIST_HEAD (&osd->o_requests);INIT_LIST_HEAD (&osd->o_linger_requests);
INIT_LIST_HEAD(&osd->o_osd_lru);Signature · 6 lines
1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe ceph-devel" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 5/9] libceph: init osd->o_node in create_osd()
Quoted 14 lines · Alex Elder
Quoted 4 lines · Sage Weil
We should drop this one, I think. See upstream commit
4c199a93a2d36b277a9fd209a0f2793f8460a215. When we added the similar call on teh request tree it caused some noise in linux-next and then got removed.Well, we need to initialize it. In particular, there is a call to
RB_EMPTY_NODE()in__unregister_request()which assumes that if a node is not in the tree, it has been initialized as it is inRB_CLEAR_NODE(). Even if that's not a normal path (and even if no current code path allows that condition), if we're usingRB_EMPTY_NODE()we need to be sure any node we'll pass is properly set up or it's broken code.
Quoted 2 lines
So it's fine with me if we use
RB_CLEAR_NODE()instead. Or, we could stop usingRB_EMPTY_NODE()(but that's more work to verify).
It sounds like RB_CLEAR_NODE is the right path. From the commit message it looks like rb_init_node() is broken and/or going away. Let's just switch to that?
And I guess we probably need to do the same in the request tree, too?
s
Quoted 44 lines
The same goes for the event passed to
__remove_event(), but that should be fixed in a separate patch.Please let me know what you think.
-Alex
Quoted 35 lines
sage
Quoted 31 lines · Alex Elder
It turns out to be harmless but the red-black node
o_nodein the ceph osd structure is not initialized increate_osd(). Add a call torb_init_node()initialize it.Signed-off-by Alex Elder <[email protected]>--- net/ceph/osd_client.c | 1 + 1 file changed, 1 insertion(+)net/ceph/osd_client.c +1
-0@@ -642,6 +642,7 @@ static struct ceph_osd *create_osd(struct ceph_osd_client *osdc, int onum) atomic_set(&osd->o_ref, 1); osd->o_osdc = osdc; osd->o_osd = onum; +rb_init_node (&osd->o_node);INIT_LIST_HEAD (&osd->o_requests);INIT_LIST_HEAD (&osd->o_linger_requests);
INIT_LIST_HEAD(&osd->o_osd_lru);Signature · 6 lines
1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe ceph-devel" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 5/9] libceph: init osd->o_node in create_osd()
Quoted 15 lines · Sage Weil
Quoted 14 lines · Alex Elder
Quoted 4 lines · Sage Weil
We should drop this one, I think. See upstream commit
4c199a93a2d36b277a9fd209a0f2793f8460a215. When we added the similar call on teh request tree it caused some noise in linux-next and then got removed.Well, we need to initialize it. In particular, there is a call to
RB_EMPTY_NODE()in__unregister_request()which assumes that if a node is not in the tree, it has been initialized as it is inRB_CLEAR_NODE(). Even if that's not a normal path (and even if no current code path allows that condition), if we're usingRB_EMPTY_NODE()we need to be sure any node we'll pass is properly set up or it's broken code.
Quoted 6 lines
Quoted 2 lines
So it's fine with me if we use
RB_CLEAR_NODE()instead. Or, we could stop usingRB_EMPTY_NODE()(but that's more work to verify).It sounds like
RB_CLEAR_NODEis the right path. From the commit message it looks likerb_init_node()is broken and/or going away. Let's just switch to that?
Until you questioned it I actually hadn't looked deep enough to know there was this good a reason to do the initialization... It was more that I prefer to see things initialized explicitly sort of thing.
Quoted 1 line
And I guess we probably need to do the same in the request tree, too?
Yes I already have a patch put together for that. I'll post it shortly, I was waiting to hear back first.
-Alex
Quoted 46 lines
s
Quoted 44 lines
The same goes for the event passed to
__remove_event(), but that should be fixed in a separate patch.Please let me know what you think.
-Alex
Quoted 35 lines
sage
Quoted 31 lines · Alex Elder
It turns out to be harmless but the red-black node
o_nodein the ceph osd structure is not initialized increate_osd(). Add a call torb_init_node()initialize it.Signed-off-by Alex Elder <[email protected]>--- net/ceph/osd_client.c | 1 + 1 file changed, 1 insertion(+)net/ceph/osd_client.c +1
-0@@ -642,6 +642,7 @@ static struct ceph_osd *create_osd(struct ceph_osd_client *osdc, int onum) atomic_set(&osd->o_ref, 1); osd->o_osdc = osdc; osd->o_osd = onum; +rb_init_node (&osd->o_node);INIT_LIST_HEAD (&osd->o_requests);INIT_LIST_HEAD (&osd->o_linger_requests);
INIT_LIST_HEAD(&osd->o_osd_lru);Signature · 6 lines
1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe ceph-devel" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 6/9 rbd: remove linger unconditionally
In reply to Alex ElderIn __unregister_linger_request(), the request is being removed from the osd client's req_linger list only when the request has a non-null osd pointer. It should be done whether or not the request currently has an osd.
This is most likely a non-issue because I believe the request will always have an osd when this function is called.
--- net/ceph/osd_client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/ceph/osd_client.c +0 -0
@@ -907,8 +907,8 @@ static void __unregister_linger_request(struct
ceph_osd_client *osdc,
struct ceph_osd_request *req)
{
dout("__unregister_linger_request %p\n", req);
+ list_del_init(&req->r_linger_item);
if (req->r_osd) {
- list_del_init(&req->r_linger_item);
list_del_init(&req->r_linger_osd);
if (list_empty(&req->r_osd->o_requests) &&
Signature · 1 line
1.7.9.5
Re: [PATCH 6/9] rbd: remove linger unconditionally
Quoted 37 lines · Alex Elder
In
__unregister_linger_request(), the request is being removed from the osd client'sreq_lingerlist only when the request has a non-null osd pointer. It should be done whether or not the request currently has an osd.This is most likely a non-issue because I believe the request will always have an osd when this function is called.
Signed-off-by Alex Elder <[email protected]>--- net/ceph/osd_client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)net/ceph/osd_client.c +1
-1@@ -907,8 +907,8 @@ static void __unregister_linger_request(struct ceph_osd_client *osdc, struct ceph_osd_request *req) { dout("__unregister_linger_request %p\n", req); +list_del_init (&req->r_linger_item);if (req->r_osd) { -list_del_init (&req->r_linger_item);list_del_init (&req->r_linger_osd);if (
list_empty(&req->r_osd->o_requests)&&Signature · 6 lines
1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe ceph-devel" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 7/9 rbd: don't use ENOTSUPP
In reply to Alex ElderENOTSUPP is not a standard errno (it shows up as "Unknown error 524" in an error message). This is what was getting produced when the the local rbd code does not implement features required by a discovered rbd image.
Change the error code returned in this case to ENXIO.
--- drivers/block/rbd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/block/rbd.c +0 -0
@@ -2456,7 +2456,7 @@ static int _rbd_dev_v2_snap_features(struct
rbd_device *rbd_dev, u64 snap_id,
incompat = le64_to_cpu(features_buf.incompat); if (incompat & ~RBD_FEATURES_ALL)
- return -ENOTSUPP;
+ return -ENXIO;
*snap_features = le64_to_cpu(features_buf.features);
Signature · 1 line
1.7.9.5
Re: [PATCH 7/9] rbd: don't use ENOTSUPP
Quoted 35 lines · Alex Elder
ENOTSUPP is not a standard errno (it shows up as "Unknown error 524" in an error message). This is what was getting produced when the the local rbd code does not implement features required by a discovered rbd image.
Change the error code returned in this case to ENXIO.
Signed-off-by Alex Elder <[email protected]>--- drivers/block/rbd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)drivers/block/rbd.c +1
-1@@ -2456,7 +2456,7 @@ static int _rbd_dev_v2_snap_features(struct rbd_device *rbd_dev, u64 snap_id, incompat =le64_to_cpu (features_buf.incompat);if (incompat & ~RBD_FEATURES_ALL ) -return -ENOTSUPP ; +return -ENXIO ; *snap_features =le64_to_cpu (features_buf.features);Signature · 7 lines
-- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe ceph-devel" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 8/9 rbd: fix ceph_pg_poolid_by_name()
In reply to Alex ElderCurrently ceph_pg_poolid_by_name() returns an int, which is used to encode a ceph pool id. This could be a problem because a pool id (at least in some cases) is a 64-bit value. We have a defined pool id value that represents "no pool," and that's a very sensible return value here.
This patch changes ceph_pg_poolid_by_name() to return a 64-bit pool id value, or CEPH_NOPOOL if the named pool is not found.
The patch also gratuitously renames the function, separating "pool" from "id" in the name by an underscore.
--- drivers/block/rbd.c | 6 +++--- include/linux/ceph/osdmap.h | 2 +- net/ceph/osdmap.c | 14 ++++++++------ 3 files changed, 12 insertions(+), 10 deletions(-)
drivers/block/rbd.c +3 -3
@@ -3642,11 +3642,11 @@ static ssize_t rbd_add(struct bus_type *bus, ceph_opts =NULL ;/* rbd_dev client now owns this */ /* pick the pool */ + rc = -ENOENT ; osdc = &rbdc->client->osdc; - rc =ceph_pg_poolid_by_name (osdc->osdmap, spec->pool_name); -if (rc <0 ) + spec->pool_id =ceph_pg_pool_id_by_name (osdc->osdmap, spec->pool_name); +if (spec->pool_id ==CEPH_NOPOOL ) goto err_out_client; - spec->pool_id = (u64 ) rc; rbd_dev =rbd_dev_create (rbdc, spec);if (!rbd_dev)
include/linux/ceph/osdmap.h +0 -0
@@ -124,6 +124,6 @@ extern int ceph_calc_pg_primary(struct ceph_osdmap
*osdmap,
struct ceph_pg pgid);
extern const char *ceph_pg_pool_name_by_id(struct ceph_osdmap *map, u64
id);
-extern int ceph_pg_poolid_by_name(struct ceph_osdmap *map, const char *name);
+extern __u64 ceph_pg_pool_id_by_name(struct ceph_osdmap *map, const char *name);
#endif
net/ceph/osdmap.c +0 -0
@@ -485,19 +485,21 @@ const char *ceph_pg_pool_name_by_id(struct
ceph_osdmap *map, u64 id)
}
EXPORT_SYMBOL(ceph_pg_pool_name_by_id);
-int ceph_pg_poolid_by_name(struct ceph_osdmap *map, const char *name) +__u64 ceph_pg_pool_id_by_name(struct ceph_osdmap *map, const char *name)
{
struct rb_node *rbp;
for (rbp = rb_first(&map->pg_pools); rbp; rbp = rb_next(rbp)) {
- struct ceph_pg_pool_info *pi =
- rb_entry(rbp, struct ceph_pg_pool_info, node);
+ struct ceph_pg_pool_info *pi;
+
+ pi = rb_entry(rbp, struct ceph_pg_pool_info, node);
if (pi->name && strcmp(pi->name, name) == 0)
- return pi->id;
+ return (__u64) pi->id;
}
- return -ENOENT;
+
+ return CEPH_NOPOOL;
}
-EXPORT_SYMBOL(ceph_pg_poolid_by_name); +EXPORT_SYMBOL(ceph_pg_pool_id_by_name);
static void __remove_pg_pool(struct rb_root *root, structceph_pg_pool_info *pi)
{
Signature · 1 line
1.7.9.5
Re: [PATCH 8/9] rbd: fix ceph_pg_poolid_by_name()
Most of the code uses int64_t/__s64 for the pool id, although in a few cases we screwed up and limited it to 32 bits. In reality, that's way overkill anyway; we could have left it at 32 bits to begin with.
My first instinct would be to change the return type to long long or s64 and avoid the use magic #defines...
Quoted 97 lines · Alex Elder
Currently
ceph_pg_poolid_by_name()returns an int, which is used to encode a ceph pool id. This could be a problem because a pool id (at least in some cases) is a 64-bit value. We have a defined pool id value that represents "no pool," and that's a very sensible return value here.This patch changes
ceph_pg_poolid_by_name()to return a 64-bit pool id value, orCEPH_NOPOOLif the named pool is not found.The patch also gratuitously renames the function, separating "pool" from "id" in the name by an underscore.
Signed-off-by Alex Elder <[email protected]>--- drivers/block/rbd.c | 6 +++--- include/linux/ceph/osdmap.h | 2 +- net/ceph/osdmap.c | 14 ++++++++------ 3 files changed, 12 insertions(+), 10 deletions(-)drivers/block/rbd.c +3
-3@@ -3642,11 +3642,11 @@ static ssize_t rbd_add(struct bus_type *bus, ceph_opts =NULL ;/* rbd_dev client now owns this */ /* pick the pool */ + rc = -ENOENT ; osdc = &rbdc->client->osdc; - rc =ceph_pg_poolid_by_name (osdc->osdmap, spec->pool_name); -if (rc <0 ) + spec->pool_id =ceph_pg_pool_id_by_name (osdc->osdmap, spec->pool_name); +if (spec->pool_id ==CEPH_NOPOOL ) goto err_out_client; - spec->pool_id = (u64 ) rc; rbd_dev =rbd_dev_create (rbdc, spec);if (!rbd_dev)include/linux/ceph/osdmap.h +0
-1@@ -124,6 +124,6 @@ extern int ceph_calc_pg_primary(struct ceph_osdmap *osdmap, struct ceph_pg pgid);extern const char *ceph_pg_pool_name_by_id (struct ceph_osdmap *map,u64 id); -extern int ceph_pg_poolid_by_name(struct ceph_osdmap *map, const char*name);
+extern__u64ceph_pg_pool_id_by_name(struct ceph_osdmap *map, const char *name);#endif
net/ceph/osdmap.c +8
-6@@ -485,19 +485,21 @@ const char *ceph_pg_pool_name_by_id(struct ceph_osdmap *map, u64 id) }EXPORT_SYMBOL (ceph_pg_pool_name_by_id ); -int ceph_pg_poolid_by_name (struct ceph_osdmap *map,const char *name) +__u64 ceph_pg_pool_id_by_name (struct ceph_osdmap *map,const char *name) {struct rb_node *rbp;for (rbp =rb_first (&map->pg_pools); rbp; rbp =rb_next (rbp)) { -struct ceph_pg_pool_info *pi = - rb_entry(rbp, struct ceph_pg_pool_info, node); +struct ceph_pg_pool_info *pi; + + pi = rb_entry(rbp, struct ceph_pg_pool_info, node);if (pi->name &&strcmp (pi->name, name) ==0 ) -return pi->id; +return (__u64 ) pi->id; } -return -ENOENT ; + +return CEPH_NOPOOL ; } -EXPORT_SYMBOL (ceph_pg_poolid_by_name); +EXPORT_SYMBOL (ceph_pg_pool_id_by_name); static void __remove_pg_pool(struct rb_root *root, struct
ceph_pg_pool_info*pi)
{Signature · 6 lines
1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe ceph-devel" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 8/9] rbd: fix ceph_pg_poolid_by_name()
Quoted 3 lines · Sage Weil
Most of the code uses int64_t/__s64 for the pool id, although in a few cases we screwed up and limited it to 32 bits. In reality, that's way overkill anyway; we could have left it at 32 bits to begin with.
The differing types representing the same abstraction are precisely the point of making this change. What really needs to happen is we need to fix *that*; that is, decide whether a pool id is 32 or 64 bits, signed or not, and then make sure it's that and only that throughout the code.
In the mean time, this change is defensive, making sure there's no uncertainty in what we're dealing with within rbd. The code will guarantee some future change won't inadvertently let a wrong-sized pool id attempt to sneak through an interface unnoticed. It may seem like overkill but this kind of bug is really hard to track down, and it's better to simply preclude it from happening.
Quoted 2 lines
My first instinct would be to change the return type to long long or s64 and avoid the use magic #defines...
I absolutely like using base types (like long long). But where those types are used to represent a true abstraction (like a snapshot id, or a pool id), it is the one place I think the use of typedefs and "magic #defines" is actually a real help because it makes explicit you're working with something more than an (e.g.) an int. A typedef makes obviously to the reader that it's restricted a bit (so, for example, it isn't meaningful to do math on it). And symbolic constants make it a lot easier to search through code for special situations like this.
This stuff is all sort of philosophical rather than technical. The code before works, and the code as I've changed it works.
Anybody else have thoughts?
-Alex
Quoted 101 lines · Alex Elder
Quoted 98 lines
Currently
ceph_pg_poolid_by_name()returns an int, which is used to encode a ceph pool id. This could be a problem because a pool id (at least in some cases) is a 64-bit value. We have a defined pool id value that represents "no pool," and that's a very sensible return value here.This patch changes
ceph_pg_poolid_by_name()to return a 64-bit pool id value, orCEPH_NOPOOLif the named pool is not found.The patch also gratuitously renames the function, separating "pool" from "id" in the name by an underscore.
Signed-off-by Alex Elder <[email protected]>--- drivers/block/rbd.c | 6 +++--- include/linux/ceph/osdmap.h | 2 +- net/ceph/osdmap.c | 14 ++++++++------ 3 files changed, 12 insertions(+), 10 deletions(-)drivers/block/rbd.c +3
-3@@ -3642,11 +3642,11 @@ static ssize_t rbd_add(struct bus_type *bus, ceph_opts =NULL ;/* rbd_dev client now owns this */ /* pick the pool */ + rc = -ENOENT ; osdc = &rbdc->client->osdc; - rc =ceph_pg_poolid_by_name (osdc->osdmap, spec->pool_name); -if (rc <0 ) + spec->pool_id =ceph_pg_pool_id_by_name (osdc->osdmap, spec->pool_name); +if (spec->pool_id ==CEPH_NOPOOL ) goto err_out_client; - spec->pool_id = (u64 ) rc; rbd_dev =rbd_dev_create (rbdc, spec);if (!rbd_dev)include/linux/ceph/osdmap.h +0
-1@@ -124,6 +124,6 @@ extern int ceph_calc_pg_primary(struct ceph_osdmap *osdmap, struct ceph_pg pgid);extern const char *ceph_pg_pool_name_by_id (struct ceph_osdmap *map,u64 id); -extern int ceph_pg_poolid_by_name(struct ceph_osdmap *map, const char*name);
+extern__u64ceph_pg_pool_id_by_name(struct ceph_osdmap *map, const char *name);#endif
net/ceph/osdmap.c +8
-6@@ -485,19 +485,21 @@ const char *ceph_pg_pool_name_by_id(struct ceph_osdmap *map, u64 id) }EXPORT_SYMBOL (ceph_pg_pool_name_by_id ); -int ceph_pg_poolid_by_name (struct ceph_osdmap *map,const char *name) +__u64 ceph_pg_pool_id_by_name (struct ceph_osdmap *map,const char *name) {struct rb_node *rbp;for (rbp =rb_first (&map->pg_pools); rbp; rbp =rb_next (rbp)) { -struct ceph_pg_pool_info *pi = - rb_entry(rbp, struct ceph_pg_pool_info, node); +struct ceph_pg_pool_info *pi; + + pi = rb_entry(rbp, struct ceph_pg_pool_info, node);if (pi->name &&strcmp (pi->name, name) ==0 ) -return pi->id; +return (__u64 ) pi->id; } -return -ENOENT ; + +return CEPH_NOPOOL ; } -EXPORT_SYMBOL (ceph_pg_poolid_by_name); +EXPORT_SYMBOL (ceph_pg_pool_id_by_name); static void __remove_pg_pool(struct rb_root *root, struct
ceph_pg_pool_info*pi)
{Signature · 6 lines
1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe ceph-devel" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 8/9] rbd: fix ceph_pg_poolid_by_name()
Quoted 22 lines · Alex Elder
Quoted 3 lines · Sage Weil
Most of the code uses int64_t/__s64 for the pool id, although in a few cases we screwed up and limited it to 32 bits. In reality, that's way overkill anyway; we could have left it at 32 bits to begin with.
The differing types representing the same abstraction are precisely the point of making this change. What really needs to happen is we need to fix *that*; that is, decide whether a pool id is 32 or 64 bits, signed or not, and then make sure it's that and only that throughout the code.
In the mean time, this change is defensive, making sure there's no uncertainty in what we're dealing with within rbd. The code will guarantee some future change won't inadvertently let a wrong-sized pool id attempt to sneak through an interface unnoticed. It may seem like overkill but this kind of bug is really hard to track down, and it's better to simply preclude it from happening.
Quoted 2 lines
My first instinct would be to change the return type to long long or s64 and avoid the use magic #defines...
Quoted 7 lines
I absolutely like using base types (like long long). But where those types are used to represent a true abstraction (like a snapshot id, or a pool id), it is the one place I think the use of typedefs and "magic #defines" is actually a real help because it makes explicit you're working with something more than an (e.g.) an int. A typedef makes obviously to the reader that it's restricted a bit (so, for example, it isn't meaningful to do math on it).
Completely agreed.
Quoted 2 lines
And symbolic constants make it a lot easier to search through code for special situations like this.
Okay with me. Just keep in mind that most of the other code looks for a negative int64_t return value (i.e., the pool id is 63 bits).
The reason there is a mismatch: it used to be a 32-bit value, and at one point we thought we'd do a pool per radosgw bucket and did a huge conversion to 64-bit. And missed a few places. The whole transition was ill-conceived and generally a bad idea, though; we should never have that many pools. So it's not clear it's worth the effort to spend another feature bit to fix it up.
sage
Quoted 109 lines
This stuff is all sort of philosophical rather than technical. The code before works, and the code as I've changed it works.
Anybody else have thoughts?
-Alex
Quoted 101 lines · Alex Elder
Quoted 98 lines
Currently
ceph_pg_poolid_by_name()returns an int, which is used to encode a ceph pool id. This could be a problem because a pool id (at least in some cases) is a 64-bit value. We have a defined pool id value that represents "no pool," and that's a very sensible return value here.This patch changes
ceph_pg_poolid_by_name()to return a 64-bit pool id value, orCEPH_NOPOOLif the named pool is not found.The patch also gratuitously renames the function, separating "pool" from "id" in the name by an underscore.
Signed-off-by Alex Elder <[email protected]>--- drivers/block/rbd.c | 6 +++--- include/linux/ceph/osdmap.h | 2 +- net/ceph/osdmap.c | 14 ++++++++------ 3 files changed, 12 insertions(+), 10 deletions(-)drivers/block/rbd.c +3
-3@@ -3642,11 +3642,11 @@ static ssize_t rbd_add(struct bus_type *bus, ceph_opts =NULL ;/* rbd_dev client now owns this */ /* pick the pool */ + rc = -ENOENT ; osdc = &rbdc->client->osdc; - rc =ceph_pg_poolid_by_name (osdc->osdmap, spec->pool_name); -if (rc <0 ) + spec->pool_id =ceph_pg_pool_id_by_name (osdc->osdmap, spec->pool_name); +if (spec->pool_id ==CEPH_NOPOOL ) goto err_out_client; - spec->pool_id = (u64 ) rc; rbd_dev =rbd_dev_create (rbdc, spec);if (!rbd_dev)include/linux/ceph/osdmap.h +0
-1@@ -124,6 +124,6 @@ extern int ceph_calc_pg_primary(struct ceph_osdmap *osdmap, struct ceph_pg pgid);extern const char *ceph_pg_pool_name_by_id (struct ceph_osdmap *map,u64 id); -extern int ceph_pg_poolid_by_name(struct ceph_osdmap *map, const char*name);
+extern__u64ceph_pg_pool_id_by_name(struct ceph_osdmap *map, const char *name);#endif
net/ceph/osdmap.c +8
-6@@ -485,19 +485,21 @@ const char *ceph_pg_pool_name_by_id(struct ceph_osdmap *map, u64 id) }EXPORT_SYMBOL (ceph_pg_pool_name_by_id ); -int ceph_pg_poolid_by_name (struct ceph_osdmap *map,const char *name) +__u64 ceph_pg_pool_id_by_name (struct ceph_osdmap *map,const char *name) {struct rb_node *rbp;for (rbp =rb_first (&map->pg_pools); rbp; rbp =rb_next (rbp)) { -struct ceph_pg_pool_info *pi = - rb_entry(rbp, struct ceph_pg_pool_info, node); +struct ceph_pg_pool_info *pi; + + pi = rb_entry(rbp, struct ceph_pg_pool_info, node);if (pi->name &&strcmp (pi->name, name) ==0 ) -return pi->id; +return (__u64 ) pi->id; } -return -ENOENT ; + +return CEPH_NOPOOL ; } -EXPORT_SYMBOL (ceph_pg_poolid_by_name); +EXPORT_SYMBOL (ceph_pg_pool_id_by_name); static void __remove_pg_pool(struct rb_root *root, struct
ceph_pg_pool_info*pi)
{Signature · 6 lines
1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe ceph-devel" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 8/9] rbd: fix ceph_pg_poolid_by_name()
Quoted 31 lines · Sage Weil
Quoted 22 lines · Alex Elder
Quoted 3 lines · Sage Weil
Most of the code uses int64_t/__s64 for the pool id, although in a few cases we screwed up and limited it to 32 bits. In reality, that's way overkill anyway; we could have left it at 32 bits to begin with.
The differing types representing the same abstraction are precisely the point of making this change. What really needs to happen is we need to fix *that*; that is, decide whether a pool id is 32 or 64 bits, signed or not, and then make sure it's that and only that throughout the code.
In the mean time, this change is defensive, making sure there's no uncertainty in what we're dealing with within rbd. The code will guarantee some future change won't inadvertently let a wrong-sized pool id attempt to sneak through an interface unnoticed. It may seem like overkill but this kind of bug is really hard to track down, and it's better to simply preclude it from happening.
Quoted 2 lines
My first instinct would be to change the return type to long long or s64 and avoid the use magic #defines...
Quoted 7 lines
I absolutely like using base types (like long long). But where those types are used to represent a true abstraction (like a snapshot id, or a pool id), it is the one place I think the use of typedefs and "magic #defines" is actually a real help because it makes explicit you're working with something more than an (e.g.) an int. A typedef makes obviously to the reader that it's restricted a bit (so, for example, it isn't meaningful to do math on it).
Quoted 7 lines
Completely agreed.
Quoted 2 lines
And symbolic constants make it a lot easier to search through code for special situations like this.
Okay with me. Just keep in mind that most of the other code looks for a negative
int64_treturn value (i.e., the pool id is 63 bits).
I.e., if I do this here but not elsewhere we're subject to the same kind of "someday" problems... In fact, it's just a different form of mismatched type--here returning an unsigned when elsewhere a signed value is assumed.
I still like the symbolic values, or in this case, maybe a macro ceph_pool_id_valid() or something. It just makes it easier to make other changes later, because you can easily (or maybe more precisely) search for the effects of a proposed change.
I find the time spent searching through code is large enough that I tend to do things in a way that facilitates that.
Let's talk about this today and come to an agreement about the best way to resolve this.
Thanks.
-Alex
Quoted 118 lines
The reason there is a mismatch: it used to be a 32-bit value, and at one point we thought we'd do a pool per radosgw bucket and did a huge conversion to 64-bit. And missed a few places. The whole transition was ill-conceived and generally a bad idea, though; we should never have that many pools. So it's not clear it's worth the effort to spend another feature bit to fix it up.
sage
Quoted 109 lines
This stuff is all sort of philosophical rather than technical. The code before works, and the code as I've changed it works.
Anybody else have thoughts?
-Alex
Quoted 101 lines · Alex Elder
Quoted 98 lines
Currently
ceph_pg_poolid_by_name()returns an int, which is used to encode a ceph pool id. This could be a problem because a pool id (at least in some cases) is a 64-bit value. We have a defined pool id value that represents "no pool," and that's a very sensible return value here.This patch changes
ceph_pg_poolid_by_name()to return a 64-bit pool id value, orCEPH_NOPOOLif the named pool is not found.The patch also gratuitously renames the function, separating "pool" from "id" in the name by an underscore.
Signed-off-by Alex Elder <[email protected]>--- drivers/block/rbd.c | 6 +++--- include/linux/ceph/osdmap.h | 2 +- net/ceph/osdmap.c | 14 ++++++++------ 3 files changed, 12 insertions(+), 10 deletions(-)drivers/block/rbd.c +3
-3@@ -3642,11 +3642,11 @@ static ssize_t rbd_add(struct bus_type *bus, ceph_opts =NULL ;/* rbd_dev client now owns this */ /* pick the pool */ + rc = -ENOENT ; osdc = &rbdc->client->osdc; - rc =ceph_pg_poolid_by_name (osdc->osdmap, spec->pool_name); -if (rc <0 ) + spec->pool_id =ceph_pg_pool_id_by_name (osdc->osdmap, spec->pool_name); +if (spec->pool_id ==CEPH_NOPOOL ) goto err_out_client; - spec->pool_id = (u64 ) rc; rbd_dev =rbd_dev_create (rbdc, spec);if (!rbd_dev)include/linux/ceph/osdmap.h +0
-1@@ -124,6 +124,6 @@ extern int ceph_calc_pg_primary(struct ceph_osdmap *osdmap, struct ceph_pg pgid);extern const char *ceph_pg_pool_name_by_id (struct ceph_osdmap *map,u64 id); -extern int ceph_pg_poolid_by_name(struct ceph_osdmap *map, const char*name);
+extern__u64ceph_pg_pool_id_by_name(struct ceph_osdmap *map, const char *name);#endif
net/ceph/osdmap.c +8
-6@@ -485,19 +485,21 @@ const char *ceph_pg_pool_name_by_id(struct ceph_osdmap *map, u64 id) }EXPORT_SYMBOL (ceph_pg_pool_name_by_id ); -int ceph_pg_poolid_by_name (struct ceph_osdmap *map,const char *name) +__u64 ceph_pg_pool_id_by_name (struct ceph_osdmap *map,const char *name) {struct rb_node *rbp;for (rbp =rb_first (&map->pg_pools); rbp; rbp =rb_next (rbp)) { -struct ceph_pg_pool_info *pi = - rb_entry(rbp, struct ceph_pg_pool_info, node); +struct ceph_pg_pool_info *pi; + + pi = rb_entry(rbp, struct ceph_pg_pool_info, node);if (pi->name &&strcmp (pi->name, name) ==0 ) -return pi->id; +return (__u64 ) pi->id; } -return -ENOENT ; + +return CEPH_NOPOOL ; } -EXPORT_SYMBOL (ceph_pg_poolid_by_name); +EXPORT_SYMBOL (ceph_pg_pool_id_by_name); static void __remove_pg_pool(struct rb_root *root, struct
ceph_pg_pool_info*pi)
{Signature · 6 lines
1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe ceph-devel" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 8/9] rbd: fix ceph_pg_poolid_by_name()
Quoted 6 lines · Alex Elder
Quoted 5 lines · Sage Weil
Quoted 4 lines · Alex Elder
Quoted 3 lines · Sage Weil
Most of the code uses int64_t/__s64 for the pool id, although in a few cases we screwed up and limited it to 32 bits. In reality, that's way overkill anyway; we could have left it at 32 bits to begin with.
I just wanted to follow up on this. Sage and I discussed this today. He said that most of the other code involving pool id's assume they are signed, so a negative pool id indicates an error. Rather than introduce another new way pool id's could be (mis)interpreted I agreed to rework this patch so that it follows that basic pattern (i.e., considering pool id's signed).
I haven't looked at it closely yet but I still expect to have a revised patch, though it's possible I'll conclude leaving things as-is is best.
Some future cleanup task can take care of unifying everything to 64 bits (or possibly 32 bits), but that's another day.
-Alex
Quoted 174 lines
Quoted 25 lines
Quoted 17 lines
The differing types representing the same abstraction are precisely the point of making this change. What really needs to happen is we need to fix *that*; that is, decide whether a pool id is 32 or 64 bits, signed or not, and then make sure it's that and only that throughout the code.
In the mean time, this change is defensive, making sure there's no uncertainty in what we're dealing with within rbd. The code will guarantee some future change won't inadvertently let a wrong-sized pool id attempt to sneak through an interface unnoticed. It may seem like overkill but this kind of bug is really hard to track down, and it's better to simply preclude it from happening.
Quoted 2 lines
My first instinct would be to change the return type to long long or s64 and avoid the use magic #defines...
Quoted 7 lines
I absolutely like using base types (like long long). But where those types are used to represent a true abstraction (like a snapshot id, or a pool id), it is the one place I think the use of typedefs and "magic #defines" is actually a real help because it makes explicit you're working with something more than an (e.g.) an int. A typedef makes obviously to the reader that it's restricted a bit (so, for example, it isn't meaningful to do math on it).
Quoted 7 lines
Completely agreed.
Quoted 2 lines
And symbolic constants make it a lot easier to search through code for special situations like this.
Okay with me. Just keep in mind that most of the other code looks for a negative
int64_treturn value (i.e., the pool id is 63 bits).I.e., if I do this here but not elsewhere we're subject to the same kind of "someday" problems... In fact, it's just a different form of mismatched type--here returning an unsigned when elsewhere a signed value is assumed.
I still like the symbolic values, or in this case, maybe a macro
ceph_pool_id_valid()or something. It just makes it easier to make other changes later, because you can easily (or maybe more precisely) search for the effects of a proposed change.I find the time spent searching through code is large enough that I tend to do things in a way that facilitates that.
Let's talk about this today and come to an agreement about the best way to resolve this.
Thanks.
-Alex
Quoted 118 lines
The reason there is a mismatch: it used to be a 32-bit value, and at one point we thought we'd do a pool per radosgw bucket and did a huge conversion to 64-bit. And missed a few places. The whole transition was ill-conceived and generally a bad idea, though; we should never have that many pools. So it's not clear it's worth the effort to spend another feature bit to fix it up.
sage
Quoted 109 lines
This stuff is all sort of philosophical rather than technical. The code before works, and the code as I've changed it works.
Anybody else have thoughts?
-Alex
Quoted 101 lines · Alex Elder
Quoted 98 lines
Currently
ceph_pg_poolid_by_name()returns an int, which is used to encode a ceph pool id. This could be a problem because a pool id (at least in some cases) is a 64-bit value. We have a defined pool id value that represents "no pool," and that's a very sensible return value here.This patch changes
ceph_pg_poolid_by_name()to return a 64-bit pool id value, orCEPH_NOPOOLif the named pool is not found.The patch also gratuitously renames the function, separating "pool" from "id" in the name by an underscore.
Signed-off-by Alex Elder <[email protected]>--- drivers/block/rbd.c | 6 +++--- include/linux/ceph/osdmap.h | 2 +- net/ceph/osdmap.c | 14 ++++++++------ 3 files changed, 12 insertions(+), 10 deletions(-)drivers/block/rbd.c +3
-3@@ -3642,11 +3642,11 @@ static ssize_t rbd_add(struct bus_type *bus, ceph_opts =NULL ;/* rbd_dev client now owns this */ /* pick the pool */ + rc = -ENOENT ; osdc = &rbdc->client->osdc; - rc =ceph_pg_poolid_by_name (osdc->osdmap, spec->pool_name); -if (rc <0 ) + spec->pool_id =ceph_pg_pool_id_by_name (osdc->osdmap, spec->pool_name); +if (spec->pool_id ==CEPH_NOPOOL ) goto err_out_client; - spec->pool_id = (u64 ) rc; rbd_dev =rbd_dev_create (rbdc, spec);if (!rbd_dev)include/linux/ceph/osdmap.h +0
-1@@ -124,6 +124,6 @@ extern int ceph_calc_pg_primary(struct ceph_osdmap *osdmap, struct ceph_pg pgid);extern const char *ceph_pg_pool_name_by_id (struct ceph_osdmap *map,u64 id); -extern int ceph_pg_poolid_by_name(struct ceph_osdmap *map, const char*name);
+extern__u64ceph_pg_pool_id_by_name(struct ceph_osdmap *map, const char *name);#endif
net/ceph/osdmap.c +8
-6@@ -485,19 +485,21 @@ const char *ceph_pg_pool_name_by_id(struct ceph_osdmap *map, u64 id) }EXPORT_SYMBOL (ceph_pg_pool_name_by_id ); -int ceph_pg_poolid_by_name (struct ceph_osdmap *map,const char *name) +__u64 ceph_pg_pool_id_by_name (struct ceph_osdmap *map,const char *name) {struct rb_node *rbp;for (rbp =rb_first (&map->pg_pools); rbp; rbp =rb_next (rbp)) { -struct ceph_pg_pool_info *pi = - rb_entry(rbp, struct ceph_pg_pool_info, node); +struct ceph_pg_pool_info *pi; + + pi = rb_entry(rbp, struct ceph_pg_pool_info, node);if (pi->name &&strcmp (pi->name, name) ==0 ) -return pi->id; +return (__u64 ) pi->id; } -return -ENOENT ; + +return CEPH_NOPOOL ; } -EXPORT_SYMBOL (ceph_pg_poolid_by_name); +EXPORT_SYMBOL (ceph_pg_pool_id_by_name); static void __remove_pg_pool(struct rb_root *root, struct
ceph_pg_pool_info*pi)
{Signature · 6 lines
1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe ceph-devel" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 8/9] rbd: fix ceph_pg_poolid_by_name()
Quoted 16 lines · Alex Elder
Quoted 6 lines · Alex Elder
Quoted 5 lines · Sage Weil
Quoted 4 lines · Alex Elder
Quoted 3 lines · Sage Weil
Most of the code uses int64_t/__s64 for the pool id, although in a few cases we screwed up and limited it to 32 bits. In reality, that's way overkill anyway; we could have left it at 32 bits to begin with.
I just wanted to follow up on this. Sage and I discussed this today. He said that most of the other code involving pool id's assume they are signed, so a negative pool id indicates an error. Rather than introduce another new way pool id's could be (mis)interpreted I agreed to rework this patch so that it follows that basic pattern (i.e., considering pool id's signed).
Quoted 3 lines
I haven't looked at it closely yet but I still expect to have a revised patch, though it's possible I'll conclude leaving things as-is is best.
OK, I've looked at it now. If we're not going to make the change I proposed, we might as well not make a change at all.
This was trying to make an incomplete fix to a much larger problem. We'll try to get the bigger problem fixed another day.
I'm retracting this patch from consideration.
-Alex
Quoted 181 lines
Some future cleanup task can take care of unifying everything to 64 bits (or possibly 32 bits), but that's another day.
-Alex
Quoted 174 lines
Quoted 25 lines
Quoted 17 lines
The differing types representing the same abstraction are precisely the point of making this change. What really needs to happen is we need to fix *that*; that is, decide whether a pool id is 32 or 64 bits, signed or not, and then make sure it's that and only that throughout the code.
In the mean time, this change is defensive, making sure there's no uncertainty in what we're dealing with within rbd. The code will guarantee some future change won't inadvertently let a wrong-sized pool id attempt to sneak through an interface unnoticed. It may seem like overkill but this kind of bug is really hard to track down, and it's better to simply preclude it from happening.
Quoted 2 lines
My first instinct would be to change the return type to long long or s64 and avoid the use magic #defines...
Quoted 7 lines
I absolutely like using base types (like long long). But where those types are used to represent a true abstraction (like a snapshot id, or a pool id), it is the one place I think the use of typedefs and "magic #defines" is actually a real help because it makes explicit you're working with something more than an (e.g.) an int. A typedef makes obviously to the reader that it's restricted a bit (so, for example, it isn't meaningful to do math on it).
Quoted 7 lines
Completely agreed.
Quoted 2 lines
And symbolic constants make it a lot easier to search through code for special situations like this.
Okay with me. Just keep in mind that most of the other code looks for a negative
int64_treturn value (i.e., the pool id is 63 bits).I.e., if I do this here but not elsewhere we're subject to the same kind of "someday" problems... In fact, it's just a different form of mismatched type--here returning an unsigned when elsewhere a signed value is assumed.
I still like the symbolic values, or in this case, maybe a macro
ceph_pool_id_valid()or something. It just makes it easier to make other changes later, because you can easily (or maybe more precisely) search for the effects of a proposed change.I find the time spent searching through code is large enough that I tend to do things in a way that facilitates that.
Let's talk about this today and come to an agreement about the best way to resolve this.
Thanks.
-Alex
Quoted 118 lines
The reason there is a mismatch: it used to be a 32-bit value, and at one point we thought we'd do a pool per radosgw bucket and did a huge conversion to 64-bit. And missed a few places. The whole transition was ill-conceived and generally a bad idea, though; we should never have that many pools. So it's not clear it's worth the effort to spend another feature bit to fix it up.
sage
Quoted 109 lines
This stuff is all sort of philosophical rather than technical. The code before works, and the code as I've changed it works.
Anybody else have thoughts?
-Alex
Quoted 101 lines · Alex Elder
Quoted 98 lines
Currently
ceph_pg_poolid_by_name()returns an int, which is used to encode a ceph pool id. This could be a problem because a pool id (at least in some cases) is a 64-bit value. We have a defined pool id value that represents "no pool," and that's a very sensible return value here.This patch changes
ceph_pg_poolid_by_name()to return a 64-bit pool id value, orCEPH_NOPOOLif the named pool is not found.The patch also gratuitously renames the function, separating "pool" from "id" in the name by an underscore.
Signed-off-by Alex Elder <[email protected]>--- drivers/block/rbd.c | 6 +++--- include/linux/ceph/osdmap.h | 2 +- net/ceph/osdmap.c | 14 ++++++++------ 3 files changed, 12 insertions(+), 10 deletions(-)drivers/block/rbd.c +3
-3@@ -3642,11 +3642,11 @@ static ssize_t rbd_add(struct bus_type *bus, ceph_opts =NULL ;/* rbd_dev client now owns this */ /* pick the pool */ + rc = -ENOENT ; osdc = &rbdc->client->osdc; - rc =ceph_pg_poolid_by_name (osdc->osdmap, spec->pool_name); -if (rc <0 ) + spec->pool_id =ceph_pg_pool_id_by_name (osdc->osdmap, spec->pool_name); +if (spec->pool_id ==CEPH_NOPOOL ) goto err_out_client; - spec->pool_id = (u64 ) rc; rbd_dev =rbd_dev_create (rbdc, spec);if (!rbd_dev)include/linux/ceph/osdmap.h +0
-1@@ -124,6 +124,6 @@ extern int ceph_calc_pg_primary(struct ceph_osdmap *osdmap, struct ceph_pg pgid);extern const char *ceph_pg_pool_name_by_id (struct ceph_osdmap *map,u64 id); -extern int ceph_pg_poolid_by_name(struct ceph_osdmap *map, const char*name);
+extern__u64ceph_pg_pool_id_by_name(struct ceph_osdmap *map, const char *name);#endif
net/ceph/osdmap.c +8
-6@@ -485,19 +485,21 @@ const char *ceph_pg_pool_name_by_id(struct ceph_osdmap *map, u64 id) }EXPORT_SYMBOL (ceph_pg_pool_name_by_id ); -int ceph_pg_poolid_by_name (struct ceph_osdmap *map,const char *name) +__u64 ceph_pg_pool_id_by_name (struct ceph_osdmap *map,const char *name) {struct rb_node *rbp;for (rbp =rb_first (&map->pg_pools); rbp; rbp =rb_next (rbp)) { -struct ceph_pg_pool_info *pi = - rb_entry(rbp, struct ceph_pg_pool_info, node); +struct ceph_pg_pool_info *pi; + + pi = rb_entry(rbp, struct ceph_pg_pool_info, node);if (pi->name &&strcmp (pi->name, name) ==0 ) -return pi->id; +return (__u64 ) pi->id; } -return -ENOENT ; + +return CEPH_NOPOOL ; } -EXPORT_SYMBOL (ceph_pg_poolid_by_name); +EXPORT_SYMBOL (ceph_pg_pool_id_by_name); static void __remove_pg_pool(struct rb_root *root, struct
ceph_pg_pool_info*pi)
{Signature · 6 lines
1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe ceph-devel" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 9/9 libceph: socket can close in any connection state
In reply to Alex ElderA connection's socket can close for any reason, independent of the state of the connection (and without irrespective of the connection mutex). As a result, the connectino can be in pretty much any state at the time its socket is closed.
Handle those other cases at the top of con_work(). Pull this whole block of code into a separate function to reduce the clutter.
--- net/ceph/messenger.c | 47 ++++++++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 17 deletions(-)
net/ceph/messenger.c +30 -17
@@ -2273,6 +2273,35 @@ static void queue_con(struct ceph_connection *con) (void )queue_con_delay (con,0 ); } +static bool con_sock_closed (struct ceph_connection *con) +{ +if (!test_and_clear_bit (CON_FLAG_SOCK_CLOSED , &con->flags)) +return false; + +#define CASE (x) \ + case CON_STATE_ ## x: \ + con->error_msg = "socket closed (con state " #x ")"; \ + break; + +switch (con->state) { +CASE (CLOSED ); +CASE (PREOPEN ); +CASE (CONNECTING ); +CASE (NEGOTIATING ); +CASE (OPEN ); +CASE (STANDBY ); +default : +pr_warning ("%s con %p unrecognized state %lu\n" , + __func__, con, con->state); + con->error_msg ="unrecognized con state" ; +BUG (); +break ; + } +#undef CASE + +return true; +} +/* * Do some work on a connection. Drop a connection ref when we're done. */
@@ -2284,24 +2313,8 @@ static void con_work(struct work_struct *work)mutex_lock (&con->mutex); restart: -if (test_and_clear_bit (CON_FLAG_SOCK_CLOSED , &con->flags)) { -switch (con->state) { -case CON_STATE_CONNECTING : - con->error_msg ="connection failed" ; -break ; -case CON_STATE_NEGOTIATING : - con->error_msg ="negotiation failed" ; -break ; -case CON_STATE_OPEN : - con->error_msg ="socket closed" ; -break ; -default : -dout ("unrecognized con state %d\n" , (int )con->state); - con->error_msg ="unrecognized con state" ; -BUG (); - } +if (con_sock_closed (con)) goto fault; - }if (test_and_clear_bit (CON_FLAG_BACKOFF , &con->flags)) {dout ("con_work %p backing off\n" , con);
Signature · 1 line
1.7.9.5
Re: [PATCH 9/9] libceph: socket can close in any connection state
Quoted 88 lines · Alex Elder
A connection's socket can close for any reason, independent of the state of the connection (and without irrespective of the connection mutex). As a result, the connectino can be in pretty much any state at the time its socket is closed.
Handle those other cases at the top of
con_work(). Pull this whole block of code into a separate function to reduce the clutter.Signed-off-by Alex Elder <[email protected]>--- net/ceph/messenger.c | 47 ++++++++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 17 deletions(-)net/ceph/messenger.c +30
-17@@ -2273,6 +2273,35 @@ static void queue_con(struct ceph_connection *con) (void )queue_con_delay (con,0 ); } +static bool con_sock_closed (struct ceph_connection *con) +{ +if (!test_and_clear_bit (CON_FLAG_SOCK_CLOSED , &con->flags)) +return false; + +#define CASE (x) \ + case CON_STATE_ ## x: \ + con->error_msg = "socket closed (con state " #x ")"; \ + break; + +switch (con->state) { +CASE (CLOSED ); +CASE (PREOPEN ); +CASE (CONNECTING ); +CASE (NEGOTIATING ); +CASE (OPEN ); +CASE (STANDBY ); +default : +pr_warning ("%s con %p unrecognized state %lu\n" , + __func__, con, con->state); + con->error_msg ="unrecognized con state" ; +BUG (); +break ; + } +#undef CASE + +return true; +} +/* * Do some work on a connection. Drop a connection ref when we're done. */ @@ -2284,24 +2313,8 @@ static void con_work(struct work_struct *work)mutex_lock (&con->mutex); restart: -if (test_and_clear_bit (CON_FLAG_SOCK_CLOSED , &con->flags)) { -switch (con->state) { -case CON_STATE_CONNECTING : - con->error_msg ="connection failed" ; -break ; -case CON_STATE_NEGOTIATING : - con->error_msg ="negotiation failed" ; -break ; -case CON_STATE_OPEN : - con->error_msg ="socket closed" ; -break ; -default : -dout ("unrecognized con state %d\n" , (int )con->state); - con->error_msg ="unrecognized con state" ; -BUG (); - } +if (con_sock_closed (con)) goto fault; - }if (test_and_clear_bit (CON_FLAG_BACKOFF , &con->flags)) {dout ("con_work %p backing off\n" , con);Signature · 6 lines
1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe ceph-devel" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html