📄 loop.c-2.2.original
字号:
lo->lo_device = inode->i_rdev; lo->lo_flags = 0; /* Backed by a block device - don't need to hold onto a file structure */ lo->lo_backing_file = NULL; } else if (S_ISREG(inode->i_mode)) { if (!inode->i_op->bmap) { printk(KERN_ERR "loop: device has no block access/not implemented\n"); goto out_putf; } /* Backed by a regular file - we need to hold onto a file structure for this file. We'll use it to write to blocks that are not already present in a sparse file. We create a new file structure based on the one passed to us via 'arg'. This is to avoid changing the file structure that the caller is using */ lo->lo_device = inode->i_dev; lo->lo_flags = LO_FLAGS_DO_BMAP; error = -ENFILE; lo->lo_backing_file = get_empty_filp(); if (lo->lo_backing_file) { lo->lo_backing_file->f_mode = file->f_mode; lo->lo_backing_file->f_pos = file->f_pos; lo->lo_backing_file->f_flags = file->f_flags; lo->lo_backing_file->f_owner = file->f_owner; lo->lo_backing_file->f_dentry = file->f_dentry; lo->lo_backing_file->f_op = file->f_op; lo->lo_backing_file->private_data = file->private_data; error = get_write_access(inode); if (error) { put_filp(lo->lo_backing_file); lo->lo_backing_file = NULL; } } } if (error) goto out_putf; if (IS_RDONLY (inode) || is_read_only(lo->lo_device)) { lo->lo_flags |= LO_FLAGS_READ_ONLY; set_device_ro(dev, 1); } else { invalidate_inode_pages (inode); set_device_ro(dev, 0); } lo->lo_dentry = dget(file->f_dentry); lo->transfer = NULL; lo->ioctl = NULL; figure_loop_size(lo);out_putf: fput(file);out: if (error) MOD_DEC_USE_COUNT; return error;}static int loop_release_xfer(struct loop_device *lo){ int err = 0; if (lo->lo_encrypt_type) { struct loop_func_table *xfer= xfer_funcs[lo->lo_encrypt_type]; if (xfer && xfer->release) err = xfer->release(lo); if (xfer && xfer->unlock) xfer->unlock(lo); lo->lo_encrypt_type = 0; } return err;}static int loop_init_xfer(struct loop_device *lo, int type,struct loop_info *i){ int err = 0; if (type) { struct loop_func_table *xfer = xfer_funcs[type]; if (xfer->init) err = xfer->init(lo, i); if (!err) { lo->lo_encrypt_type = type; if (xfer->lock) xfer->lock(lo); } } return err;} static int loop_clr_fd(struct loop_device *lo, kdev_t dev){ struct dentry *dentry = lo->lo_dentry; if (!dentry) return -ENXIO; if (lo->lo_refcnt > 1) /* we needed one fd for the ioctl */ return -EBUSY; if (S_ISBLK(dentry->d_inode->i_mode)) blkdev_release (dentry->d_inode); lo->lo_dentry = NULL; if (lo->lo_backing_file != NULL) { fput(lo->lo_backing_file); lo->lo_backing_file = NULL; } else { dput(dentry); } loop_release_xfer(lo); lo->transfer = NULL; lo->ioctl = NULL; lo->lo_device = 0; lo->lo_encrypt_type = 0; lo->lo_offset = 0; lo->lo_encrypt_key_size = 0; memset(lo->lo_encrypt_key, 0, LO_KEY_SIZE); memset(lo->lo_name, 0, LO_NAME_SIZE); loop_sizes[lo->lo_number] = 0; invalidate_buffers(dev); MOD_DEC_USE_COUNT; return 0;}static int loop_set_status(struct loop_device *lo, struct loop_info *arg){ struct loop_info info; int err; unsigned int type; if (lo->lo_encrypt_key_size && lo->lo_key_owner != current->uid && !capable(CAP_SYS_ADMIN)) return -EPERM; if (!lo->lo_dentry) return -ENXIO; if (copy_from_user(&info, arg, sizeof (struct loop_info))) return -EFAULT; if ((unsigned int) info.lo_encrypt_key_size > LO_KEY_SIZE) return -EINVAL; type = info.lo_encrypt_type; if (type >= MAX_LO_CRYPT || xfer_funcs[type] == NULL) return -EINVAL; err = loop_release_xfer(lo); if (!err) err = loop_init_xfer(lo, type, &info); if (err) return err; lo->lo_offset = info.lo_offset; strncpy(lo->lo_name, info.lo_name, LO_NAME_SIZE); lo->transfer = xfer_funcs[type]->transfer; lo->ioctl = xfer_funcs[type]->ioctl; lo->lo_encrypt_key_size = info.lo_encrypt_key_size; lo->lo_init[0] = info.lo_init[0]; lo->lo_init[1] = info.lo_init[1]; if (info.lo_encrypt_key_size) { memcpy(lo->lo_encrypt_key, info.lo_encrypt_key, info.lo_encrypt_key_size); lo->lo_key_owner = current->uid; } figure_loop_size(lo); return 0;}static int loop_get_status(struct loop_device *lo, struct loop_info *arg){ struct loop_info info; if (!lo->lo_dentry) return -ENXIO; if (!arg) return -EINVAL; memset(&info, 0, sizeof(info)); info.lo_number = lo->lo_number; info.lo_device = kdev_t_to_nr(lo->lo_dentry->d_inode->i_dev); info.lo_inode = lo->lo_dentry->d_inode->i_ino; info.lo_rdevice = kdev_t_to_nr(lo->lo_device); info.lo_offset = lo->lo_offset; info.lo_flags = lo->lo_flags; strncpy(info.lo_name, lo->lo_name, LO_NAME_SIZE); info.lo_encrypt_type = lo->lo_encrypt_type; if (lo->lo_encrypt_key_size && capable(CAP_SYS_ADMIN)) { info.lo_encrypt_key_size = lo->lo_encrypt_key_size; memcpy(info.lo_encrypt_key, lo->lo_encrypt_key, lo->lo_encrypt_key_size); } return copy_to_user(arg, &info, sizeof(info)) ? -EFAULT : 0;}static int lo_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg){ struct loop_device *lo; int dev; if (!inode) return -EINVAL; if (MAJOR(inode->i_rdev) != MAJOR_NR) { printk(KERN_WARNING "lo_ioctl: pseudo-major != %d\n", MAJOR_NR); return -ENODEV; } dev = MINOR(inode->i_rdev); if (dev >= MAX_LOOP) return -ENODEV; lo = &loop_dev[dev]; switch (cmd) { case LOOP_SET_FD: return loop_set_fd(lo, inode->i_rdev, arg); case LOOP_CLR_FD: return loop_clr_fd(lo, inode->i_rdev); case LOOP_SET_STATUS: return loop_set_status(lo, (struct loop_info *) arg); case LOOP_GET_STATUS: return loop_get_status(lo, (struct loop_info *) arg); case BLKGETSIZE: /* Return device size */ if (!lo->lo_dentry) return -ENXIO; if (!arg) return -EINVAL; return put_user(loop_sizes[lo->lo_number] << 1, (long *) arg); default: return lo->ioctl ? lo->ioctl(lo, cmd, arg) : -EINVAL; } return 0;}static int lo_open(struct inode *inode, struct file *file){ struct loop_device *lo; int dev, type; if (!inode) return -EINVAL; if (MAJOR(inode->i_rdev) != MAJOR_NR) { printk(KERN_WARNING "lo_open: pseudo-major != %d\n", MAJOR_NR); return -ENODEV; } dev = MINOR(inode->i_rdev); if (dev >= MAX_LOOP) { return -ENODEV; } lo = &loop_dev[dev]; type = lo->lo_encrypt_type; if (type && xfer_funcs[type] && xfer_funcs[type]->lock) xfer_funcs[type]->lock(lo); lo->lo_refcnt++; MOD_INC_USE_COUNT; return 0;}static int lo_release(struct inode *inode, struct file *file){ struct loop_device *lo; int dev, err; if (!inode) return 0; if (MAJOR(inode->i_rdev) != MAJOR_NR) { printk(KERN_WARNING "lo_release: pseudo-major != %d\n", MAJOR_NR); return 0; } dev = MINOR(inode->i_rdev); if (dev >= MAX_LOOP) return 0; err = fsync_dev(inode->i_rdev); lo = &loop_dev[dev]; if (lo->lo_refcnt <= 0) printk(KERN_ERR "lo_release: refcount(%d) <= 0\n", lo->lo_refcnt); else { int type = lo->lo_encrypt_type; --lo->lo_refcnt; if (xfer_funcs[type] && xfer_funcs[type]->unlock) xfer_funcs[type]->unlock(lo); MOD_DEC_USE_COUNT; } return err;}static struct file_operations lo_fops = { NULL, /* lseek - default */ block_read, /* read - general block-dev read */ block_write, /* write - general block-dev write */ NULL, /* readdir - bad */ NULL, /* poll */ lo_ioctl, /* ioctl */ NULL, /* mmap */ lo_open, /* open */ NULL, /* flush */ lo_release /* release */};/* * And now the modules code and kernel interface. */#ifdef MODULE#define loop_init init_module#endifint loop_register_transfer(struct loop_func_table *funcs){ if ((unsigned)funcs->number > MAX_LO_CRYPT || xfer_funcs[funcs->number]) return -EINVAL; xfer_funcs[funcs->number] = funcs; return 0; }int loop_unregister_transfer(int number){ struct loop_device *lo; if ((unsigned)number >= MAX_LO_CRYPT) return -EINVAL; for (lo = &loop_dev[0]; lo < &loop_dev[MAX_LOOP]; lo++) { int type = lo->lo_encrypt_type; if (type == number) { xfer_funcs[type]->release(lo); lo->transfer = NULL; lo->lo_encrypt_type = 0; } } xfer_funcs[number] = NULL; return 0; }EXPORT_SYMBOL(loop_register_transfer);EXPORT_SYMBOL(loop_unregister_transfer);int __init loop_init(void) { int i; if (register_blkdev(MAJOR_NR, "loop", &lo_fops)) { printk(KERN_WARNING "Unable to get major number %d for loop device\n", MAJOR_NR); return -EIO; }#ifndef MODULE printk(KERN_INFO "loop: registered device at major %d\n", MAJOR_NR);#endif blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; for (i=0; i < MAX_LOOP; i++) { memset(&loop_dev[i], 0, sizeof(struct loop_device)); loop_dev[i].lo_number = i; } memset(&loop_sizes, 0, sizeof(loop_sizes)); memset(&loop_blksizes, 0, sizeof(loop_blksizes)); blk_size[MAJOR_NR] = loop_sizes; blksize_size[MAJOR_NR] = loop_blksizes; return 0;}#ifdef MODULEvoid cleanup_module(void) { if (unregister_blkdev(MAJOR_NR, "loop") != 0) printk(KERN_WARNING "loop: cannot unregister blkdev\n");}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -