summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2014-09-18 17:25:20 +0000
committermav <mav@FreeBSD.org>2014-09-18 17:25:20 +0000
commit03ea8d9f92f451bbc7fbc3a4d4313c90d3f922cb (patch)
tree285d2abb3ae8104eed942525c6eb2b750b2c6ede
parentae0fd509347654ab2767ae15c219994d2071f68e (diff)
downloadFreeBSD-src-03ea8d9f92f451bbc7fbc3a4d4313c90d3f922cb.zip
FreeBSD-src-03ea8d9f92f451bbc7fbc3a4d4313c90d3f922cb.tar.gz
When updating device media size use cached cdevsw pointer.
Using pointer from the cdev directly is dangerous since we have no reference on it, and it may change any time. That caused panic if device has gone. While there, report capacity change only if it really changed. MFC after: 3 days
-rw-r--r--sys/cam/ctl/ctl_backend_block.c40
1 files changed, 20 insertions, 20 deletions
diff --git a/sys/cam/ctl/ctl_backend_block.c b/sys/cam/ctl/ctl_backend_block.c
index afd836f..787e83a 100644
--- a/sys/cam/ctl/ctl_backend_block.c
+++ b/sys/cam/ctl/ctl_backend_block.c
@@ -2278,7 +2278,9 @@ ctl_be_block_modify_file(struct ctl_be_block_lun *be_lun,
if (params->lun_size_bytes != 0) {
be_lun->size_bytes = params->lun_size_bytes;
} else {
+ vn_lock(be_lun->vn, LK_SHARED | LK_RETRY);
error = VOP_GETATTR(be_lun->vn, &vattr, curthread->td_ucred);
+ VOP_UNLOCK(be_lun->vn, 0);
if (error != 0) {
snprintf(req->error_str, sizeof(req->error_str),
"error calling VOP_GETATTR() for file %s",
@@ -2296,24 +2298,22 @@ static int
ctl_be_block_modify_dev(struct ctl_be_block_lun *be_lun,
struct ctl_lun_req *req)
{
- struct cdev *dev;
- struct cdevsw *devsw;
+ struct ctl_be_block_devdata *dev_data;
int error;
struct ctl_lun_modify_params *params;
uint64_t size_bytes;
params = &req->reqdata.modify;
- dev = be_lun->vn->v_rdev;
- devsw = dev->si_devsw;
- if (!devsw->d_ioctl) {
+ dev_data = &be_lun->backend.dev;
+ if (!dev_data->csw->d_ioctl) {
snprintf(req->error_str, sizeof(req->error_str),
"%s: no d_ioctl for device %s!", __func__,
be_lun->dev_path);
return (ENODEV);
}
- error = devsw->d_ioctl(dev, DIOCGMEDIASIZE,
+ error = dev_data->csw->d_ioctl(dev_data->cdev, DIOCGMEDIASIZE,
(caddr_t)&size_bytes, FREAD,
curthread);
if (error) {
@@ -2346,6 +2346,7 @@ ctl_be_block_modify(struct ctl_be_block_softc *softc, struct ctl_lun_req *req)
{
struct ctl_lun_modify_params *params;
struct ctl_be_block_lun *be_lun;
+ uint64_t oldsize;
int error;
params = &req->reqdata.modify;
@@ -2376,28 +2377,27 @@ ctl_be_block_modify(struct ctl_be_block_softc *softc, struct ctl_lun_req *req)
}
}
- vn_lock(be_lun->vn, LK_SHARED | LK_RETRY);
-
+ oldsize = be_lun->size_bytes;
if (be_lun->vn->v_type == VREG)
error = ctl_be_block_modify_file(be_lun, req);
else
error = ctl_be_block_modify_dev(be_lun, req);
-
- VOP_UNLOCK(be_lun->vn, 0);
-
if (error != 0)
goto bailout_error;
- be_lun->size_blocks = be_lun->size_bytes >> be_lun->blocksize_shift;
+ if (be_lun->size_bytes != oldsize) {
+ be_lun->size_blocks = be_lun->size_bytes >>
+ be_lun->blocksize_shift;
- /*
- * The maximum LBA is the size - 1.
- *
- * XXX: Note that this field is being updated without locking,
- * which might cause problems on 32-bit architectures.
- */
- be_lun->ctl_be_lun.maxlba = be_lun->size_blocks - 1;
- ctl_lun_capacity_changed(&be_lun->ctl_be_lun);
+ /*
+ * The maximum LBA is the size - 1.
+ *
+ * XXX: Note that this field is being updated without locking,
+ * which might cause problems on 32-bit architectures.
+ */
+ be_lun->ctl_be_lun.maxlba = be_lun->size_blocks - 1;
+ ctl_lun_capacity_changed(&be_lun->ctl_be_lun);
+ }
/* Tell the user the exact size we ended up using */
params->lun_size_bytes = be_lun->size_bytes;
OpenPOWER on IntegriCloud