Author: mav
Date: Fri Sep 11 12:50:52 2015
New Revision: 287664
URL: https://svnweb.freebsd.org/changeset/base/287664

Log:
  Reference/release devices on every I/O, rather on open/close.
  
  While this may be slower, it allows device destruction to complete,
  rather then block waiting for indefinitely long time.

Modified:
  head/sys/cam/ctl/ctl_backend_block.c

Modified: head/sys/cam/ctl/ctl_backend_block.c
==============================================================================
--- head/sys/cam/ctl/ctl_backend_block.c        Fri Sep 11 12:45:56 2015        
(r287663)
+++ head/sys/cam/ctl/ctl_backend_block.c        Fri Sep 11 12:50:52 2015        
(r287664)
@@ -126,18 +126,11 @@ typedef enum {
        CTL_BE_BLOCK_FILE
 } ctl_be_block_type;
 
-struct ctl_be_block_devdata {
-       struct cdev *cdev;
-       struct cdevsw *csw;
-       int dev_ref;
-};
-
 struct ctl_be_block_filedata {
        struct ucred *cred;
 };
 
 union ctl_be_block_bedata {
-       struct ctl_be_block_devdata dev;
        struct ctl_be_block_filedata file;
 };
 
@@ -823,16 +816,15 @@ static void
 ctl_be_block_dispatch_zvol(struct ctl_be_block_lun *be_lun,
                           struct ctl_be_block_io *beio)
 {
-       struct ctl_be_block_devdata *dev_data;
        union ctl_io *io;
+       struct cdevsw *csw;
+       struct cdev *dev;
        struct uio xuio;
        struct iovec *xiovec;
-       int flags;
-       int error, i;
+       int error, flags, i, ref;
 
        DPRINTF("entered\n");
 
-       dev_data = &be_lun->backend.dev;
        io = beio->io;
        flags = 0;
        if (ARGS(io)->flags & CTL_LLF_DPO)
@@ -865,13 +857,20 @@ ctl_be_block_dispatch_zvol(struct ctl_be
        devstat_start_transaction(beio->lun->disk_stats, &beio->ds_t0);
        mtx_unlock(&be_lun->io_lock);
 
-       if (beio->bio_cmd == BIO_READ) {
-               error = (*dev_data->csw->d_read)(dev_data->cdev, &xuio, flags);
+       csw = devvn_refthread(be_lun->vn, &dev, &ref);
+       if (csw) {
+               if (beio->bio_cmd == BIO_READ)
+                       error = csw->d_read(dev, &xuio, flags);
+               else
+                       error = csw->d_write(dev, &xuio, flags);
+               dev_relthread(dev, ref);
+       } else
+               error = ENXIO;
+
+       if (beio->bio_cmd == BIO_READ)
                SDT_PROBE(cbb, kernel, read, file_done, 0, 0, 0, 0, 0);
-       } else {
-               error = (*dev_data->csw->d_write)(dev_data->cdev, &xuio, flags);
+       else
                SDT_PROBE(cbb, kernel, write, file_done, 0, 0, 0, 0, 0);
-       }
 
        mtx_lock(&be_lun->io_lock);
        devstat_end_transaction(beio->lun->disk_stats, beio->io_len,
@@ -915,23 +914,30 @@ static void
 ctl_be_block_gls_zvol(struct ctl_be_block_lun *be_lun,
                        struct ctl_be_block_io *beio)
 {
-       struct ctl_be_block_devdata *dev_data = &be_lun->backend.dev;
        union ctl_io *io = beio->io;
+       struct cdevsw *csw;
+       struct cdev *dev;
        struct ctl_lba_len_flags *lbalen = ARGS(io);
        struct scsi_get_lba_status_data *data;
        off_t roff, off;
-       int error, status;
+       int error, ref, status;
 
        DPRINTF("entered\n");
 
+       csw = devvn_refthread(be_lun->vn, &dev, &ref);
+       if (csw == NULL) {
+               status = 0;     /* unknown up to the end */
+               off = be_lun->size_bytes;
+               goto done;
+       }
        off = roff = ((off_t)lbalen->lba) * be_lun->cbe_lun.blocksize;
-       error = (*dev_data->csw->d_ioctl)(dev_data->cdev, FIOSEEKHOLE,
-           (caddr_t)&off, FREAD, curthread);
+       error = csw->d_ioctl(dev, FIOSEEKHOLE, (caddr_t)&off, FREAD,
+           curthread);
        if (error == 0 && off > roff)
                status = 0;     /* mapped up to off */
        else {
-               error = (*dev_data->csw->d_ioctl)(dev_data->cdev, FIOSEEKDATA,
-                   (caddr_t)&off, FREAD, curthread);
+               error = csw->d_ioctl(dev, FIOSEEKDATA, (caddr_t)&off, FREAD,
+                   curthread);
                if (error == 0 && off > roff)
                        status = 1;     /* deallocated up to off */
                else {
@@ -939,7 +945,9 @@ ctl_be_block_gls_zvol(struct ctl_be_bloc
                        off = be_lun->size_bytes;
                }
        }
+       dev_relthread(dev, ref);
 
+done:
        data = (struct scsi_get_lba_status_data *)io->scsiio.kern_data_ptr;
        scsi_u64to8b(lbalen->lba, data->descr[0].addr);
        scsi_ulto4b(MIN(UINT32_MAX, off / be_lun->cbe_lun.blocksize -
@@ -955,9 +963,10 @@ ctl_be_block_flush_dev(struct ctl_be_blo
 {
        struct bio *bio;
        union ctl_io *io;
-       struct ctl_be_block_devdata *dev_data;
+       struct cdevsw *csw;
+       struct cdev *dev;
+       int ref;
 
-       dev_data = &be_lun->backend.dev;
        io = beio->io;
 
        DPRINTF("entered\n");
@@ -966,7 +975,6 @@ ctl_be_block_flush_dev(struct ctl_be_blo
        bio = g_alloc_bio();
 
        bio->bio_cmd        = BIO_FLUSH;
-       bio->bio_dev        = dev_data->cdev;
        bio->bio_offset     = 0;
        bio->bio_data       = 0;
        bio->bio_done       = ctl_be_block_biodone;
@@ -986,7 +994,15 @@ ctl_be_block_flush_dev(struct ctl_be_blo
        devstat_start_transaction(be_lun->disk_stats, &beio->ds_t0);
        mtx_unlock(&be_lun->io_lock);
 
-       (*dev_data->csw->d_strategy)(bio);
+       csw = devvn_refthread(be_lun->vn, &dev, &ref);
+       if (csw) {
+               bio->bio_dev = dev;
+               csw->d_strategy(bio);
+               dev_relthread(dev, ref);
+       } else {
+               bio->bio_error = ENXIO;
+               ctl_be_block_biodone(bio);
+       }
 }
 
 static void
@@ -995,15 +1011,17 @@ ctl_be_block_unmap_dev_range(struct ctl_
                       uint64_t off, uint64_t len, int last)
 {
        struct bio *bio;
-       struct ctl_be_block_devdata *dev_data;
        uint64_t maxlen;
+       struct cdevsw *csw;
+       struct cdev *dev;
+       int ref;
 
-       dev_data = &be_lun->backend.dev;
+       csw = devvn_refthread(be_lun->vn, &dev, &ref);
        maxlen = LONG_MAX - (LONG_MAX % be_lun->cbe_lun.blocksize);
        while (len > 0) {
                bio = g_alloc_bio();
                bio->bio_cmd        = BIO_DELETE;
-               bio->bio_dev        = dev_data->cdev;
+               bio->bio_dev        = dev;
                bio->bio_offset     = off;
                bio->bio_length     = MIN(len, maxlen);
                bio->bio_data       = 0;
@@ -1020,8 +1038,15 @@ ctl_be_block_unmap_dev_range(struct ctl_
                        beio->send_complete = 1;
                mtx_unlock(&be_lun->io_lock);
 
-               (*dev_data->csw->d_strategy)(bio);
+               if (csw) {
+                       csw->d_strategy(bio);
+               } else {
+                       bio->bio_error = ENXIO;
+                       ctl_be_block_biodone(bio);
+               }
        }
+       if (csw)
+               dev_relthread(dev, ref);
 }
 
 static void
@@ -1029,12 +1054,10 @@ ctl_be_block_unmap_dev(struct ctl_be_blo
                       struct ctl_be_block_io *beio)
 {
        union ctl_io *io;
-       struct ctl_be_block_devdata *dev_data;
        struct ctl_ptr_len_flags *ptrlen;
        struct scsi_unmap_desc *buf, *end;
        uint64_t len;
 
-       dev_data = &be_lun->backend.dev;
        io = beio->io;
 
        DPRINTF("entered\n");
@@ -1067,23 +1090,25 @@ ctl_be_block_dispatch_dev(struct ctl_be_
                          struct ctl_be_block_io *beio)
 {
        TAILQ_HEAD(, bio) queue = TAILQ_HEAD_INITIALIZER(queue);
-       int i;
        struct bio *bio;
-       struct ctl_be_block_devdata *dev_data;
+       struct cdevsw *csw;
+       struct cdev *dev;
        off_t cur_offset;
-       int max_iosize;
+       int i, max_iosize, ref;
 
        DPRINTF("entered\n");
-
-       dev_data = &be_lun->backend.dev;
+       csw = devvn_refthread(be_lun->vn, &dev, &ref);
 
        /*
         * We have to limit our I/O size to the maximum supported by the
         * backend device.  Hopefully it is MAXPHYS.  If the driver doesn't
         * set it properly, use DFLTPHYS.
         */
-       max_iosize = dev_data->cdev->si_iosize_max;
-       if (max_iosize < PAGE_SIZE)
+       if (csw) {
+               max_iosize = dev->si_iosize_max;
+               if (max_iosize < PAGE_SIZE)
+                       max_iosize = DFLTPHYS;
+       } else
                max_iosize = DFLTPHYS;
 
        cur_offset = beio->io_offset;
@@ -1101,7 +1126,7 @@ ctl_be_block_dispatch_dev(struct ctl_be_
                        KASSERT(bio != NULL, ("g_alloc_bio() failed!\n"));
 
                        bio->bio_cmd = beio->bio_cmd;
-                       bio->bio_dev = dev_data->cdev;
+                       bio->bio_dev = dev;
                        bio->bio_caller1 = beio;
                        bio->bio_length = min(cur_size, max_iosize);
                        bio->bio_offset = cur_offset;
@@ -1128,23 +1153,36 @@ ctl_be_block_dispatch_dev(struct ctl_be_
         */
        while ((bio = TAILQ_FIRST(&queue)) != NULL) {
                TAILQ_REMOVE(&queue, bio, bio_queue);
-               (*dev_data->csw->d_strategy)(bio);
+               if (csw)
+                       csw->d_strategy(bio);
+               else {
+                       bio->bio_error = ENXIO;
+                       ctl_be_block_biodone(bio);
+               }
        }
+       if (csw)
+               dev_relthread(dev, ref);
 }
 
 static uint64_t
 ctl_be_block_getattr_dev(struct ctl_be_block_lun *be_lun, const char *attrname)
 {
-       struct ctl_be_block_devdata     *dev_data = &be_lun->backend.dev;
        struct diocgattr_arg    arg;
-       int                     error;
+       struct cdevsw *csw;
+       struct cdev *dev;
+       int error, ref;
 
-       if (dev_data->csw == NULL || dev_data->csw->d_ioctl == NULL)
+       csw = devvn_refthread(be_lun->vn, &dev, &ref);
+       if (csw == NULL)
                return (UINT64_MAX);
        strlcpy(arg.name, attrname, sizeof(arg.name));
        arg.len = sizeof(arg.value.off);
-       error = dev_data->csw->d_ioctl(dev_data->cdev,
-           DIOCGATTR, (caddr_t)&arg, FREAD, curthread);
+       if (csw->d_ioctl) {
+               error = csw->d_ioctl(dev, DIOCGATTR, (caddr_t)&arg, FREAD,
+                   curthread);
+       } else
+               error = ENODEV;
+       dev_relthread(dev, ref);
        if (error != 0)
                return (UINT64_MAX);
        return (arg.value.off);
@@ -1853,22 +1891,19 @@ ctl_be_block_open_dev(struct ctl_be_bloc
 {
        struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun;
        struct ctl_lun_create_params *params;
-       struct vattr                  vattr;
+       struct cdevsw                *csw;
        struct cdev                  *dev;
-       struct cdevsw                *devsw;
        char                         *value;
-       int                           error, atomic, maxio, unmap, tmp;
+       int                           error, atomic, maxio, ref, unmap, tmp;
        off_t                         ps, pss, po, pos, us, uss, uo, uos, otmp;
 
        params = &be_lun->params;
 
        be_lun->dev_type = CTL_BE_BLOCK_DEV;
-       be_lun->backend.dev.cdev = be_lun->vn->v_rdev;
-       be_lun->backend.dev.csw = dev_refthread(be_lun->backend.dev.cdev,
-                                            &be_lun->backend.dev.dev_ref);
-       if (be_lun->backend.dev.csw == NULL)
-               panic("Unable to retrieve device switch");
-       if (strcmp(be_lun->backend.dev.csw->d_name, "zvol") == 0) {
+       csw = devvn_refthread(be_lun->vn, &dev, &ref);
+       if (csw == NULL)
+               return (ENXIO);
+       if (strcmp(csw->d_name, "zvol") == 0) {
                be_lun->dispatch = ctl_be_block_dispatch_zvol;
                be_lun->get_lba_status = ctl_be_block_gls_zvol;
                atomic = maxio = CTLBLK_MAX_IO_SIZE;
@@ -1876,7 +1911,7 @@ ctl_be_block_open_dev(struct ctl_be_bloc
                be_lun->dispatch = ctl_be_block_dispatch_dev;
                be_lun->get_lba_status = NULL;
                atomic = 0;
-               maxio = be_lun->backend.dev.cdev->si_iosize_max;
+               maxio = dev->si_iosize_max;
                if (maxio <= 0)
                        maxio = DFLTPHYS;
                if (maxio > CTLBLK_MAX_IO_SIZE)
@@ -1886,26 +1921,17 @@ ctl_be_block_open_dev(struct ctl_be_bloc
        be_lun->getattr = ctl_be_block_getattr_dev;
        be_lun->unmap = ctl_be_block_unmap_dev;
 
-       error = VOP_GETATTR(be_lun->vn, &vattr, NOCRED);
-       if (error) {
+       if (!csw->d_ioctl) {
+               dev_relthread(dev, ref);
                snprintf(req->error_str, sizeof(req->error_str),
-                        "error getting vnode attributes for device %s",
-                        be_lun->dev_path);
-               return (error);
-       }
-
-       dev = be_lun->vn->v_rdev;
-       devsw = dev->si_devsw;
-       if (!devsw->d_ioctl) {
-               snprintf(req->error_str, sizeof(req->error_str),
-                        "no d_ioctl for device %s!",
-                        be_lun->dev_path);
+                        "no d_ioctl for device %s!", be_lun->dev_path);
                return (ENODEV);
        }
 
-       error = devsw->d_ioctl(dev, DIOCGSECTORSIZE, (caddr_t)&tmp, FREAD,
+       error = csw->d_ioctl(dev, DIOCGSECTORSIZE, (caddr_t)&tmp, FREAD,
                               curthread);
        if (error) {
+               dev_relthread(dev, ref);
                snprintf(req->error_str, sizeof(req->error_str),
                         "error %d returned for DIOCGSECTORSIZE ioctl "
                         "on %s!", error, be_lun->dev_path);
@@ -1923,14 +1949,15 @@ ctl_be_block_open_dev(struct ctl_be_bloc
                if (params->blocksize_bytes % tmp == 0) {
                        cbe_lun->blocksize = params->blocksize_bytes;
                } else {
+                       dev_relthread(dev, ref);
                        snprintf(req->error_str, sizeof(req->error_str),
                                 "requested blocksize %u is not an even "
                                 "multiple of backing device blocksize %u",
                                 params->blocksize_bytes, tmp);
                        return (EINVAL);
-                       
                }
        } else if (params->blocksize_bytes != 0) {
+               dev_relthread(dev, ref);
                snprintf(req->error_str, sizeof(req->error_str),
                         "requested blocksize %u < backing device "
                         "blocksize %u", params->blocksize_bytes, tmp);
@@ -1938,9 +1965,10 @@ ctl_be_block_open_dev(struct ctl_be_bloc
        } else
                cbe_lun->blocksize = tmp;
 
-       error = devsw->d_ioctl(dev, DIOCGMEDIASIZE, (caddr_t)&otmp, FREAD,
-                              curthread);
+       error = csw->d_ioctl(dev, DIOCGMEDIASIZE, (caddr_t)&otmp, FREAD,
+                            curthread);
        if (error) {
+               dev_relthread(dev, ref);
                snprintf(req->error_str, sizeof(req->error_str),
                         "error %d returned for DIOCGMEDIASIZE "
                         " ioctl on %s!", error,
@@ -1950,6 +1978,7 @@ ctl_be_block_open_dev(struct ctl_be_bloc
 
        if (params->lun_size_bytes != 0) {
                if (params->lun_size_bytes > otmp) {
+                       dev_relthread(dev, ref);
                        snprintf(req->error_str, sizeof(req->error_str),
                                 "requested LUN size %ju > backing device "
                                 "size %ju",
@@ -1965,13 +1994,13 @@ ctl_be_block_open_dev(struct ctl_be_bloc
        cbe_lun->maxlba = (be_lun->size_blocks == 0) ?
            0 : (be_lun->size_blocks - 1);
 
-       error = devsw->d_ioctl(dev, DIOCGSTRIPESIZE,
-                              (caddr_t)&ps, FREAD, curthread);
+       error = csw->d_ioctl(dev, DIOCGSTRIPESIZE, (caddr_t)&ps, FREAD,
+           curthread);
        if (error)
                ps = po = 0;
        else {
-               error = devsw->d_ioctl(dev, DIOCGSTRIPEOFFSET,
-                                      (caddr_t)&po, FREAD, curthread);
+               error = csw->d_ioctl(dev, DIOCGSTRIPEOFFSET, (caddr_t)&po,
+                   FREAD, curthread);
                if (error)
                        po = 0;
        }
@@ -2016,8 +2045,8 @@ ctl_be_block_open_dev(struct ctl_be_bloc
 
                strlcpy(arg.name, "GEOM::candelete", sizeof(arg.name));
                arg.len = sizeof(arg.value.i);
-               error = devsw->d_ioctl(dev, DIOCGATTR,
-                   (caddr_t)&arg, FREAD, curthread);
+               error = csw->d_ioctl(dev, DIOCGATTR, (caddr_t)&arg, FREAD,
+                   curthread);
                unmap = (error == 0) ? arg.value.i : 0;
        }
        value = ctl_get_opt(&cbe_lun->options, "unmap");
@@ -2028,6 +2057,7 @@ ctl_be_block_open_dev(struct ctl_be_bloc
        else
                cbe_lun->flags &= ~CTL_LUN_FLAG_UNMAP;
 
+       dev_relthread(dev, ref);
        return (0);
 }
 
@@ -2038,24 +2068,6 @@ ctl_be_block_close(struct ctl_be_block_l
        int flags;
 
        if (be_lun->vn) {
-               switch (be_lun->dev_type) {
-               case CTL_BE_BLOCK_DEV:
-                       if (be_lun->backend.dev.csw) {
-                               dev_relthread(be_lun->backend.dev.cdev,
-                                             be_lun->backend.dev.dev_ref);
-                               be_lun->backend.dev.csw  = NULL;
-                               be_lun->backend.dev.cdev = NULL;
-                       }
-                       break;
-               case CTL_BE_BLOCK_FILE:
-                       break;
-               case CTL_BE_BLOCK_NONE:
-                       break;
-               default:
-                       panic("Unexpected backend type.");
-                       break;
-               }
-
                flags = FREAD;
                if ((cbe_lun->flags & CTL_LUN_FLAG_READONLY) == 0)
                        flags |= FWRITE;
@@ -2553,21 +2565,25 @@ ctl_be_block_modify_dev(struct ctl_be_bl
                        struct ctl_lun_req *req)
 {
        struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun;
-       struct ctl_be_block_devdata *dev_data;
-       int error;
        struct ctl_lun_create_params *params = &be_lun->params;
+       struct cdevsw *csw;
+       struct cdev *dev;
        uint64_t size_bytes;
+       int error, ref;
 
-       dev_data = &be_lun->backend.dev;
-       if (!dev_data->csw->d_ioctl) {
+       csw = devvn_refthread(be_lun->vn, &dev, &ref);
+       if (csw == NULL)
+               return (ENXIO);
+       if (csw->d_ioctl == NULL) {
+               dev_relthread(dev, ref);
                snprintf(req->error_str, sizeof(req->error_str),
                         "no d_ioctl for device %s!", be_lun->dev_path);
                return (ENODEV);
        }
 
-       error = dev_data->csw->d_ioctl(dev_data->cdev, DIOCGMEDIASIZE,
-                              (caddr_t)&size_bytes, FREAD,
-                              curthread);
+       error = csw->d_ioctl(dev, DIOCGMEDIASIZE, (caddr_t)&size_bytes, FREAD,
+           curthread);
+       dev_relthread(dev, ref);
        if (error) {
                snprintf(req->error_str, sizeof(req->error_str),
                         "error %d returned for DIOCGMEDIASIZE ioctl "
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to