static struct ssd_info *_alloc_ssd(char *path)
{
	struct ssd_info *ssd;
	struct block_device *const bdev = lookup_bdev(path);
	dev_t dev_t = 0;
	if (IS_ERR(bdev))
		return NULL;
	DBG("bdev %p found for path %s.\n", bdev, path);
	dev_t = bdev->bd_dev;
	bdput(bdev);

	ssd = _search_ssd(dev_t);
	if (NULL != ssd)
		return NULL;	/* EEXIST */

	ssd = kzalloc(sizeof(*ssd), GFP_NOWAIT);
	if (unlikely(NULL == ssd))
		return NULL;	/* ENOMEM */

	strcpy(ssd->path, path);
	ssd->dev_t = dev_t;
	atomic_set(&ssd->nr_ref, 0);
	INIT_LIST_HEAD(&ssd->list);

	DBG("Created ssd struct ptr=%p.\n", ssd);

	return ssd;
}
示例#2
0
/**
 * Resize disk.
 *
 * @gd disk.
 * @new_size new size [logical block].
 *
 * RETURN:
 *   true in success, or false.
 */
bool resize_disk(struct gendisk *gd, u64 new_size)
{
	struct block_device *bdev;
	u64 old_size;

	ASSERT(gd);

	old_size = get_capacity(gd);
	if (old_size == new_size) {
		return true;
	}
	set_capacity(gd, new_size);

	bdev = bdget_disk(gd, 0);
	if (!bdev) {
		LOGe("bdget_disk failed.\n");
		return false;
	}
	mutex_lock(&bdev->bd_mutex);
	if (old_size > new_size) {
		LOGn("Shrink disk should discard block cache.\n");
		check_disk_size_change(gd, bdev);
		/* This should be implemented in check_disk_size_change(). */
		bdev->bd_invalidated = 0;
	} else {
		i_size_write(bdev->bd_inode,
			(loff_t)new_size * LOGICAL_BLOCK_SIZE);
	}
	mutex_unlock(&bdev->bd_mutex);
	bdput(bdev);
	return true;
}
示例#3
0
ssize_t diskdump_sysfs_show_disk(struct gendisk *disk, char *buf)
{
	struct block_device *bdev;
	int part, tmp, len = 0, maxlen = 1024;
	char* p = buf; 
	char name[BDEVNAME_SIZE];

	if (!dump_ops || !dump_ops->find_dump)
		return 0;

	if (!disk->part)
		return 0;

	/* print device */
	down(&dump_ops_mutex);
	for (part = 0; part < disk->minors; part++) {
		bdev = bdget_disk(disk, part);
		if (dump_ops->find_dump(bdev)) {
			tmp = sprintf(p, "%s\n", bdevname(bdev, name));
			len += tmp;
			p += tmp;
		}
		bdput(bdev);
		if(len >= maxlen)
			break;
	}
	up(&dump_ops_mutex);

	return len;
}
示例#4
0
/*
 * look up a superblock on which quota ops will be performed
 * - use the name of a block device to find the superblock thereon
 */
static struct super_block *quotactl_block(const char __user *special, int cmd)
{
#ifdef CONFIG_BLOCK
	struct block_device *bdev;
	struct super_block *sb;
	char *tmp = getname(special);

	if (IS_ERR(tmp))
		return ERR_CAST(tmp);
	bdev = lookup_bdev(tmp);
	putname(tmp);
	if (IS_ERR(bdev))
		return ERR_CAST(bdev);
	if (quotactl_cmd_write(cmd))
		sb = get_super_thawed(bdev);
	else
		sb = get_super(bdev);
	bdput(bdev);
	if (!sb)
		return ERR_PTR(-ENODEV);

	return sb;
#else
	return ERR_PTR(-ENODEV);
#endif
}
示例#5
0
文件: dm.c 项目: waterice/Test-Git
/*
 * Functions to lock and unlock any filesystem running on the
 * device.
 */
static int lock_fs(struct mapped_device *md)
{
	int r = -ENOMEM;

	md->frozen_bdev = bdget_disk(md->disk, 0);
	if (!md->frozen_bdev) {
		DMWARN("bdget failed in lock_fs");
		goto out;
	}

	WARN_ON(md->frozen_sb);

	md->frozen_sb = freeze_bdev(md->frozen_bdev);
	if (IS_ERR(md->frozen_sb)) {
		r = PTR_ERR(md->frozen_sb);
		goto out_bdput;
	}

	/* don't bdput right now, we don't want the bdev
	 * to go away while it is locked.  We'll bdput
	 * in unlock_fs
	 */
	return 0;

out_bdput:
	bdput(md->frozen_bdev);
	md->frozen_sb = NULL;
	md->frozen_bdev = NULL;
out:
	return r;
}
示例#6
0
/* this function performs work that has been deferred until sleeping is OK
 */
void
aoecmd_sleepwork(struct work_struct *work)
{
	struct aoedev *d = container_of(work, struct aoedev, work);

	if (d->flags & DEVFL_GDALLOC)
		aoeblk_gdalloc(d);

	if (d->flags & DEVFL_NEWSIZE) {
		struct block_device *bd;
		unsigned long flags;
		u64 ssize;

		ssize = d->gd->capacity;
		bd = bdget_disk(d->gd, 0);

		if (bd) {
			mutex_lock(&bd->bd_inode->i_mutex);
			i_size_write(bd->bd_inode, (loff_t)ssize<<9);
			mutex_unlock(&bd->bd_inode->i_mutex);
			bdput(bd);
		}
		spin_lock_irqsave(&d->lock, flags);
		d->flags |= DEVFL_UP;
		d->flags &= ~DEVFL_NEWSIZE;
		spin_unlock_irqrestore(&d->lock, flags);
	}
}
示例#7
0
文件: dm.c 项目: waterice/Test-Git
static void unlock_fs(struct mapped_device *md)
{
	thaw_bdev(md->frozen_bdev, md->frozen_sb);
	bdput(md->frozen_bdev);

	md->frozen_sb = NULL;
	md->frozen_bdev = NULL;
}
示例#8
0
/*
 * Convert a device path to a dev_t.
 */
static int lookup_device(const char *path, dev_t *dev)
{
	struct block_device *bdev = lookup_bdev(path);
	if (IS_ERR(bdev))
		return PTR_ERR(bdev);
	*dev = bdev->bd_dev;
	bdput(bdev);
	return 0;
}
static ssize_t reset_store(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t len)
{
	int ret;
	unsigned short do_reset;
	struct zram *zram;
	struct block_device *bdev;

	zram = dev_to_zram(dev);
	bdev = bdget_disk(zram->disk, 0);

	if (!bdev)
		return -ENOMEM;

	/* Do not reset an active device! */
	if (bdev->bd_holders) {
		ret = -EBUSY;
		goto out;
	}

	ret = kstrtou16(buf, 10, &do_reset);
	if (ret)
		goto out;

	if (!do_reset) {
		ret = -EINVAL;
		goto out;
	}

	/* Make sure all pending I/O is finished */
	fsync_bdev(bdev);
	bdput(bdev);

	down_write(&zram->init_lock);
	if (zram->init_done)
		__zram_reset_device(zram);
	up_write(&zram->init_lock);

	return len;

out:
	bdput(bdev);
	return ret;
}
示例#10
0
/*
 * Find the swap type that corresponds to given device (if any).
 *
 * @offset - number of the PAGE_SIZE-sized block of the device, starting
 * from 0, in which the swap header is expected to be located.
 *
 * This is needed for the suspend to disk (aka swsusp).
 */
int swap_type_of(dev_t device, sector_t offset, struct block_device **bdev_p)
{
	struct block_device *bdev = NULL;
	int i;

	if (device)
		bdev = bdget(device);

	spin_lock(&swap_lock);
	for (i = 0; i < nr_swapfiles; i++) {
		struct swap_info_struct *sis = swap_info + i;

		if (!(sis->flags & SWP_WRITEOK))
			continue;

		if (!bdev) {
			if (bdev_p)
				*bdev_p = sis->bdev;

			spin_unlock(&swap_lock);
			return i;
		}
		if (bdev == sis->bdev) {
			struct swap_extent *se;

			se = list_entry(sis->extent_list.next,
					struct swap_extent, list);
			if (se->start_block == offset) {
				if (bdev_p)
					*bdev_p = sis->bdev;

				spin_unlock(&swap_lock);
				bdput(bdev);
				return i;
			}
		}
	}
	spin_unlock(&swap_lock);
	if (bdev)
		bdput(bdev);

	return -ENODEV;
}
示例#11
0
文件: dm.c 项目: wxlong/Test
static int __unlock_fs(struct mapped_device *md)
{
	struct block_device *bdev;

	if (!test_and_clear_bit(DMF_FS_LOCKED, &md->flags))
		return 0;

	bdev = bdget_disk(md->disk, 0);
	if (!bdev) {
		DMWARN("bdget failed in __unlock_fs");
		return -ENOMEM;
	}

	thaw_bdev(bdev, md->frozen_sb);
	md->frozen_sb = NULL;
	bdput(bdev);
	bdput(bdev);
	return 0;
}
示例#12
0
文件: devio.c 项目: 8l/FUZIX
void bufsync(void)
{
	bufptr bp;

	/* FIXME: this can generate a lot of d_flush calls when you have
	   plenty of buffers */
	for (bp = bufpool; bp < bufpool_end; ++bp) {
		if ((bp->bf_dev != NO_DEVICE) && bp->bf_dirty)
		        bdput(bp);
	}
}
示例#13
0
文件: devio.c 项目: 8l/FUZIX
void bdrop(uint16_t dev)
{
	bufptr bp;

	for (bp = bufpool; bp < bufpool_end; ++bp) {
		if (bp->bf_dev == dev) {
		        bdput(bp);
		        bp->bf_dev = NO_DEVICE;
                }
	}
}
示例#14
0
文件: tbio.c 项目: ystk/debian-ltp
static void tbio_exit(void)
{
	if(Device.bdev) {
		invalidate_bdev(Device.bdev,1);
		bdput(Device.bdev);
	}

	del_gendisk(Device.gd);
	put_disk(Device.gd);
	unregister_blkdev(TBIO_MAJOR , "tbio");
	vfree(Device.data);
}
示例#15
0
void ssd_unregister(char *path)
{
	struct block_device *const bdev = lookup_bdev(path);
	dev_t dev_t = 0;
	DBG("bdev %p found for path %s.\n", bdev, path);
	if (IS_ERR(bdev))
		return;
	dev_t = bdev->bd_dev;
	bdput(bdev);
	mutex_lock(&gctx.ctl_mtx);
	_ssd_remove(_search_ssd(dev_t));
	mutex_unlock(&gctx.ctl_mtx);
}
示例#16
0
文件: dm.c 项目: wxlong/Test
static void __set_size(struct gendisk *disk, sector_t size)
{
	struct block_device *bdev;

	set_capacity(disk, size);
	bdev = bdget_disk(disk, 0);
	if (bdev) {
		down(&bdev->bd_inode->i_sem);
		i_size_write(bdev->bd_inode, (loff_t)size << SECTOR_SHIFT);
		up(&bdev->bd_inode->i_sem);
		bdput(bdev);
	}
}
示例#17
0
文件: zvol.c 项目: alek-p/zfs
static void
zvol_size_changed(zvol_state_t *zv, uint64_t volsize)
{
	struct block_device *bdev;

	bdev = bdget_disk(zv->zv_disk, 0);
	if (bdev == NULL)
		return;
	set_capacity(zv->zv_disk, volsize >> 9);
	zv->zv_volsize = volsize;
	check_disk_size_change(zv->zv_disk, bdev);

	bdput(bdev);
}
示例#18
0
/*
 * performs formatting of _device_ according to _fdata_
 * Note: The discipline's format_function is assumed to deliver formatting
 * commands to format a single unit of the device. In terms of the ECKD
 * devices this means CCWs are generated to format a single track.
 */
static int dasd_format(struct dasd_block *block, struct format_data_t *fdata)
{
    struct dasd_ccw_req *cqr;
    struct dasd_device *base;
    int rc;

    base = block->base;
    if (base->discipline->format_device == NULL)
        return -EPERM;

    if (base->state != DASD_STATE_BASIC) {
        DEV_MESSAGE(KERN_WARNING, base, "%s",
                    "dasd_format: device is not disabled! ");
        return -EBUSY;
    }

    DBF_DEV_EVENT(DBF_NOTICE, base,
                  "formatting units %d to %d (%d B blocks) flags %d",
                  fdata->start_unit,
                  fdata->stop_unit, fdata->blksize, fdata->intensity);

    /* Since dasdfmt keeps the device open after it was disabled,
     * there still exists an inode for this device.
     * We must update i_blkbits, otherwise we might get errors when
     * enabling the device later.
     */
    if (fdata->start_unit == 0) {
        struct block_device *bdev = bdget_disk(block->gdp, 0);
        bdev->bd_inode->i_blkbits = blksize_bits(fdata->blksize);
        bdput(bdev);
    }

    while (fdata->start_unit <= fdata->stop_unit) {
        cqr = base->discipline->format_device(base, fdata);
        if (IS_ERR(cqr))
            return PTR_ERR(cqr);
        rc = dasd_sleep_on_interruptible(cqr);
        dasd_sfree_request(cqr, cqr->memdev);
        if (rc) {
            if (rc != -ERESTARTSYS)
                DEV_MESSAGE(KERN_ERR, base,
                            " Formatting of unit %d failed "
                            "with rc = %d",
                            fdata->start_unit, rc);
            return rc;
        }
        fdata->start_unit++;
    }
    return 0;
}
示例#19
0
/*
 * Ensure the zap is flushed then inform the VFS of the capacity change.
 */
static int
zvol_update_volsize(zvol_state_t *zv, uint64_t volsize, objset_t *os)
{
	struct block_device *bdev;
	dmu_tx_t *tx;
	int error;

	ASSERT(MUTEX_HELD(&zvol_state_lock));

	tx = dmu_tx_create(os);
	dmu_tx_hold_zap(tx, ZVOL_ZAP_OBJ, TRUE, NULL);
	error = dmu_tx_assign(tx, TXG_WAIT);
	if (error) {
		dmu_tx_abort(tx);
		return (error);
	}

	error = zap_update(os, ZVOL_ZAP_OBJ, "size", 8, 1,
	    &volsize, tx);
	dmu_tx_commit(tx);

	if (error)
		return (error);

	error = dmu_free_long_range(os,
	    ZVOL_OBJ, volsize, DMU_OBJECT_END);
	if (error)
		return (error);

	bdev = bdget_disk(zv->zv_disk, 0);
	if (!bdev)
		return (EIO);
/*
 * 2.6.28 API change
 * Added check_disk_size_change() helper function.
 */
#ifdef HAVE_CHECK_DISK_SIZE_CHANGE
	set_capacity(zv->zv_disk, volsize >> 9);
	zv->zv_volsize = volsize;
	check_disk_size_change(zv->zv_disk, bdev);
#else
	zv->zv_volsize = volsize;
	zv->zv_changed = 1;
	(void) check_disk_change(bdev);
#endif /* HAVE_CHECK_DISK_SIZE_CHANGE */

	bdput(bdev);

	return (0);
}
示例#20
0
/*
 * performs formatting of _device_ according to _fdata_
 * Note: The discipline's format_function is assumed to deliver formatting
 * commands to format a single unit of the device. In terms of the ECKD
 * devices this means CCWs are generated to format a single track.
 */
static int dasd_format(struct dasd_block *block, struct format_data_t *fdata)
{
	struct dasd_ccw_req *cqr;
	struct dasd_device *base;
	int rc;

	base = block->base;
	if (base->discipline->format_device == NULL)
		return -EPERM;

	if (base->state != DASD_STATE_BASIC) {
		pr_warning("%s: The DASD cannot be formatted while it is "
			   "enabled\n",  dev_name(&base->cdev->dev));
		return -EBUSY;
	}

	DBF_DEV_EVENT(DBF_NOTICE, base,
		      "formatting units %u to %u (%u B blocks) flags %u",
		      fdata->start_unit,
		      fdata->stop_unit, fdata->blksize, fdata->intensity);

	/* Since dasdfmt keeps the device open after it was disabled,
	 * there still exists an inode for this device.
	 * We must update i_blkbits, otherwise we might get errors when
	 * enabling the device later.
	 */
	if (fdata->start_unit == 0) {
		struct block_device *bdev = bdget_disk(block->gdp, 0);
		bdev->bd_inode->i_blkbits = blksize_bits(fdata->blksize);
		bdput(bdev);
	}

	while (fdata->start_unit <= fdata->stop_unit) {
		cqr = base->discipline->format_device(base, fdata);
		if (IS_ERR(cqr))
			return PTR_ERR(cqr);
		rc = dasd_sleep_on_interruptible(cqr);
		dasd_sfree_request(cqr, cqr->memdev);
		if (rc) {
			if (rc != -ERESTARTSYS)
				pr_err("%s: Formatting unit %d failed with "
				       "rc=%d\n", dev_name(&base->cdev->dev),
				       fdata->start_unit, rc);
			return rc;
		}
		fdata->start_unit++;
	}
	return 0;
}
示例#21
0
static struct block_device *stackbd_bdev_open(char dev_path[])
{
    /* Open underlying device */
    struct block_device *bdev_raw = lookup_bdev(dev_path);
    printk("Opened %s\n", dev_path);

    if (IS_ERR(bdev_raw))
    {
        printk("stackbd: error opening raw device <%lu>\n", PTR_ERR(bdev_raw));
        return NULL;
    }

    if (!bdget(bdev_raw->bd_dev))
    {
        printk("stackbd: error bdget()\n");
        return NULL;
    }


    /* FIXME:VER */
    /*    if (blkdev_get(bdev_raw, STACKBD_BDEV_MODE, &stackbd))*/
    if (blkdev_get(bdev_raw, STACKBD_BDEV_MODE))
    {
        printk("stackbd: error blkdev_get()\n");
        bdput(bdev_raw);
        return NULL;
    }

    if (bd_claim(bdev_raw, &stackbd)) {
        printk("stackbd: error bd_claim()\n");
        bdput(bdev_raw);
        return NULL;
    }

    return bdev_raw;
}
示例#22
0
文件: dm.c 项目: ena30/snake-os
static void free_dev(struct mapped_device *md)
{
	unsigned int minor = md->disk->first_minor;

	if (md->suspended_bdev) {
		thaw_bdev(md->suspended_bdev, NULL);
		bdput(md->suspended_bdev);
	}
	mempool_destroy(md->tio_pool);
	mempool_destroy(md->io_pool);
	del_gendisk(md->disk);
	free_minor(minor);
	put_disk(md->disk);
	blk_put_queue(md->queue);
	kfree(md);
}
示例#23
0
static void __exit stackbd_exit(void)
{
    printk("stackbd: exit\n");

    if (stackbd.is_active)
    {
        kthread_stop(stackbd.thread);
        blkdev_put(stackbd.bdev_raw, STACKBD_BDEV_MODE);
        bdput(stackbd. bdev_raw);
    }

	del_gendisk(stackbd.gd);
	put_disk(stackbd.gd);
	unregister_blkdev(major_num, STACKBD_NAME);
	blk_cleanup_queue(stackbd.queue);
}
示例#24
0
文件: dm.c 项目: 3sOx/asuswrt-merlin
int dm_resume(struct mapped_device *md)
{
	int r = -EINVAL;
	struct bio *def;
	struct dm_table *map = NULL;

	down(&md->suspend_lock);
	if (!dm_suspended(md))
		goto out;

	map = dm_get_table(md);
	if (!map || !dm_table_get_size(map))
		goto out;

	r = dm_table_resume_targets(map);
	if (r)
		goto out;

	down_write(&md->io_lock);
	clear_bit(DMF_BLOCK_IO, &md->flags);

	def = bio_list_get(&md->deferred);
	__flush_deferred_io(md, def);
	up_write(&md->io_lock);

	unlock_fs(md);

	if (md->suspended_bdev) {
		bdput(md->suspended_bdev);
		md->suspended_bdev = NULL;
	}

	clear_bit(DMF_SUSPENDED, &md->flags);

	dm_table_unplug_all(map);

	kobject_uevent(&md->disk->kobj, KOBJ_CHANGE);

	r = 0;

out:
	dm_table_put(map);
	up(&md->suspend_lock);

	return r;
}
示例#25
0
文件: zvol.c 项目: alek-p/zfs
/*
 * Given a path, return TRUE if path is a ZVOL.
 */
boolean_t
zvol_is_zvol(const char *device)
{
	struct block_device *bdev;
	unsigned int major;

	bdev = vdev_lookup_bdev(device);
	if (IS_ERR(bdev))
		return (B_FALSE);

	major = MAJOR(bdev->bd_dev);
	bdput(bdev);

	if (major == zvol_major)
		return (B_TRUE);

	return (B_FALSE);
}
示例#26
0
/*
 * Ensure the zap is flushed then inform the VFS of the capacity change.
 */
static int
zvol_update_volsize(zvol_state_t *zv, uint64_t volsize)
{
	struct block_device *bdev;
	dmu_tx_t *tx;
	int error;

	ASSERT(MUTEX_HELD(&zvol_state_lock));

	tx = dmu_tx_create(zv->zv_objset);
	dmu_tx_hold_zap(tx, ZVOL_ZAP_OBJ, TRUE, NULL);
	error = dmu_tx_assign(tx, TXG_WAIT);
	if (error) {
		dmu_tx_abort(tx);
		return (error);
	}

	error = zap_update(zv->zv_objset, ZVOL_ZAP_OBJ, "size", 8, 1,
	    &volsize, tx);
	dmu_tx_commit(tx);

	if (error)
		return (error);

	error = dmu_free_long_range(zv->zv_objset,
	    ZVOL_OBJ, volsize, DMU_OBJECT_END);
	if (error)
		return (error);

	zv->zv_volsize = volsize;
	zv->zv_changed = 1;

	bdev = bdget_disk(zv->zv_disk, 0);
	if (!bdev)
		return EIO;

	error = check_disk_change(bdev);
	ASSERT3U(error, !=, 0);
	bdput(bdev);

	return (0);
}
示例#27
0
static void free_dev(struct mapped_device *md)
{
	int minor = md->disk->first_minor;

	if (md->suspended_bdev) {
		thaw_bdev(md->suspended_bdev, NULL);
		bdput(md->suspended_bdev);
	}
	mempool_destroy(md->tio_pool);
	mempool_destroy(md->io_pool);
	del_gendisk(md->disk);
	free_minor(minor);

	spin_lock(&_minor_lock);
	md->disk->private_data = NULL;
	spin_unlock(&_minor_lock);

	put_disk(md->disk);
	blk_cleanup_queue(md->queue);
	module_put(THIS_MODULE);
	kfree(md);
}
示例#28
0
int _lkl_disk_del_disk(__kernel_dev_t devt)
{
	struct block_device *bdev;
	struct gendisk *gd;
	int ret = 0, partno;

	bdev = bdget(devt);
	if (!bdev)
		return -EINVAL;

	gd = get_gendisk(new_decode_dev(devt), &partno);
	if (!gd || gd->major != major) {
		ret = -EINVAL;
		goto out;
	}

	del_gendisk(gd);

out:
	bdput(bdev);
	return ret;
}
示例#29
0
int set_blocksize(kdev_t dev, int size)
{
	int oldsize;
	struct block_device *bdev;

	/* Size must be a power of two, and between 512 and PAGE_SIZE */
	if (size > PAGE_SIZE || size < 512 || (size & (size-1)))
		return -EINVAL;

	/* Size cannot be smaller than the size supported by the device */
	if (size < get_hardsect_size(dev))
		return -EINVAL;

	/* No blocksize array? Implies hardcoded BLOCK_SIZE */
	if (!blksize_size[MAJOR(dev)]) {
		if (size == BLOCK_SIZE)
			return 0;
		return -EINVAL;
	}

	oldsize = blksize_size[MAJOR(dev)][MINOR(dev)];
	if (oldsize == size)
		return 0;

	if (!oldsize && size == BLOCK_SIZE) {
		blksize_size[MAJOR(dev)][MINOR(dev)] = size;
		return 0;
	}

	/* Ok, we're actually changing the blocksize.. */
	bdev = bdget(dev);
	sync_buffers(dev, 2);
	blksize_size[MAJOR(dev)][MINOR(dev)] = size;
	bdev->bd_inode->i_blkbits = blksize_bits(size);
	kill_bdev(bdev);
	bdput(bdev);
	return 0;
}
示例#30
0
static int stackbd_start(char dev_path[])
{
    unsigned max_sectors;

    if (!(stackbd.bdev_raw = stackbd_bdev_open(dev_path)))
        return -EFAULT;

    /* Set up our internal device */
    stackbd.capacity = get_capacity(stackbd.bdev_raw->bd_disk);
    printk("stackbd: Device real capacity: %llu\n", (unsigned long long) stackbd.capacity);

    set_capacity(stackbd.gd, stackbd.capacity);

    max_sectors = queue_max_hw_sectors(bdev_get_queue(stackbd.bdev_raw));
    blk_queue_max_hw_sectors(stackbd.queue, max_sectors);
    printk("stackbd: Max sectors: %u\n", max_sectors);

    stackbd.thread = kthread_create(stackbd_threadfn, NULL,
           stackbd.gd->disk_name);
    if (IS_ERR(stackbd.thread))
    {
        printk("stackbd: error kthread_create <%lu>\n",
               PTR_ERR(stackbd.thread));
        goto error_after_bdev;
    }

    printk("stackbd: done initializing successfully\n");
    stackbd.is_active = 1;
    wake_up_process(stackbd.thread);

    return 0;

error_after_bdev:
    blkdev_put(stackbd.bdev_raw, STACKBD_BDEV_MODE);
    bdput(stackbd.bdev_raw);

    return -EFAULT;
}