📄 lloop.c
字号:
int error; loff_t size; if (!try_module_get(THIS_MODULE)) return -ENODEV; error = -EBUSY; if (lo->lo_state != LLOOP_UNBOUND) goto out; mapping = file->f_mapping; inode = mapping->host; error = -EINVAL; if (!S_ISREG(inode->i_mode) || inode->i_sb->s_magic != LL_SUPER_MAGIC) goto out; if (!(file->f_mode & FMODE_WRITE)) lo_flags |= LO_FLAGS_READ_ONLY; size = get_loop_size(lo, file); if ((loff_t)(sector_t)size != size) { error = -EFBIG; goto out; } /* remove all pages in cache so as dirty pages not to be existent. */ truncate_inode_pages(mapping, 0); set_device_ro(bdev, (lo_flags & LO_FLAGS_READ_ONLY) != 0); lo->lo_blocksize = CFS_PAGE_SIZE; lo->lo_device = bdev; lo->lo_flags = lo_flags; lo->lo_backing_file = file; lo->ioctl = NULL; lo->lo_sizelimit = 0; lo->old_gfp_mask = mapping_gfp_mask(mapping); mapping_set_gfp_mask(mapping, lo->old_gfp_mask & ~(__GFP_IO|__GFP_FS)); lo->lo_bio = lo->lo_biotail = NULL; /* * set queue make_request_fn, and add limits based on lower level * device */ blk_queue_make_request(lo->lo_queue, loop_make_request); lo->lo_queue->queuedata = lo; lo->lo_queue->unplug_fn = loop_unplug; /* queue parameters */ blk_queue_hardsect_size(lo->lo_queue, CFS_PAGE_SIZE); blk_queue_max_sectors(lo->lo_queue, LLOOP_MAX_SEGMENTS); blk_queue_max_phys_segments(lo->lo_queue, LLOOP_MAX_SEGMENTS); set_capacity(disks[lo->lo_number], size); bd_set_size(bdev, size << 9); set_blocksize(bdev, lo->lo_blocksize); kernel_thread(loop_thread, lo, CLONE_KERNEL); down(&lo->lo_sem); return 0; out: /* This is safe: open() is still holding a reference. */ module_put(THIS_MODULE); return error;}static int loop_clr_fd(struct lloop_device *lo, struct block_device *bdev, int count){ struct file *filp = lo->lo_backing_file; int gfp = lo->old_gfp_mask; if (lo->lo_state != LLOOP_BOUND) return -ENXIO; if (lo->lo_refcnt > count) /* we needed one fd for the ioctl */ return -EBUSY; if (filp == NULL) return -EINVAL; spin_lock_irq(&lo->lo_lock); lo->lo_state = LLOOP_RUNDOWN; if (atomic_dec_and_test(&lo->lo_pending)) up(&lo->lo_bh_mutex); spin_unlock_irq(&lo->lo_lock); down(&lo->lo_sem); lo->lo_backing_file = NULL; lo->ioctl = NULL; lo->lo_device = NULL; lo->lo_offset = 0; lo->lo_sizelimit = 0; lo->lo_flags = 0; ll_invalidate_bdev(bdev, 0); set_capacity(disks[lo->lo_number], 0); bd_set_size(bdev, 0); mapping_set_gfp_mask(filp->f_mapping, gfp); lo->lo_state = LLOOP_UNBOUND; fput(filp); /* This is safe: open() is still holding a reference. */ module_put(THIS_MODULE); return 0;}static int lo_open(struct inode *inode, struct file *file){ struct lloop_device *lo = inode->i_bdev->bd_disk->private_data; down(&lo->lo_ctl_mutex); lo->lo_refcnt++; up(&lo->lo_ctl_mutex); return 0;}static int lo_release(struct inode *inode, struct file *file){ struct lloop_device *lo = inode->i_bdev->bd_disk->private_data; down(&lo->lo_ctl_mutex); --lo->lo_refcnt; up(&lo->lo_ctl_mutex); return 0;}/* lloop device node's ioctl function. */static int lo_ioctl(struct inode *inode, struct file *unused, unsigned int cmd, unsigned long arg){ struct lloop_device *lo = inode->i_bdev->bd_disk->private_data; struct block_device *bdev = inode->i_bdev; int err = 0; down(&lloop_mutex); switch (cmd) { case LL_IOC_LLOOP_DETACH: { err = loop_clr_fd(lo, bdev, 2); if (err == 0) blkdev_put(bdev); /* grabbed in LLOOP_ATTACH */ break; } case LL_IOC_LLOOP_INFO: { __u64 ino = 0; if (lo->lo_state == LLOOP_BOUND) ino = lo->lo_backing_file->f_dentry->d_inode->i_ino; if (put_user(ino, (__u64 *)arg)) err = -EFAULT; break; } default: err = -EINVAL; break; } up(&lloop_mutex); return err;}static struct block_device_operations lo_fops = { .owner = THIS_MODULE, .open = lo_open, .release = lo_release, .ioctl = lo_ioctl,};/* dynamic iocontrol callback. * This callback is registered in lloop_init and will be called by * ll_iocontrol_call. * This is a llite regular file ioctl function. It takes the responsibility * of attaching a file, and detaching a file by a lloop's device numner. */static enum llioc_iter lloop_ioctl(struct inode *unused, struct file *file, unsigned int cmd, unsigned long arg, void *magic, int *rcp){ struct lloop_device *lo = NULL; struct block_device *bdev = NULL; int err = 0; dev_t dev; if (magic != ll_iocontrol_magic) return LLIOC_CONT; if (disks == NULL) GOTO(out1, err = -ENODEV); down(&lloop_mutex); switch (cmd) { case LL_IOC_LLOOP_ATTACH: { struct lloop_device *lo_free = NULL; int i; for (i = 0; i < max_loop; i++, lo = NULL) { lo = &loop_dev[i]; if (lo->lo_state == LLOOP_UNBOUND) { if (!lo_free) lo_free = lo; continue; } if (lo->lo_backing_file->f_dentry->d_inode == file->f_dentry->d_inode) break; } if (lo || !lo_free) GOTO(out, err = -EBUSY); lo = lo_free; dev = MKDEV(lloop_major, lo->lo_number); /* quit if the used pointer is writable */ if (put_user((long)old_encode_dev(dev), (long*)arg)) GOTO(out, err = -EFAULT); bdev = open_by_devnum(dev, file->f_mode); if (IS_ERR(bdev)) GOTO(out, err = PTR_ERR(bdev)); get_file(file); err = loop_set_fd(lo, NULL, bdev, file); if (err) { fput(file); blkdev_put(bdev); } break; } case LL_IOC_LLOOP_DETACH_BYDEV: { int minor; dev = old_decode_dev(arg); if (MAJOR(dev) != lloop_major) GOTO(out, err = -EINVAL); minor = MINOR(dev); if (minor > max_loop - 1) GOTO(out, err = -EINVAL); lo = &loop_dev[minor]; if (lo->lo_state != LLOOP_BOUND) GOTO(out, err = -EINVAL); bdev = lo->lo_device; err = loop_clr_fd(lo, bdev, 1); if (err == 0) blkdev_put(bdev); /* grabbed in LLOOP_ATTACH */ break; } default: err = -EINVAL; break; }out: up(&lloop_mutex);out1: if (rcp) *rcp = err; return LLIOC_STOP;}static int __init lloop_init(void){ int i; unsigned int cmdlist[] = { LL_IOC_LLOOP_ATTACH, LL_IOC_LLOOP_DETACH_BYDEV, }; if (max_loop < 1 || max_loop > 256) { CWARN("lloop: invalid max_loop (must be between" " 1 and 256), using default (8)\n"); max_loop = 8; } lloop_major = register_blkdev(0, "lloop"); if (lloop_major < 0) return -EIO; ll_iocontrol_magic = ll_iocontrol_register(lloop_ioctl, 2, cmdlist); if (ll_iocontrol_magic == NULL) goto out_mem1; loop_dev = kmalloc(max_loop * sizeof(struct lloop_device), GFP_KERNEL); if (!loop_dev) goto out_mem1; memset(loop_dev, 0, max_loop * sizeof(struct lloop_device)); disks = kmalloc(max_loop * sizeof(struct gendisk *), GFP_KERNEL); if (!disks) goto out_mem2; for (i = 0; i < max_loop; i++) { disks[i] = alloc_disk(1); if (!disks[i]) goto out_mem3; } init_MUTEX(&lloop_mutex); for (i = 0; i < max_loop; i++) { struct lloop_device *lo = &loop_dev[i]; struct gendisk *disk = disks[i]; memset(lo, 0, sizeof(*lo)); lo->lo_queue = blk_alloc_queue(GFP_KERNEL); if (!lo->lo_queue) goto out_mem4; init_MUTEX(&lo->lo_ctl_mutex); init_MUTEX_LOCKED(&lo->lo_sem); init_MUTEX_LOCKED(&lo->lo_bh_mutex); lo->lo_number = i; spin_lock_init(&lo->lo_lock); disk->major = lloop_major; disk->first_minor = i; disk->fops = &lo_fops; sprintf(disk->disk_name, "lloop%d", i); disk->private_data = lo; disk->queue = lo->lo_queue; } /* We cannot fail after we call this, so another loop!*/ for (i = 0; i < max_loop; i++) add_disk(disks[i]); return 0;out_mem4: while (i--) blk_put_queue(loop_dev[i].lo_queue); i = max_loop;out_mem3: while (i--) put_disk(disks[i]); kfree(disks);out_mem2: kfree(loop_dev);out_mem1: unregister_blkdev(lloop_major, "lloop"); ll_iocontrol_unregister(ll_iocontrol_magic); CERROR("lloop: ran out of memory\n"); return -ENOMEM;}static void lloop_exit(void){ int i; ll_iocontrol_unregister(ll_iocontrol_magic); for (i = 0; i < max_loop; i++) { del_gendisk(disks[i]); blk_put_queue(loop_dev[i].lo_queue); put_disk(disks[i]); } if (ll_unregister_blkdev(lloop_major, "lloop")) CWARN("lloop: cannot unregister blkdev\n"); kfree(disks); kfree(loop_dev);}module_init(lloop_init);module_exit(lloop_exit);CFS_MODULE_PARM(max_loop, "i", int, 0444, "maximum of lloop_device");MODULE_AUTHOR("Cluster File Systems, Inc. <info@clusterfs.com>");MODULE_DESCRIPTION("Lustre virtual block device");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -