📄 bc_dev24.c
字号:
/******************************************************************* * Copyright (c) 1994-1998 Jetico, Inc., Finland * All rights reserved. * * File: driver/bc_dev.c * * Description: BestCrypt pseudo-device driver. * * Scope: BestCrypt pseudo-device driver * * Platforms: Linux * * Ideas: Igor M. Arsenin * Serge A. Frolov * Vitaliy G. Zolotarev * * Author: Nail R. Kaipov * * Created: 10-Nov-1998 * * Revision: 06-Aug-1999. new strategy routine * 15-Sep-1999. 2.3.x kernels support * 11-Oct-1999. strategy bugfix * 15-Dec-1999. driver refinement * 21-Mar-2000. bugfix for large blocks (v0.4b-2) * 15-Jun-2000. partition support * 15-Nov-2000. major rewrite. 2.4.0 version * 01-Feb-2001. minor fixes. partitions cleanup. * 02-May-2001. SMP bugfix, /proc update * 06-Jun-2001. writing magic in bc_clr_fd * 10-Oct-2001. bc_lock_dev() fixed * 04-Nov-2003. 64-bit IV added. * *******************************************************************/#ifndef EXPORT_SYMTAB#define EXPORT_SYMTAB#endif#include "bc_cfg.h"#include <linux/module.h>#include <linux/fs.h> /* inode et al */#include <linux/proc_fs.h> /* proc_fs support */#include <linux/devfs_fs_kernel.h> /* devfs_fs support */#include <linux/file.h> /* fget()/fput() pair */#include <linux/vmalloc.h> /* vmalloc() */#include <asm/uaccess.h> /* put_user() */#include <asm/atomic.h> /* atomic operations */#include <linux/hdreg.h> /* hd_geometry */#include "bc_types.h" /* bc types */#include "bc_ioctl.h" /* ioctl codes */#include "bc_mgr.h"#include "bc_dev.h" /* bc types codes */#define DEVICE_OFF(dev)#include <linux/blk.h>#define __KERNEL_SYSCALLS__#include <linux/unistd.h>#ifndef GFP_NOIO#define GFP_NOIO GFP_BUFFER#endifstatic int bc_devices = DEFAULT_BC_DEVICES;static int bc_partitions = DEFAULT_BC_PARTITIONS;static int bc_minor_shift = 0;struct bc_device *bc_dev; /* bc devices' array */static struct bc_disk *bc_dsk; /* bc disks array */static int *bc_sizes; /**/static int *bc_blksizes; /**/static struct hd_struct *bc_hd; /**//* pid control table support */#define BC_PID_SIZE 64static pid_t *bc_pid_table;static int bc_pid_size;static int bc_pid_next;static struct semaphore bc_pid_sema;static struct timer_list bc_pid_timer;static devfs_handle_t bc_hdevfs;static struct gendisk bc_gendisk;static struct proc_dir_entry *proc_bcrypt;static DECLARE_WAIT_QUEUE_HEAD(wait_open);static DECLARE_WAIT_QUEUE_HEAD(wait_bc);EXPORT_SYMBOL(register_bc_algo);EXPORT_SYMBOL(unregister_bc_algo);MODULE_PARM(bc_devices, "i");MODULE_PARM_DESC(bc_devices, "Max. number of devices (1-256).");MODULE_PARM(bc_partitions, "i");MODULE_PARM_DESC(bc_partitions, "Max. partitions per device (0-63).");MODULE_AUTHOR("Jetico, Inc.");MODULE_DESCRIPTION("BestCrypt encrypted block device driver.");#ifdef MODULE_LICENSEMODULE_LICENSE("Jetico, Inc.");#endifstatic int bc_ioctl (struct inode *, struct file *, unsigned int, unsigned long);static int bc_open (struct inode *, struct file *);static int bc_release (struct inode *, struct file *);/*static struct file_operations bc_fops;*/static struct block_device_operations bc_bdops = { ioctl :bc_ioctl, open :bc_open, release:bc_release};/*-----------------------------------------------------------*/static inline struct bc_device *get_bcdev(kdev_t dev){ int mn = MINOR(dev); if (MAJOR_NR == MAJOR(dev) && MAX_MINORS > MINOR(dev)) { mn >>= bc_minor_shift; if (0 <= mn && bc_devices > mn) return bc_dev+mn; } return NULL; /* -ENODEV error */}static inline struct bc_disk *get_bcdsk(kdev_t dev) { int mn = MINOR(dev); if (MAJOR_NR == MAJOR(dev) && MAX_MINORS > MINOR(dev)) { if (0 <= mn && bc_devices * bc_partitions > mn) return bc_dsk+mn; } return NULL; }static inline int is_parent(struct bc_disk *bd) { if (NULL != bd) return !(bd->bd_number & ((1 << bc_minor_shift) - 1)); return 0;}static inline void reset_dev(struct bc_device *bc){ int i, j; if (NULL == bc) return; bc->bc_offset = 0L; bc->bc_start_sector = 0L; bc->bc_num_sectors = 0L; bc->bc_dev = 0; bc->bc_key = 0; bc->bc_alg = NULL; bc->bc_file = NULL; bc->bc_dentry = NULL; atomic_set(&bc->bc_pending, 0); spin_lock_init(&bc->bc_lock); init_MUTEX_LOCKED(&bc->bc_thread); init_MUTEX_LOCKED(&bc->bc_run); bc->bc_bh = NULL; bc->bc_bhtail = NULL; bc->bc_gfpmask = 0; bc->bc_save_fops = NULL; bc->bc_activity = 0; memset(&bc->bc_flags, 0, sizeof(bc->bc_flags)); if (NULL != bc->bc_buffer) vfree(bc->bc_buffer); bc->bc_buffer = NULL; i = bc->bc_number << bc_minor_shift; j = i + (1 << bc_minor_shift); memset(&bc_dsk[i], 0, (j-i) * sizeof(struct bc_disk)); for (; i < j; i++) bc_dsk[i].bd_number = i;}/*-----------------------------------------------------------*/static inline int bc_find_pid(pid_t pid) { register int i; for (i = 0; i < bc_pid_next; i++) if (pid == bc_pid_table[i]) return i; return -1;}static int bc_find_pid_safe(pid_t pid){ int i; down(&bc_pid_sema); i = bc_find_pid(pid); up(&bc_pid_sema); return i;}static int bc_add_pid(pid_t pid) { pid_t *tmp; down(&bc_pid_sema); if (bc_find_pid(pid) > -1) { up(&bc_pid_sema); return 0; } if (bc_pid_next < bc_pid_size) { bc_pid_table[bc_pid_next] = pid; bc_pid_next++; } else { tmp = kmalloc((bc_pid_size+BC_PID_SIZE) * sizeof(pid_t), GFP_KERNEL); if (NULL == tmp) { up(&bc_pid_sema); return -ENOMEM; } memcpy(bc_pid_table, tmp, bc_pid_size * sizeof(pid_t)); kfree(bc_pid_table); bc_pid_table = tmp; bc_pid_size += BC_PID_SIZE; bc_pid_table[bc_pid_next] = pid; bc_pid_next++; } if (1 == bc_pid_next) { bc_pid_timer.expires = jiffies + 5 * HZ; add_timer(&bc_pid_timer); } up(&bc_pid_sema); return 0;}static int bc_del_pid(pid_t pid) { int i; pid_t *tmp; down(&bc_pid_sema); i = bc_find_pid(pid); if (0 > i) { up(&bc_pid_sema); return 0; } bc_pid_next--; if (bc_pid_next) bc_pid_table[i] = bc_pid_table[bc_pid_next]; bc_pid_table[bc_pid_next] = 0; if (bc_pid_size-bc_pid_next > 2*BC_PID_SIZE) { tmp = kmalloc((bc_pid_size-BC_PID_SIZE) * sizeof(pid_t), GFP_KERNEL); if (NULL == tmp) { up(&bc_pid_sema); return 0; } bc_pid_size -= BC_PID_SIZE; memcpy(bc_pid_table, tmp, bc_pid_size * sizeof(pid_t)); kfree(bc_pid_table); bc_pid_table = tmp; } up(&bc_pid_sema); return 0;}static void bc_pid_timer_proc(unsigned long unused) { register int i; down(&bc_pid_sema);#ifdef CONFIG_SMP write_lock_irq(&tasklist_lock);#endif for (i = 0; i < bc_pid_next; i++) { if (NULL == find_task_by_pid(bc_pid_table[i])) { bc_pid_next--; if (bc_pid_next) bc_pid_table[i] = bc_pid_table[bc_pid_next]; bc_pid_table[bc_pid_next] = 0; i--; } }#ifdef CONFIG_SMP write_unlock_irq(&tasklist_lock);#endif if (bc_pid_next) { bc_pid_timer.expires = jiffies + 5 * HZ; add_timer(&bc_pid_timer); } up(&bc_pid_sema);}/*-----------------------------------------------------------*/static int bc_thread(void *data){ struct bc_device *bc = (struct bc_device *)data; struct buffer_head *bh; struct bc_disk *bd; struct file *file; size_t len, ret, size; loff_t pos, sec; char *dst, *buf = NULL; u16 iv[4]; u64 iv64, iv64le; mm_segment_t fs; int i, uptodate, rw; daemonize(); sprintf(current->comm, "bcrypt%d", bc->bc_number);#ifdef SCHED_OTHER spin_lock_irq(¤t->sigmask_lock); sigfillset(¤t->blocked); flush_signals(current); spin_unlock_irq(¤t->sigmask_lock); current->policy = SCHED_OTHER;#else spin_lock_irq(¤t->sighand->siglock); sigfillset(¤t->blocked); flush_signals(current); spin_unlock_irq(¤t->sighand->siglock); current->policy = SCHED_NORMAL;#endif#ifdef _NICE_PRESENT_ current->nice = -20;#else set_user_nice(current, -20l);#endif #ifdef PF_NOIO /* 2.4.17 kludge */ current->flags |= PF_NOIO;#endif spin_lock_irq(&bc->bc_lock); bc->bc_flags.active = 1; atomic_inc(&bc->bc_pending); spin_unlock_irq(&bc->bc_lock); up(&bc->bc_thread); while (1) { down_interruptible(&bc->bc_run); i = atomic_read(&bc->bc_pending); if (i == 0) break; spin_lock_irq(&bc->bc_lock); bh = bc->bc_bh; if (NULL == bh) { spin_unlock_irq(&bc->bc_lock); continue; } if (bc->bc_bhtail == bh) bc->bc_bhtail = NULL; bc->bc_bh = bh->b_reqnext; bh->b_reqnext = NULL; spin_unlock_irq(&bc->bc_lock); uptodate = 0; bd = get_bcdsk(bh->b_rdev); if (!bd->bd_flags.configured && bc->bc_flags.busy) { bd->bd_offset = bc->bc_offset + (((loff_t)bc_gendisk.part[bd->bd_number].start_sect) << 9); } sec = (loff_t)bh->b_rsector + bc->bc_start_sector; pos = sec * 512 + bd->bd_offset; len = bh->b_size; dst = bh->b_data; file = bc->bc_file; iv[0] = iv[1] = iv[2] = iv[3] = sec & 0xFFFF; iv64 = sec + 1; bc->bc_activity = 1; rw = !!test_and_clear_bit(BH_Dirty, &bh->b_state); if (READ == rw) { fs = get_fs(); set_fs(KERNEL_DS); ret = file->f_op->read(file, dst, len, &pos); set_fs(fs); if (ret != len) { printk(KERN_ERR "bc: read error wanted %ld, read %ld\n", (unsigned long)len, (unsigned long)ret); goto error_out; } if (bc->bc_flags.iv_64bit) { iv64le = __cpu_to_le64(iv64); bc->bc_alg->decrypt(bc->bc_key, (char *)(&iv64le), dst, dst, len); } else { bc->bc_alg->decrypt(bc->bc_key, (char *)iv, dst, dst, len); } } else { buf = bc->bc_buffer; size = BC_BUFFER_SIZE; while (len > 0) { if (size > len) size = len; if (bc->bc_flags.iv_64bit) { iv64le = __cpu_to_le64(iv64); bc->bc_alg->encrypt(bc->bc_key, (char *)(&iv64le), dst, buf, size); } else { bc->bc_alg->encrypt(bc->bc_key, (char *)iv, dst, buf, size); } fs = get_fs(); set_fs(KERNEL_DS); ret = file->f_op->write(file, buf, size, &pos); set_fs(fs); if (ret != size) { printk(KERN_ERR "bc: write error wanted %ld, wrote %ld\n", (unsigned long)size, (unsigned long)ret); goto error_out; } if (bc->bc_flags.iv_64bit) { iv64 += BC_BUFFER_SIZE/512; } else { iv[0] = ((int)iv[0] + BC_BUFFER_SIZE/512) & 0xFFFF; iv[3] = iv[2] = iv[1] = iv[0]; } dst += size; len -= size; } } uptodate = 1;error_out: bh->b_end_io(bh, uptodate); if (atomic_dec_and_test(&bc->bc_pending)) break; } up(&bc->bc_thread); return 0;}static int bc_make_request(request_queue_t *q, int rw, struct buffer_head *bh){ int rw_ahead; struct bc_device *bc; struct bc_disk *bd; if (!buffer_locked(bh)) BUG(); rw_ahead = 0; bc = get_bcdev(bh->b_rdev); bd = get_bcdsk(bh->b_rdev); if (!bc || !bd || !bc->bc_dentry || !bc->bc_dentry->d_inode) { printk(KERN_ERR "bc: invalid device.\n"); goto error_out; } if (!bd->bd_flags.configured && !bc->bc_flags.busy) { printk(KERN_ERR "bc: device not configured yet.\n"); goto error_out; } if (WRITE == rw) { if (bc->bc_flags.readonly) { printk(KERN_ERR "bc: attempt to write on readonly device.\n"); goto error_out; } } else if (READA == rw) { rw = READ; rw_ahead = 1; } else if (READ != rw) { printk(KERN_ERR "bc: unknown command (%d).\n", rw); goto error_out; } spin_lock_irq(&bc->bc_lock); if (!bc->bc_flags.active) { spin_unlock_irq(&bc->bc_lock); goto error_out; } atomic_inc(&bc->bc_pending);// spin_unlock_irq(&bc->bc_lock); #ifdef CONFIG_HIGHMEM bh = create_bounce(rw, bh);#endif if (WRITE == rw) set_bit(BH_Dirty, &bh->b_state);// spin_lock_irq(&bc->bc_lock); if (bc->bc_bhtail) bc->bc_bhtail->b_reqnext = bh; else bc->bc_bh = bh; bc->bc_bhtail = bh; spin_unlock_irq(&bc->bc_lock); up(&bc->bc_run); return 0;error_out: buffer_IO_error(bh); return 0;}/*-- end of strategy routine --------------------------------*//*-- fops functions -----------------------------------------*/static int bc_open(struct inode *inode, struct file *file){ struct bc_device *bc; if (NULL == inode) return -EINVAL; MOD_INC_USE_COUNT; bc = get_bcdev(inode->i_rdev); if (NULL == bc) { printk(KERN_ERR "bc_open: invalid device (%d, %d).\n",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -