📄 block_dev.c
字号:
return new_bdev; } spin_unlock(&bdev_lock); iput(new_bdev->bd_inode); } destroy_bdev(new_bdev); } return bdev;}static inline void __bd_forget(struct inode *inode){ list_del_init(&inode->i_devices); inode->i_bdev = NULL; inode->i_mapping = &inode->i_data;}void bdput(struct block_device *bdev){ if (atomic_dec_and_lock(&bdev->bd_count, &bdev_lock)) { struct list_head *p; if (bdev->bd_openers) BUG(); list_del(&bdev->bd_hash); while ( (p = bdev->bd_inodes.next) != &bdev->bd_inodes ) { __bd_forget(list_entry(p, struct inode, i_devices)); } spin_unlock(&bdev_lock); iput(bdev->bd_inode); destroy_bdev(bdev); }} int bd_acquire(struct inode *inode){ struct block_device *bdev; spin_lock(&bdev_lock); if (inode->i_bdev) { atomic_inc(&inode->i_bdev->bd_count); spin_unlock(&bdev_lock); return 0; } spin_unlock(&bdev_lock); bdev = bdget(kdev_t_to_nr(inode->i_rdev)); if (!bdev) return -ENOMEM; spin_lock(&bdev_lock); if (!inode->i_bdev) { inode->i_bdev = bdev; inode->i_mapping = bdev->bd_inode->i_mapping; list_add(&inode->i_devices, &bdev->bd_inodes); } else if (inode->i_bdev != bdev) BUG(); spin_unlock(&bdev_lock); return 0;}/* Call when you free inode */void bd_forget(struct inode *inode){ spin_lock(&bdev_lock); if (inode->i_bdev) __bd_forget(inode); spin_unlock(&bdev_lock);}static struct { const char *name; struct block_device_operations *bdops;} blkdevs[MAX_BLKDEV];int get_blkdev_list(char * p){ int i; int len; len = sprintf(p, "\nBlock devices:\n"); for (i = 0; i < MAX_BLKDEV ; i++) { if (blkdevs[i].bdops) { len += sprintf(p+len, "%3d %s\n", i, blkdevs[i].name); } } return len;}/* Return the function table of a device. Load the driver if needed.*/const struct block_device_operations * get_blkfops(unsigned int major){ const struct block_device_operations *ret = NULL; /* major 0 is used for non-device mounts */ if (major && major < MAX_BLKDEV) {#ifdef CONFIG_KMOD if (!blkdevs[major].bdops) { char name[20]; sprintf(name, "block-major-%d", major); request_module(name); }#endif ret = blkdevs[major].bdops; } return ret;}int register_blkdev(unsigned int major, const char * name, struct block_device_operations *bdops){ if (major == 0) { for (major = MAX_BLKDEV-1; major > 0; major--) { if (blkdevs[major].bdops == NULL) { blkdevs[major].name = name; blkdevs[major].bdops = bdops; return major; } } return -EBUSY; } if (major >= MAX_BLKDEV) return -EINVAL; if (blkdevs[major].bdops && blkdevs[major].bdops != bdops) return -EBUSY; blkdevs[major].name = name; blkdevs[major].bdops = bdops; return 0;}int unregister_blkdev(unsigned int major, const char * name){ if (major >= MAX_BLKDEV) return -EINVAL; if (!blkdevs[major].bdops) return -EINVAL; if (strcmp(blkdevs[major].name, name)) return -EINVAL; blkdevs[major].name = NULL; blkdevs[major].bdops = NULL; return 0;}/* * This routine checks whether a removable media has been changed, * and invalidates all buffer-cache-entries in that case. This * is a relatively slow routine, so we have to try to minimize using * it. Thus it is called only upon a 'mount' or 'open'. This * is the best way of combining speed and utility, I think. * People changing diskettes in the middle of an operation deserve * to lose :-) */int check_disk_change(kdev_t dev){ int i; const struct block_device_operations * bdops = NULL; i = MAJOR(dev); if (i < MAX_BLKDEV) bdops = blkdevs[i].bdops; if (bdops == NULL) { devfs_handle_t de; de = devfs_find_handle (NULL, NULL, i, MINOR (dev), DEVFS_SPECIAL_BLK, 0); if (de) { bdops = devfs_get_ops (de); devfs_put_ops (de); /* We're running in owner module */ } } if (bdops == NULL) return 0; if (bdops->check_media_change == NULL) return 0; if (!bdops->check_media_change(dev)) return 0; printk(KERN_DEBUG "VFS: Disk change detected on device %s\n", bdevname(dev)); if (invalidate_device(dev, 0)) printk("VFS: busy inodes on changed media.\n"); if (bdops->revalidate) bdops->revalidate(dev); return 1;}int ioctl_by_bdev(struct block_device *bdev, unsigned cmd, unsigned long arg){ int res; mm_segment_t old_fs = get_fs(); if (!bdev->bd_op->ioctl) return -EINVAL; set_fs(KERNEL_DS); res = bdev->bd_op->ioctl(bdev->bd_inode, NULL, cmd, arg); set_fs(old_fs); return res;}static int do_open(struct block_device *bdev, struct inode *inode, struct file *file){ int ret = -ENXIO; kdev_t dev = to_kdev_t(bdev->bd_dev); down(&bdev->bd_sem); lock_kernel(); if (!bdev->bd_op) bdev->bd_op = get_blkfops(MAJOR(dev)); if (bdev->bd_op) { ret = 0; if (bdev->bd_op->owner) __MOD_INC_USE_COUNT(bdev->bd_op->owner); if (bdev->bd_op->open) ret = bdev->bd_op->open(inode, file); if (!ret) { bdev->bd_openers++; bdev->bd_inode->i_size = blkdev_size(dev); bdev->bd_inode->i_blkbits = blksize_bits(block_size(dev)); } else { if (bdev->bd_op->owner) __MOD_DEC_USE_COUNT(bdev->bd_op->owner); if (!bdev->bd_openers) bdev->bd_op = NULL; } } unlock_kernel(); up(&bdev->bd_sem); if (ret) bdput(bdev); return ret;}int blkdev_get(struct block_device *bdev, mode_t mode, unsigned flags, int kind){ /* * This crockload is due to bad choice of ->open() type. * It will go away. * For now, block device ->open() routine must _not_ * examine anything in 'inode' argument except ->i_rdev. */ struct file fake_file = {}; struct dentry fake_dentry = {}; fake_file.f_mode = mode; fake_file.f_flags = flags; fake_file.f_dentry = &fake_dentry; fake_dentry.d_inode = bdev->bd_inode; return do_open(bdev, bdev->bd_inode, &fake_file);}int blkdev_open(struct inode * inode, struct file * filp){ struct block_device *bdev; /* * Preserve backwards compatibility and allow large file access * even if userspace doesn't ask for it explicitly. Some mkfs * binary needs it. We might want to drop this workaround * during an unstable branch. */ filp->f_flags |= O_LARGEFILE; bd_acquire(inode); bdev = inode->i_bdev; return do_open(bdev, inode, filp);} int blkdev_put(struct block_device *bdev, int kind){ int ret = 0; kdev_t rdev = to_kdev_t(bdev->bd_dev); /* this should become bdev */ struct inode *bd_inode = bdev->bd_inode; down(&bdev->bd_sem); lock_kernel(); if (kind == BDEV_FILE) __block_fsync(bd_inode); else if (kind == BDEV_FS) fsync_no_super(rdev); if (!--bdev->bd_openers) kill_bdev(bdev); if (bdev->bd_op->release) ret = bdev->bd_op->release(bd_inode, NULL); if (bdev->bd_op->owner) __MOD_DEC_USE_COUNT(bdev->bd_op->owner); if (!bdev->bd_openers) bdev->bd_op = NULL; unlock_kernel(); up(&bdev->bd_sem); bdput(bdev); return ret;}int blkdev_close(struct inode * inode, struct file * filp){ return blkdev_put(inode->i_bdev, BDEV_FILE);}static int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd, unsigned long arg){ if (inode->i_bdev->bd_op->ioctl) return inode->i_bdev->bd_op->ioctl(inode, file, cmd, arg); return -EINVAL;}struct address_space_operations def_blk_aops = { readpage: blkdev_readpage, writepage: blkdev_writepage, sync_page: block_sync_page, prepare_write: blkdev_prepare_write, commit_write: blkdev_commit_write, direct_IO: blkdev_direct_IO,};struct file_operations def_blk_fops = { open: blkdev_open, release: blkdev_close, llseek: block_llseek, read: generic_file_read, write: generic_file_write, mmap: generic_file_mmap, fsync: block_fsync, ioctl: blkdev_ioctl,};const char * bdevname(kdev_t dev){ static char buffer[32]; const char * name = blkdevs[MAJOR(dev)].name; if (!name) name = "unknown-block"; sprintf(buffer, "%s(%d,%d)", name, MAJOR(dev), MINOR(dev)); return buffer;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -