📄 bc_dev24.c
字号:
MAJOR(inode->i_rdev), MINOR(inode->i_rdev)); MOD_DEC_USE_COUNT; return -ENODEV; } while (1) { down(&bc->bc_control); if (!bc->bc_flags.busy) break; up(&bc->bc_control); sleep_on(&wait_open); } bc->bc_refcnt++; up(&bc->bc_control); if (capable(CAP_SYS_ADMIN)) { bc_add_pid(current->pid); } return 0;}static int bc_release(struct inode *inode, struct file *file){ struct bc_device *bc; if (NULL == inode) return 0; bc = get_bcdev(inode->i_rdev); if (NULL == bc) return 0;/* fsync() is not required here. It should be called before by upper level. Moreover, fsync() here leads to ReiserFS hangup on umount. error = fsync_dev(inode->i_rdev);*/ down(&bc->bc_control); if (0 >= bc->bc_refcnt) printk(KERN_WARNING "bc_release: refcount (%d) <= 0\n", bc->bc_refcnt); else { bc->bc_refcnt--; MOD_DEC_USE_COUNT; } up(&bc->bc_control); return 0;}static ssize_t bc_read (struct file *file, char *buf, size_t count, loff_t *ppos){ struct bc_disk *bd; struct bc_device *bc; struct inode *inode; if (NULL == file) return -EINVAL; inode = file->f_dentry->d_inode; if (NULL == inode) return -EIO; bd = get_bcdsk(inode->i_rdev); if (NULL == bd) return -ENODEV; bc = get_bcdev(inode->i_rdev); if (NULL == bc) return -ENODEV; if (!bd->bd_flags.configured || bd->bd_flags.mounted) return -EIO; if (bc->bc_save_fops && bc->bc_save_fops->read) return bc->bc_save_fops->read(file, buf, count, ppos); else return -EPERM;}static ssize_t bc_write(struct file *file, const char *buf, size_t count, loff_t *ppos){ struct bc_disk *bd; struct bc_device *bc; struct inode *inode; if (NULL == file) return -EINVAL; inode = file->f_dentry->d_inode; if (NULL == inode) return -EIO; bd = get_bcdsk(inode->i_rdev); if (NULL == bd) return -ENODEV; bc = get_bcdev(inode->i_rdev); if (NULL == bc) return -ENODEV; if (!bd->bd_flags.configured || bd->bd_flags.mounted) return -EIO; if (bc->bc_save_fops && bc->bc_save_fops->write) return bc->bc_save_fops->write(file, buf, count, ppos); else return -EPERM;}/*-- end of fops functions ----------------------------------*/static int bc_get_info(struct bc_disk *bd, struct bc_device *bc, struct bc_info *arg){ struct bc_info query; long busy; BC_GET_ARG(arg, query) put_user(BC_VERSION_MAJOR, (long *)&arg->ver_major); put_user(BC_VERSION_MINOR, (long *)&arg->ver_minor); busy = bd->bd_flags.configured || bc->bc_refcnt > 1 ? 1 : 0; put_user(busy, (long *)&arg->busy); return 0;}static int bc_check(struct bc_check *arg){ struct bc_check query; struct file *file; int i, max_devices; BC_GET_ARG(arg, query) if (bc_find_pid_safe(current->pid) < 0) return -EPERM; if (!(file = fget(query.fd))) return -EBADF; max_devices = bc_devices * bc_partitions; for (i = 0; i < max_devices; i++) { if (!bc_dsk[i].bd_flags.configured) continue; if (file == bc_dev[i>>bc_minor_shift].bc_file) break; } if (max_devices == i) i = BC_CONTAINER_UNUSED; else if (bc_dsk[i].bd_flags.mounted) i = BC_CONTAINER_MOUNTED; else i = BC_CONTAINER_USED; put_user(i, (long *)&arg->busy); return 0;}#define MAX_DISK_SIZE 1024*1024*1024static int scan_device(struct bc_disk *bd, struct bc_device *bc){ int i, part, size; kdev_t dev; struct super_block *sb = NULL; if (!is_parent(bd)) return -EPERM; if (NULL == bc->bc_dentry) return -ENXIO; if (bc->bc_refcnt > 1) return -EBUSY; bc->bc_flags.busy = 1; if (S_ISREG(bc->bc_dentry->d_inode->i_mode)) { size = (bc->bc_dentry->d_inode->i_size - bc->bc_offset) >> BLOCK_SIZE_BITS; } else { size = MAX_DISK_SIZE; dev = bc->bc_dev; if (blk_size[MAJOR(dev)]) { size = blk_size[MAJOR(dev)][MINOR(dev)]; size -= (bc->bc_offset >> BLOCK_SIZE_BITS); } } bc_sizes[bd->bd_number] = size; bd->bd_offset = bc->bc_offset; if (!bc->bc_flags.multpart || !bc_minor_shift) { /* skip partitions */ bd->bd_flags.configured = 1; bc->bc_flags.busy = 0; wake_up(&wait_open); return 0; } for (i = bc_gendisk.max_p - 1; i >= 0; i--) { part = bd->bd_number + i; dev = MKDEV(MAJOR_NR, part); sb = get_super(dev); sync_dev(dev); if (sb) invalidate_inodes(sb); invalidate_buffers(dev); bc_gendisk.part[part].start_sect = 0; bc_gendisk.part[part].nr_sects = 0; bc_dsk[part].bd_flags.configured = 0; bc_dsk[part].bd_offset = bc->bc_offset; }; bc_gendisk.part[bd->bd_number].nr_sects = size << 1; grok_partitions(&bc_gendisk, bc->bc_number, bc_gendisk.max_p, size << 1); for (i = bc_gendisk.max_p - 1; i >= 0; i--) { part = bd->bd_number + i; if (0 < bc_gendisk.part[part].nr_sects) { bc_dsk[part].bd_flags.configured = 1; bc_dsk[part].bd_offset = bc->bc_offset + (((loff_t)bc_gendisk.part[part].start_sect) << 9); } } bc->bc_flags.busy = 0; wake_up(&wait_open); return 0;}static int bc_set_fd(struct bc_disk *bd, struct bc_device *bc, kdev_t dev, struct inode *dev_inode, struct bc_file64 *arg)/* key must be ready */{ struct file *file = NULL; struct inode *inode = NULL; struct bc_algorithm *bc_alg = NULL; struct bc_file64 query; int error;/* struct list_head *ptr; struct file *other;*/ if (bc_find_pid_safe(current->pid) < 0) return -EPERM; MOD_INC_USE_COUNT; BC_GET_ARG(arg, query) if (!is_parent(bd)) { error = -EPERM; goto error_out; } if (bc->bc_dentry) { error = -EBUSY; goto error_out; } bc_alg = get_bc_algo(query.alg_id, NULL); if (NULL == bc_alg || bc_alg->test_key(query.key_handle) != 0) { error = -EINVAL; goto error_out; } if (!(file = fget(query.fd))) { error = -EBADF; goto error_out; } inode = file->f_dentry->d_inode;/* list_for_each(ptr, &file->f_list) { other = list_entry(ptr, struct file, f_list); if (other && other->f_dentry) if (inode == other->f_dentry->d_inode) printk("file busy pid=%d\n", other->f_owner.pid); }*/ error = -EINVAL; if (!inode) { printk(KERN_ERR "bc_set_fd: NULL inode.\n"); goto error_out; } if (!file->f_op) { printk(KERN_ERR "bc_set_fd: NULL file_operations.\n"); goto error_out; } if (!file->f_op->read) { printk(KERN_ERR "bc_set_fd: Can't perform reads.\n"); goto error_out; } reset_dev(bc); if (S_ISBLK(inode->i_mode)) { error = blkdev_open(inode, file); if (error) goto error_out; bc->bc_dev = inode->i_rdev; } else if (S_ISREG(inode->i_mode)) { bc->bc_dev = inode->i_dev; } else goto error_out; bc->bc_flags.iv_64bit = query.flags & BC_FLAGS_IV_64BIT || 0; bc->bc_flags.multpart = query.flags & BC_FLAGS_MULTPART || 0; bc->bc_flags.readonly = IS_RDONLY(inode) || is_read_only(bc->bc_dev) || (NULL == file->f_op->write) || query.flags & BC_FLAGS_READONLY; if (!bc->bc_flags.readonly) { error = get_write_access(inode); if (error) { printk (KERN_ERR "bc_set_fd: Can't get write access.\n"); goto error_out; } invalidate_inode_pages (inode); } set_device_ro(dev, bc->bc_flags.readonly); if (NULL != dev_inode->i_fop) { bc->bc_save_fops = dev_inode->i_fop; memcpy(&(bc->bc_fops), dev_inode->i_fop, sizeof(bc->bc_fops)); bc->bc_fops.read = bc_read; bc->bc_fops.write = bc_write; dev_inode->i_fop = &(bc->bc_fops); } bc->bc_buffer = vmalloc(BC_BUFFER_SIZE); if (NULL == bc->bc_buffer) goto error_out; bc->bc_key = query.key_handle; bc->bc_alg = bc_alg; bc->bc_file = file; bc->bc_dentry = dget(file->f_dentry); bc->bc_offset = (loff_t)query.offset; bc->bc_start_sector = (loff_t)query.start_sector; bc->bc_num_sectors = (loff_t)query.num_sectors; bc_alg->lock_key(query.key_handle, 1); bc->bc_gfpmask = bc->bc_dentry->d_inode->i_mapping->gfp_mask; bc->bc_dentry->d_inode->i_mapping->gfp_mask = GFP_NOIO; kernel_thread(bc_thread, bc, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); down(&bc->bc_thread); scan_device(bd, bc); return 0;error_out: if (file) fput(file); MOD_DEC_USE_COUNT; return error;}static int errno;static int bc_clr_fd(struct bc_disk *bd, struct bc_device *bc, kdev_t dev, struct inode *dev_inode){ int i, n, minor; devfs_handle_t hdevfs; size_t ret; loff_t pos; unsigned char magic; mm_segment_t fs; if (bc_find_pid_safe(current->pid) < 0) return -EPERM; if (!is_parent(bd)) return -EPERM; if (NULL == bc->bc_dentry) return -ENXIO; if (NULL == bc->bc_file) return -ENXIO; if (bc->bc_refcnt > 1) return -EBUSY; spin_lock_irq(&bc->bc_lock); if (atomic_dec_and_test(&bc->bc_pending)) up(&bc->bc_run); bc->bc_flags.active = 0; spin_unlock_irq(&bc->bc_lock); down(&bc->bc_thread); waitpid(-1, NULL, __WCLONE|WNOHANG); bc->bc_dentry->d_inode->i_mapping->gfp_mask = bc->bc_gfpmask; n = 1 << bc_minor_shift; for (i = 0; i < n; i++) { minor = bc->bc_number*n+i; sync_dev(MKDEV(MAJOR_NR, minor)); invalidate_buffers(MKDEV(MAJOR_NR, minor)); while (i) { hdevfs = devfs_find_handle(bc->bc_hdevfs, NULL, MAJOR_NR, minor, DEVFS_SPECIAL_BLK, 0); if (NULL == hdevfs) { bc_hd[minor].de = 0; break; } if (hdevfs != bc->bc_hdevfs) devfs_unregister(hdevfs); } bc_sizes[minor] = 0; } if (bc->bc_save_fops) { dev_inode->i_fop = bc->bc_save_fops; } if (!bc->bc_flags.readonly && bc->bc_offset) { pos = 0; magic = 0xEB; fs = get_fs(); set_fs(KERNEL_DS); ret = bc->bc_file->f_op->write(bc->bc_file, &magic, 1, &pos); set_fs(fs); if (ret != 1) printk(KERN_ERR "bc: error %ld writing magic\n", (unsigned long)ret); } if (S_ISBLK(bc->bc_dentry->d_inode->i_mode)) blkdev_put(bc->bc_dentry->d_inode->i_bdev, BDEV_FILE); if (!bc->bc_flags.readonly) put_write_access(bc->bc_dentry->d_inode); dput(bc->bc_dentry); fput(bc->bc_file); // bc->bc_alg->lock_key(bc->bc_key, 0); bc->bc_alg->free_key(bc->bc_key); reset_dev(bc); MOD_DEC_USE_COUNT; return 0;}static int bc_lock_dev(struct bc_disk *bd, struct bc_device *bc, kdev_t dev, int lock){ struct vfsmount *mnt, *root; struct list_head *ptr; if (bc_find_pid_safe(current->pid) < 0) return -EPERM;// if (!capable(CAP_SYS_ADMIN))// return -EPERM; if (!bd->bd_flags.configured) { if (!lock) return 0; printk(KERN_ERR "bc: attempt to lock free device.\n"); return -ENXIO; } spin_lock(&dcache_lock); if (lock && !bd->bd_flags.mounted) { root = current->fs->rootmnt; list_for_each(ptr, &root->mnt_list) { mnt = list_entry(ptr, struct vfsmount, mnt_list); if (NULL == mnt || NULL == mnt->mnt_sb || NULL == mnt->mnt_root || NULL == mnt->mnt_devname) continue; if (dev == mnt->mnt_sb->s_dev) { mntget(mnt); break; } } bd->bd_flags.mounted = 1; bc->bc_refcnt++; } else if (!lock && bd->bd_flags.mounted) { root = current->fs->rootmnt; list_for_each(ptr, &root->mnt_list) { mnt = list_entry(ptr, struct vfsmount, mnt_list); if (NULL == mnt || NULL == mnt->mnt_sb || NULL == mnt->mnt_root || NULL == mnt->mnt_devname) continue; if (dev == mnt->mnt_sb->s_dev) { mntput(mnt); break; } } bd->bd_flags.mounted = 0; bc->bc_refcnt--; } spin_unlock(&dcache_lock); return 0;}static int bc_force_unlock(struct bc_disk *bd, struct bc_device *bc, kdev_t dev){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -