| 1 |
|
|---|
| 2 |
|
|---|
| 3 |
|
|---|
| 4 |
|
|---|
| 5 |
|
|---|
| 6 |
|
|---|
| 7 |
|
|---|
| 8 |
#include <linux/config.h> |
|---|
| 9 |
#include <linux/init.h> |
|---|
| 10 |
#include <linux/mm.h> |
|---|
| 11 |
#include <linux/fcntl.h> |
|---|
| 12 |
#include <linux/slab.h> |
|---|
| 13 |
#include <linux/kmod.h> |
|---|
| 14 |
#include <linux/major.h> |
|---|
| 15 |
#include <linux/devfs_fs_kernel.h> |
|---|
| 16 |
#include <linux/smp_lock.h> |
|---|
| 17 |
#include <linux/highmem.h> |
|---|
| 18 |
#include <linux/blkdev.h> |
|---|
| 19 |
#include <linux/module.h> |
|---|
| 20 |
#include <linux/blkpg.h> |
|---|
| 21 |
#include <linux/buffer_head.h> |
|---|
| 22 |
#include <linux/mpage.h> |
|---|
| 23 |
#include <linux/mount.h> |
|---|
| 24 |
#include <linux/uio.h> |
|---|
| 25 |
#include <linux/namei.h> |
|---|
| 26 |
#include <asm/uaccess.h> |
|---|
| 27 |
|
|---|
| 28 |
struct bdev_inode { |
|---|
| 29 |
struct block_device bdev; |
|---|
| 30 |
struct inode vfs_inode; |
|---|
| 31 |
}; |
|---|
| 32 |
|
|---|
| 33 |
static inline struct bdev_inode *BDEV_I(struct inode *inode) |
|---|
| 34 |
{ |
|---|
| 35 |
return container_of(inode, struct bdev_inode, vfs_inode); |
|---|
| 36 |
} |
|---|
| 37 |
|
|---|
| 38 |
inline struct block_device *I_BDEV(struct inode *inode) |
|---|
| 39 |
{ |
|---|
| 40 |
return &BDEV_I(inode)->bdev; |
|---|
| 41 |
} |
|---|
| 42 |
|
|---|
| 43 |
EXPORT_SYMBOL(I_BDEV); |
|---|
| 44 |
|
|---|
| 45 |
static sector_t max_block(struct block_device *bdev) |
|---|
| 46 |
{ |
|---|
| 47 |
sector_t retval = ~((sector_t)0); |
|---|
| 48 |
loff_t sz = i_size_read(bdev->bd_inode); |
|---|
| 49 |
|
|---|
| 50 |
if (sz) { |
|---|
| 51 |
unsigned int size = block_size(bdev); |
|---|
| 52 |
unsigned int sizebits = blksize_bits(size); |
|---|
| 53 |
retval = (sz >> sizebits); |
|---|
| 54 |
} |
|---|
| 55 |
return retval; |
|---|
| 56 |
} |
|---|
| 57 |
|
|---|
| 58 |
|
|---|
| 59 |
static void kill_bdev(struct block_device *bdev) |
|---|
| 60 |
{ |
|---|
| 61 |
invalidate_bdev(bdev, 1); |
|---|
| 62 |
truncate_inode_pages(bdev->bd_inode->i_mapping, 0); |
|---|
| 63 |
} |
|---|
| 64 |
|
|---|
| 65 |
int set_blocksize(struct block_device *bdev, int size) |
|---|
| 66 |
{ |
|---|
| 67 |
int oldsize; |
|---|
| 68 |
|
|---|
| 69 |
|
|---|
| 70 |
if (size > PAGE_SIZE || size < 512 || (size & (size-1))) |
|---|
| 71 |
return -EINVAL; |
|---|
| 72 |
|
|---|
| 73 |
|
|---|
| 74 |
if (size < bdev_hardsect_size(bdev)) |
|---|
| 75 |
return -EINVAL; |
|---|
| 76 |
|
|---|
| 77 |
oldsize = bdev->bd_block_size; |
|---|
| 78 |
if (oldsize == size) |
|---|
| 79 |
return 0; |
|---|
| 80 |
|
|---|
| 81 |
|
|---|
| 82 |
sync_blockdev(bdev); |
|---|
| 83 |
bdev->bd_block_size = size; |
|---|
| 84 |
bdev->bd_inode->i_blkbits = blksize_bits(size); |
|---|
| 85 |
kill_bdev(bdev); |
|---|
| 86 |
return 0; |
|---|
| 87 |
} |
|---|
| 88 |
|
|---|
| 89 |
EXPORT_SYMBOL(set_blocksize); |
|---|
| 90 |
|
|---|
| 91 |
int sb_set_blocksize(struct super_block *sb, int size) |
|---|
| 92 |
{ |
|---|
| 93 |
int bits; |
|---|
| 94 |
if (set_blocksize(sb->s_bdev, size) < 0) |
|---|
| 95 |
return 0; |
|---|
| 96 |
sb->s_blocksize = size; |
|---|
| 97 |
for (bits = 9, size >>= 9; size >>= 1; bits++) |
|---|
| 98 |
; |
|---|
| 99 |
sb->s_blocksize_bits = bits; |
|---|
| 100 |
return sb->s_blocksize; |
|---|
| 101 |
} |
|---|
| 102 |
|
|---|
| 103 |
EXPORT_SYMBOL(sb_set_blocksize); |
|---|
| 104 |
|
|---|
| 105 |
int sb_min_blocksize(struct super_block *sb, int size) |
|---|
| 106 |
{ |
|---|
| 107 |
int minsize = bdev_hardsect_size(sb->s_bdev); |
|---|
| 108 |
if (size < minsize) |
|---|
| 109 |
size = minsize; |
|---|
| 110 |
return sb_set_blocksize(sb, size); |
|---|
| 111 |
} |
|---|
| 112 |
|
|---|
| 113 |
EXPORT_SYMBOL(sb_min_blocksize); |
|---|
| 114 |
|
|---|
| 115 |
static int |
|---|
| 116 |
blkdev_get_block(struct inode *inode, sector_t iblock, |
|---|
| 117 |
struct buffer_head *bh, int create) |
|---|
| 118 |
{ |
|---|
| 119 |
if (iblock >= max_block(I_BDEV(inode))) { |
|---|
| 120 |
if (create) |
|---|
| 121 |
return -EIO; |
|---|
| 122 |
|
|---|
| 123 |
|
|---|
| 124 |
|
|---|
| 125 |
|
|---|
| 126 |
|
|---|
| 127 |
|
|---|
| 128 |
|
|---|
| 129 |
return 0; |
|---|
| 130 |
} |
|---|
| 131 |
bh->b_bdev = I_BDEV(inode); |
|---|
| 132 |
bh->b_blocknr = iblock; |
|---|
| 133 |
set_buffer_mapped(bh); |
|---|
| 134 |
return 0; |
|---|
| 135 |
} |
|---|
| 136 |
|
|---|
| 137 |
static int |
|---|
| 138 |
blkdev_get_blocks(struct inode *inode, sector_t iblock, |
|---|
| 139 |
unsigned long max_blocks, struct buffer_head *bh, int create) |
|---|
| 140 |
{ |
|---|
| 141 |
if ((iblock + max_blocks) > max_block(I_BDEV(inode))) |
|---|
| 142 |
return -EIO; |
|---|
| 143 |
|
|---|
| 144 |
bh->b_bdev = I_BDEV(inode); |
|---|
| 145 |
bh->b_blocknr = iblock; |
|---|
| 146 |
bh->b_size = max_blocks << inode->i_blkbits; |
|---|
| 147 |
set_buffer_mapped(bh); |
|---|
| 148 |
return 0; |
|---|
| 149 |
} |
|---|
| 150 |
|
|---|
| 151 |
static ssize_t |
|---|
| 152 |
blkdev_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, |
|---|
| 153 |
loff_t offset, unsigned long nr_segs) |
|---|
| 154 |
{ |
|---|
| 155 |
struct file *file = iocb->ki_filp; |
|---|
| 156 |
struct inode *inode = file->f_mapping->host; |
|---|
| 157 |
|
|---|
| 158 |
return blockdev_direct_IO_no_locking(rw, iocb, inode, I_BDEV(inode), |
|---|
| 159 |
iov, offset, nr_segs, blkdev_get_blocks, NULL); |
|---|
| 160 |
} |
|---|
| 161 |
|
|---|
| 162 |
static int blkdev_writepage(struct page *page, struct writeback_control *wbc) |
|---|
| 163 |
{ |
|---|
| 164 |
return block_write_full_page(page, blkdev_get_block, wbc); |
|---|
| 165 |
} |
|---|
| 166 |
|
|---|
| 167 |
static int blkdev_readpage(struct file * file, struct page * page) |
|---|
| 168 |
{ |
|---|
| 169 |
return block_read_full_page(page, blkdev_get_block); |
|---|
| 170 |
} |
|---|
| 171 |
|
|---|
| 172 |
static int blkdev_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to) |
|---|
| 173 |
{ |
|---|
| 174 |
return block_prepare_write(page, from, to, blkdev_get_block); |
|---|
| 175 |
} |
|---|
| 176 |
|
|---|
| 177 |
static int blkdev_commit_write(struct file *file, struct page *page, unsigned from, unsigned to) |
|---|
| 178 |
{ |
|---|
| 179 |
return block_commit_write(page, from, to); |
|---|
| 180 |
} |
|---|
| 181 |
|
|---|
| 182 |
|
|---|
| 183 |
|
|---|
| 184 |
|
|---|
| 185 |
|
|---|
| 186 |
|
|---|
| 187 |
static loff_t block_llseek(struct file *file, loff_t offset, int origin) |
|---|
| 188 |
{ |
|---|
| 189 |
struct inode *bd_inode = file->f_mapping->host; |
|---|
| 190 |
loff_t size; |
|---|
| 191 |
loff_t retval; |
|---|
| 192 |
|
|---|
| 193 |
down(&bd_inode->i_sem); |
|---|
| 194 |
size = i_size_read(bd_inode); |
|---|
| 195 |
|
|---|
| 196 |
switch (origin) { |
|---|
| 197 |
case 2: |
|---|
| 198 |
offset += size; |
|---|
| 199 |
break; |
|---|
| 200 |
case 1: |
|---|
| 201 |
offset += file->f_pos; |
|---|
| 202 |
} |
|---|
| 203 |
retval = -EINVAL; |
|---|
| 204 |
if (offset >= 0 && offset <= size) { |
|---|
| 205 |
if (offset != file->f_pos) { |
|---|
| 206 |
file->f_pos = offset; |
|---|
| 207 |
} |
|---|
| 208 |
retval = offset; |
|---|
| 209 |
} |
|---|
| 210 |
up(&bd_inode->i_sem); |
|---|
| 211 |
return retval; |
|---|
| 212 |
} |
|---|
| 213 |
|
|---|
| 214 |
|
|---|
| 215 |
|
|---|
| 216 |
|
|---|
| 217 |
|
|---|
| 218 |
|
|---|
| 219 |
static int block_fsync(struct file *filp, struct dentry *dentry, int datasync) |
|---|
| 220 |
{ |
|---|
| 221 |
return sync_blockdev(I_BDEV(filp->f_mapping->host)); |
|---|
| 222 |
} |
|---|
| 223 |
|
|---|
| 224 |
|
|---|
| 225 |
|
|---|
| 226 |
|
|---|
| 227 |
|
|---|
| 228 |
static spinlock_t bdev_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; |
|---|
| 229 |
static kmem_cache_t * bdev_cachep; |
|---|
| 230 |
|
|---|
| 231 |
static struct inode *bdev_alloc_inode(struct super_block *sb) |
|---|
| 232 |
{ |
|---|
| 233 |
struct bdev_inode *ei = kmem_cache_alloc(bdev_cachep, SLAB_KERNEL); |
|---|
| 234 |
if (!ei) |
|---|
| 235 |
return NULL; |
|---|
| 236 |
return &ei->vfs_inode; |
|---|
| 237 |
} |
|---|
| 238 |
|
|---|
| 239 |
static void bdev_destroy_inode(struct inode *inode) |
|---|
| 240 |
{ |
|---|
| 241 |
struct bdev_inode *bdi = BDEV_I(inode); |
|---|
| 242 |
|
|---|
| 243 |
bdi->bdev.bd_inode_backing_dev_info = NULL; |
|---|
| 244 |
kmem_cache_free(bdev_cachep, bdi); |
|---|
| 245 |
} |
|---|
| 246 |
|
|---|
| 247 |
static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) |
|---|
| 248 |
{ |
|---|
| 249 |
struct bdev_inode *ei = (struct bdev_inode *) foo; |
|---|
| 250 |
struct block_device *bdev = &ei->bdev; |
|---|
| 251 |
|
|---|
| 252 |
if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == |
|---|
| 253 |
SLAB_CTOR_CONSTRUCTOR) |
|---|
| 254 |
{ |
|---|
| 255 |
memset(bdev, 0, sizeof(*bdev)); |
|---|
| 256 |
sema_init(&bdev->bd_sem, 1); |
|---|
| 257 |
sema_init(&bdev->bd_mount_sem, 1); |
|---|
| 258 |
INIT_LIST_HEAD(&bdev->bd_inodes); |
|---|
| 259 |
INIT_LIST_HEAD(&bdev->bd_list); |
|---|
| 260 |
inode_init_once(&ei->vfs_inode); |
|---|
| 261 |
} |
|---|
| 262 |
} |
|---|
| 263 |
|
|---|
| 264 |
static inline void __bd_forget(struct inode *inode) |
|---|
| 265 |
{ |
|---|
| 266 |
list_del_init(&inode->i_devices); |
|---|
| 267 |
inode->i_bdev = NULL; |
|---|
| 268 |
inode->i_mapping = &inode->i_data; |
|---|
| 269 |
} |
|---|
| 270 |
|
|---|
| 271 |
static void bdev_clear_inode(struct inode *inode) |
|---|
| 272 |
{ |
|---|
| 273 |
struct block_device *bdev = &BDEV_I(inode)->bdev; |
|---|
| 274 |
struct list_head *p; |
|---|
| 275 |
spin_lock(&bdev_lock); |
|---|
| 276 |
while ( (p = bdev->bd_inodes.next) != &bdev->bd_inodes ) { |
|---|
| 277 |
__bd_forget(list_entry(p, struct inode, i_devices)); |
|---|
| 278 |
} |
|---|
| 279 |
list_del_init(&bdev->bd_list); |
|---|
| 280 |
spin_unlock(&bdev_lock); |
|---|
| 281 |
} |
|---|
| 282 |
|
|---|
| 283 |
static struct super_operations bdev_sops = { |
|---|
| 284 |
.statfs = simple_statfs, |
|---|
| 285 |
.alloc_inode = bdev_alloc_inode, |
|---|
| 286 |
.destroy_inode = bdev_destroy_inode, |
|---|
| 287 |
.drop_inode = generic_delete_inode, |
|---|
| 288 |
.clear_inode = bdev_clear_inode, |
|---|
| 289 |
}; |
|---|
| 290 |
|
|---|
| 291 |
static struct super_block *bd_get_sb(struct file_system_type *fs_type, |
|---|
| 292 |
int flags, const char *dev_name, void *data) |
|---|
| 293 |
{ |
|---|
| 294 |
return get_sb_pseudo(fs_type, "bdev:", &bdev_sops, 0x62646576); |
|---|
| 295 |
} |
|---|
| 296 |
|
|---|
| 297 |
static struct file_system_type bd_type = { |
|---|
| 298 |
.name = "bdev", |
|---|
| 299 |
.get_sb = bd_get_sb, |
|---|
| 300 |
.kill_sb = kill_anon_super, |
|---|
| 301 |
}; |
|---|
| 302 |
|
|---|
| 303 |
static struct vfsmount *bd_mnt; |
|---|
| 304 |
struct super_block *blockdev_superblock; |
|---|
| 305 |
|
|---|
| 306 |
void __init bdev_cache_init(void) |
|---|
| 307 |
{ |
|---|
| 308 |
int err; |
|---|
| 309 |
bdev_cachep = kmem_cache_create("bdev_cache", sizeof(struct bdev_inode), |
|---|
| 310 |
0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|SLAB_PANIC, |
|---|
| 311 |
init_once, NULL); |
|---|
| 312 |
err = register_filesystem(&bd_type); |
|---|
| 313 |
if (err) |
|---|
| 314 |
panic("Cannot register bdev pseudo-fs"); |
|---|
| 315 |
bd_mnt = kern_mount(&bd_type); |
|---|
| 316 |
err = PTR_ERR(bd_mnt); |
|---|
| 317 |
if (IS_ERR(bd_mnt)) |
|---|
| 318 |
panic("Cannot create bdev pseudo-fs"); |
|---|
| 319 |
blockdev_superblock = bd_mnt->mnt_sb; |
|---|
| 320 |
} |
|---|
| 321 |
|
|---|
| 322 |
|
|---|
| 323 |
|
|---|
| 324 |
|
|---|
| 325 |
|
|---|
| 326 |
|
|---|
| 327 |
static inline unsigned long hash(dev_t dev) |
|---|
| 328 |
{ |
|---|
| 329 |
return MAJOR(dev)+MINOR(dev); |
|---|
| 330 |
} |
|---|
| 331 |
|
|---|
| 332 |
static int bdev_test(struct inode *inode, void *data) |
|---|
| 333 |
{ |
|---|
| 334 |
return BDEV_I(inode)->bdev.bd_dev == *(dev_t *)data; |
|---|
| 335 |
} |
|---|
| 336 |
|
|---|
| 337 |
static int bdev_set(struct inode *inode, void *data) |
|---|
| 338 |
{ |
|---|
| 339 |
BDEV_I(inode)->bdev.bd_dev = *(dev_t *)data; |
|---|
| 340 |
return 0; |
|---|
| 341 |
} |
|---|
| 342 |
|
|---|
| 343 |
static LIST_HEAD(all_bdevs); |
|---|
| 344 |
|
|---|
| 345 |
struct block_device *bdget(dev_t dev) |
|---|
| 346 |
{ |
|---|
| 347 |
struct block_device *bdev; |
|---|
| 348 |
struct inode *inode; |
|---|
| 349 |
|
|---|
| 350 |
inode = iget5_locked(bd_mnt->mnt_sb, hash(dev), |
|---|
| 351 |
bdev_test, bdev_set, &dev); |
|---|
| 352 |
|
|---|
| 353 |
if (!inode) |
|---|
| 354 |
return NULL; |
|---|
| 355 |
|
|---|
| 356 |
bdev = &BDEV_I(inode)->bdev; |
|---|
| 357 |
|
|---|
| 358 |
if (inode->i_state & I_NEW) { |
|---|
| 359 |
bdev->bd_contains = NULL; |
|---|
| 360 |
bdev->bd_inode = inode; |
|---|
| 361 |
bdev->bd_block_size = (1 << inode->i_blkbits); |
|---|
| 362 |
bdev->bd_part_count = 0; |
|---|
| 363 |
bdev->bd_invalidated = 0; |
|---|
| 364 |
inode->i_mode = S_IFBLK; |
|---|
| 365 |
inode->i_rdev = dev; |
|---|
| 366 |
inode->i_bdev = bdev; |
|---|
| 367 |
inode->i_data.a_ops = &def_blk_aops; |
|---|
| 368 |
mapping_set_gfp_mask(&inode->i_data, GFP_USER); |
|---|
| 369 |
inode->i_data.backing_dev_info = &default_backing_dev_info; |
|---|
| 370 |
spin_lock(&bdev_lock); |
|---|
| 371 |
list_add(&bdev->bd_list, &all_bdevs); |
|---|
| 372 |
spin_unlock(&bdev_lock); |
|---|
| 373 |
unlock_new_inode(inode); |
|---|
| 374 |
} |
|---|
| 375 |
return bdev; |
|---|
| 376 |
} |
|---|
| 377 |
|
|---|
| 378 |
EXPORT_SYMBOL(bdget); |
|---|
| 379 |
|
|---|
| 380 |
long nr_blockdev_pages(void) |
|---|
| 381 |
{ |
|---|
| 382 |
struct list_head *p; |
|---|
| 383 |
long ret = 0; |
|---|
| 384 |
spin_lock(&bdev_lock); |
|---|
| 385 |
list_for_each(p, &all_bdevs) { |
|---|
| 386 |
struct block_device *bdev; |
|---|
| 387 |
bdev = list_entry(p, struct block_device, bd_list); |
|---|
| 388 |
ret += bdev->bd_inode->i_mapping->nrpages; |
|---|
| 389 |
} |
|---|
| 390 |
spin_unlock(&bdev_lock); |
|---|
| 391 |
return ret; |
|---|
| 392 |
} |
|---|
| 393 |
|
|---|
| 394 |
void bdput(struct block_device *bdev) |
|---|
| 395 |
{ |
|---|
| 396 |
iput(bdev->bd_inode); |
|---|
| 397 |
} |
|---|
| 398 |
|
|---|
| 399 |
EXPORT_SYMBOL(bdput); |
|---|
| 400 |
|
|---|
| 401 |
static struct block_device *bd_acquire(struct inode *inode) |
|---|
| 402 |
{ |
|---|
| 403 |
struct block_device *bdev; |
|---|
| 404 |
spin_lock(&bdev_lock); |
|---|
| 405 |
bdev = inode->i_bdev; |
|---|
| 406 |
if (bdev && igrab(bdev->bd_inode)) { |
|---|
| 407 |
spin_unlock(&bdev_lock); |
|---|
| 408 |
return bdev; |
|---|
| 409 |
} |
|---|
| 410 |
spin_unlock(&bdev_lock); |
|---|
| 411 |
bdev = bdget(inode->i_rdev); |
|---|
| 412 |
if (bdev) { |
|---|
| 413 |
spin_lock(&bdev_lock); |
|---|
| 414 |
if (inode->i_bdev) |
|---|
| 415 |
__bd_forget(inode); |
|---|
| 416 |
inode->i_bdev = bdev; |
|---|
| 417 |
inode->i_mapping = bdev->bd_inode->i_mapping; |
|---|
| 418 |
list_add(&inode->i_devices, &bdev->bd_inodes); |
|---|
| 419 |
spin_unlock(&bdev_lock); |
|---|
| 420 |
} |
|---|
| 421 |
return bdev; |
|---|
| 422 |
} |
|---|
| 423 |
|
|---|
| 424 |
|
|---|
| 425 |
|
|---|
| 426 |
void bd_forget(struct inode *inode) |
|---|
| 427 |
{ |
|---|
| 428 |
spin_lock(&bdev_lock); |
|---|
| 429 |
if (inode->i_bdev) |
|---|
| 430 |
__bd_forget(inode); |
|---|
| 431 |
spin_unlock(&bdev_lock); |
|---|
| 432 |
} |
|---|
| 433 |
|
|---|
| 434 |
int bd_claim(struct block_device *bdev, void *holder) |
|---|
| 435 |
{ |
|---|
| 436 |
int res; |
|---|
| 437 |
spin_lock(&bdev_lock); |
|---|
| 438 |
|
|---|
| 439 |
|
|---|
| 440 |
if (bdev->bd_holder == holder) |
|---|
| 441 |
res = 0; |
|---|
| 442 |
else if (bdev->bd_holder != NULL) |
|---|
| 443 |
res = -EBUSY; |
|---|
| 444 |
else if (bdev->bd_contains == bdev) |
|---|
| 445 |
res = 0; |
|---|
| 446 |
|
|---|
| 447 |
else if (bdev->bd_contains->bd_holder == bd_claim) |
|---|
| 448 |
res = 0; |
|---|
| 449 |
else if (bdev->bd_contains->bd_holder != NULL) |
|---|
| 450 |
res = -EBUSY; |
|---|
| 451 |
else |
|---|
| 452 |
res = 0; |
|---|
| 453 |
|
|---|
| 454 |
|
|---|
| 455 |
if (res==0) { |
|---|
| 456 |
|
|---|
| 457 |
|
|---|
| 458 |
|
|---|
| 459 |
|
|---|
| 460 |
bdev->bd_contains->bd_holders ++; |
|---|
| 461 |
bdev->bd_contains->bd_holder = bd_claim; |
|---|
| 462 |
bdev->bd_holders++; |
|---|
| 463 |
bdev->bd_holder = holder; |
|---|
| 464 |
} |
|---|
| 465 |
spin_unlock(&bdev_lock); |
|---|
| 466 |
return res; |
|---|
| 467 |
} |
|---|
| 468 |
|
|---|
| 469 |
EXPORT_SYMBOL(bd_claim); |
|---|
| 470 |
|
|---|
| 471 |
void bd_release(struct block_device *bdev) |
|---|
| 472 |
{ |
|---|
| 473 |
spin_lock(&bdev_lock); |
|---|
| 474 |
if (!--bdev->bd_contains->bd_holders) |
|---|
| 475 |
bdev->bd_contains->bd_holder = NULL; |
|---|
| 476 |
if (!--bdev->bd_holders) |
|---|
| 477 |
bdev->bd_holder = NULL; |
|---|
| 478 |
spin_unlock(&bdev_lock); |
|---|
| 479 |
} |
|---|
| 480 |
|
|---|
| 481 |
EXPORT_SYMBOL(bd_release); |
|---|
| 482 |
|
|---|
| 483 |
|
|---|
| 484 |
|
|---|
| 485 |
|
|---|
| 486 |
|
|---|
| 487 |
|
|---|
| 488 |
|
|---|
| 489 |
|
|---|
| 490 |
struct block_device *open_by_devnum(dev_t dev, unsigned mode) |
|---|
| 491 |
{ |
|---|
| 492 |
struct block_device *bdev = bdget(dev); |
|---|
| 493 |
int err = -ENOMEM; |
|---|
| 494 |
int flags = mode & FMODE_WRITE ? O_RDWR : O_RDONLY; |
|---|
| 495 |
if (bdev) |
|---|
| 496 |
err = blkdev_get(bdev, mode, flags); |
|---|
| 497 |
return err ? ERR_PTR(err) : bdev; |
|---|
| 498 |
} |
|---|
| 499 |
|
|---|
| 500 |
EXPORT_SYMBOL(open_by_devnum); |
|---|
| 501 |
|
|---|
| 502 |
|
|---|
| 503 |
|
|---|
| 504 |
|
|---|
| 505 |
|
|---|
| 506 |
|
|---|
| 507 |
|
|---|
| 508 |
|
|---|
| 509 |
|
|---|
| 510 |
|
|---|
| 511 |
int check_disk_change(struct block_device *bdev) |
|---|
| 512 |
{ |
|---|
| 513 |
struct gendisk *disk = bdev->bd_disk; |
|---|
| 514 |
struct block_device_operations * bdops = disk->fops; |
|---|
| 515 |
|
|---|
| 516 |
if (!bdops->media_changed) |
|---|
| 517 |
return 0; |
|---|
| 518 |
if (!bdops->media_changed(bdev->bd_disk)) |
|---|
| 519 |
return 0; |
|---|
| 520 |
|
|---|
| 521 |
if (__invalidate_device(bdev, 0)) |
|---|
| 522 |
printk("VFS: busy inodes on changed media.\n"); |
|---|
| 523 |
|
|---|
| 524 |
if (bdops->revalidate_disk) |
|---|
| 525 |
bdops->revalidate_disk(bdev->bd_disk); |
|---|
| 526 |
if (bdev->bd_disk->minors > 1) |
|---|
| 527 |
bdev->bd_invalidated = 1; |
|---|
| 528 |
return 1; |
|---|
| 529 |
} |
|---|
| 530 |
|
|---|
| 531 |
EXPORT_SYMBOL(check_disk_change); |
|---|
| 532 |
|
|---|
| 533 |
void bd_set_size(struct block_device *bdev, loff_t size) |
|---|
| 534 |
{ |
|---|
| 535 |
unsigned bsize = bdev_hardsect_size(bdev); |
|---|
| 536 |
|
|---|
| 537 |
bdev->bd_inode->i_size = size; |
|---|
| 538 |
while (bsize < PAGE_CACHE_SIZE) { |
|---|
| 539 |
if (size & bsize) |
|---|
| 540 |
break; |
|---|
| 541 |
bsize <<= 1; |
|---|
| 542 |
} |
|---|
| 543 |
bdev->bd_block_size = bsize; |
|---|
| 544 |
bdev->bd_inode->i_blkbits = blksize_bits(bsize); |
|---|
| 545 |
} |
|---|
| 546 |
EXPORT_SYMBOL(bd_set_size); |
|---|
| 547 |
|
|---|
| 548 |
static int do_open(struct block_device *bdev, struct file *file) |
|---|
| 549 |
{ |
|---|
| 550 |
struct module *owner = NULL; |
|---|
| 551 |
struct gendisk *disk; |
|---|
| 552 |
int ret = -ENXIO; |
|---|
| 553 |
int part; |
|---|
| 554 |
|
|---|
| 555 |
file->f_mapping = bdev->bd_inode->i_mapping; |
|---|
| 556 |
lock_kernel(); |
|---|
| 557 |
disk = get_gendisk(bdev->bd_dev, &part); |
|---|
| 558 |
if (!disk) { |
|---|
| 559 |
unlock_kernel(); |
|---|
| 560 |
bdput(bdev); |
|---|
| 561 |
return ret; |
|---|
| 562 |
} |
|---|
| 563 |
owner = disk->fops->owner; |
|---|
| 564 |
|
|---|
| 565 |
down(&bdev->bd_sem); |
|---|
| 566 |
if (!bdev->bd_openers) { |
|---|
| 567 |
bdev->bd_disk = disk; |
|---|
| 568 |
bdev->bd_contains = bdev; |
|---|
| 569 |
if (!part) { |
|---|
| 570 |
struct backing_dev_info *bdi; |
|---|
| 571 |
if (disk->fops->open) { |
|---|
| 572 |
ret = disk->fops->open(bdev->bd_inode, file); |
|---|
| 573 |
if (ret) |
|---|
| 574 |
goto out_first; |
|---|
| 575 |
} |
|---|
| 576 |
if (!bdev->bd_openers) { |
|---|
| 577 |
bd_set_size(bdev,(loff_t)get_capacity(disk)<<9); |
|---|
| 578 |
bdi = blk_get_backing_dev_info(bdev); |
|---|
| 579 |
if (bdi == NULL) |
|---|
| 580 |
bdi = &default_backing_dev_info; |
|---|
| 581 |
bdev->bd_inode->i_data.backing_dev_info = bdi; |
|---|
| 582 |
} |
|---|
| 583 |
if (bdev->bd_invalidated) |
|---|
| 584 |
rescan_partitions(disk, bdev); |
|---|
| 585 |
} else { |
|---|
| 586 |
struct hd_struct *p; |
|---|
| 587 |
struct block_device *whole; |
|---|
| 588 |
whole = bdget_disk(disk, 0); |
|---|
| 589 |
ret = -ENOMEM; |
|---|
| 590 |
if (!whole) |
|---|
| 591 |
goto out_first; |
|---|
| 592 |
ret = blkdev_get(whole, file->f_mode, file->f_flags); |
|---|
| 593 |
if (ret) |
|---|
| 594 |
goto out_first; |
|---|
| 595 |
bdev->bd_contains = whole; |
|---|
| 596 |
down(&whole->bd_sem); |
|---|
| 597 |
whole->bd_part_count++; |
|---|
| 598 |
p = disk->part[part - 1]; |
|---|
| 599 |
bdev->bd_inode->i_data.backing_dev_info = |
|---|
| 600 |
whole->bd_inode->i_data.backing_dev_info; |
|---|
| 601 |
if (!(disk->flags & GENHD_FL_UP) || !p || !p->nr_sects) { |
|---|
| 602 |
whole->bd_part_count--; |
|---|
| 603 |
up(&whole->bd_sem); |
|---|
| 604 |
ret = -ENXIO; |
|---|
| 605 |
goto out_first; |
|---|
| 606 |
} |
|---|
| 607 |
kobject_get(&p->kobj); |
|---|
| 608 |
bdev->bd_part = p; |
|---|
| 609 |
bd_set_size(bdev, (loff_t) p->nr_sects << 9); |
|---|
| 610 |
up(&whole->bd_sem); |
|---|
| 611 |
} |
|---|
| 612 |
} else { |
|---|
| 613 |
put_disk(disk); |
|---|
| 614 |
module_put(owner); |
|---|
| 615 |
if (bdev->bd_contains == bdev) { |
|---|
| 616 |
if (bdev->bd_disk->fops->open) { |
|---|
| 617 |
ret = bdev->bd_disk->fops->open(bdev->bd_inode, file); |
|---|
| 618 |
if (ret) |
|---|
| 619 |
goto out; |
|---|
| 620 |
} |
|---|
| 621 |
if (bdev->bd_invalidated) |
|---|
| 622 |
rescan_partitions(bdev->bd_disk, bdev); |
|---|
| 623 |
} else { |
|---|
| 624 |
down(&bdev->bd_contains->bd_sem); |
|---|
| 625 |
bdev->bd_contains->bd_part_count++; |
|---|
| 626 |
up(&bdev->bd_contains->bd_sem); |
|---|
| 627 |
} |
|---|
| 628 |
} |
|---|
| 629 |
bdev->bd_openers++; |
|---|
| 630 |
up(&bdev->bd_sem); |
|---|
| 631 |
unlock_kernel(); |
|---|
| 632 |
return 0; |
|---|
| 633 |
|
|---|
| 634 |
out_first: |
|---|
| 635 |
bdev->bd_disk = NULL; |
|---|
| 636 |
bdev->bd_inode->i_data.backing_dev_info = &default_backing_dev_info; |
|---|
| 637 |
if (bdev != bdev->bd_contains) |
|---|
| 638 |
blkdev_put(bdev->bd_contains); |
|---|
| 639 |
bdev->bd_contains = NULL; |
|---|
| 640 |
put_disk(disk); |
|---|
| 641 |
module_put(owner); |
|---|
| 642 |
out: |
|---|
| 643 |
up(&bdev->bd_sem); |
|---|
| 644 |
unlock_kernel(); |
|---|
| 645 |
if (ret) |
|---|
| 646 |
bdput(bdev); |
|---|
| 647 |
return ret; |
|---|
| 648 |
} |
|---|
| 649 |
|
|---|
| 650 |
int blkdev_get(struct block_device *bdev, mode_t mode, unsigned flags) |
|---|
| 651 |
{ |
|---|
| 652 |
|
|---|
| 653 |
|
|---|
| 654 |
|
|---|
| 655 |
|
|---|
| 656 |
|
|---|
| 657 |
|
|---|
| 658 |
struct file fake_file = {}; |
|---|
| 659 |
struct dentry fake_dentry = {}; |
|---|
| 660 |
fake_file.f_mode = mode; |
|---|
| 661 |
fake_file.f_flags = flags; |
|---|
| 662 |
fake_file.f_dentry = &fake_dentry; |
|---|
| 663 |
fake_dentry.d_inode = bdev->bd_inode; |
|---|
| 664 |
|
|---|
| 665 |
return do_open(bdev, &fake_file); |
|---|
| 666 |
} |
|---|
| 667 |
|
|---|
| 668 |
EXPORT_SYMBOL(blkdev_get); |
|---|
| 669 |
|
|---|
| 670 |
int blkdev_open(struct inode * inode, struct file * filp) |
|---|
| 671 |
{ |
|---|
| 672 |
struct block_device *bdev; |
|---|
| 673 |
int res; |
|---|
| 674 |
|
|---|
| 675 |
|
|---|
| 676 |
|
|---|
| 677 |
|
|---|
| 678 |
|
|---|
| 679 |
|
|---|
| 680 |
|
|---|
| 681 |
filp->f_flags |= O_LARGEFILE; |
|---|
| 682 |
|
|---|
| 683 |
bdev = bd_acquire(inode); |
|---|
| 684 |
|
|---|
| 685 |
res = do_open(bdev, filp); |
|---|
| 686 |
if (res) |
|---|
| 687 |
return res; |
|---|
| 688 |
|
|---|
| 689 |
if (!(filp->f_flags & O_EXCL) ) |
|---|
| 690 |
return 0; |
|---|
| 691 |
|
|---|
| 692 |
if (!(res = bd_claim(bdev, filp))) |
|---|
| 693 |
return 0; |
|---|
| 694 |
|
|---|
| 695 |
blkdev_put(bdev); |
|---|
| 696 |
return res; |
|---|
| 697 |
} |
|---|
| 698 |
|
|---|
| 699 |
EXPORT_SYMBOL(blkdev_open); |
|---|
| 700 |
|
|---|
| 701 |
int blkdev_put(struct block_device *bdev) |
|---|
| 702 |
{ |
|---|
| 703 |
int ret = 0; |
|---|
| 704 |
struct inode *bd_inode = bdev->bd_inode; |
|---|
| 705 |
struct gendisk *disk = bdev->bd_disk; |
|---|
| 706 |
|
|---|
| 707 |
down(&bdev->bd_sem); |
|---|
| 708 |
lock_kernel(); |
|---|
| 709 |
if (!--bdev->bd_openers) { |
|---|
| 710 |
sync_blockdev(bdev); |
|---|
| 711 |
kill_bdev(bdev); |
|---|
| 712 |
} |
|---|
| 713 |
if (bdev->bd_contains == bdev) { |
|---|
| 714 |
if (disk->fops->release) |
|---|
| 715 |
ret = disk->fops->release(bd_inode, NULL); |
|---|
| 716 |
} else { |
|---|
| 717 |
down(&bdev->bd_contains->bd_sem); |
|---|
| 718 |
bdev->bd_contains->bd_part_count--; |
|---|
| 719 |
up(&bdev->bd_contains->bd_sem); |
|---|
| 720 |
} |
|---|
| 721 |
if (!bdev->bd_openers) { |
|---|
| 722 |
struct module *owner = disk->fops->owner; |
|---|
| 723 |
|
|---|
| 724 |
put_disk(disk); |
|---|
| 725 |
module_put(owner); |
|---|
| 726 |
|
|---|
| 727 |
if (bdev->bd_contains != bdev) { |
|---|
| 728 |
kobject_put(&bdev->bd_part->kobj); |
|---|
| 729 |
bdev->bd_part = NULL; |
|---|
| 730 |
} |
|---|
| 731 |
bdev->bd_disk = NULL; |
|---|
| 732 |
bdev->bd_inode->i_data.backing_dev_info = &default_backing_dev_info; |
|---|
| 733 |
if (bdev != bdev->bd_contains) { |
|---|
| 734 |
blkdev_put(bdev->bd_contains); |
|---|
| 735 |
} |
|---|
| 736 |
bdev->bd_contains = NULL; |
|---|
| 737 |
} |
|---|
| 738 |
unlock_kernel(); |
|---|
| 739 |
up(&bdev->bd_sem); |
|---|
| 740 |
bdput(bdev); |
|---|
| 741 |
return ret; |
|---|
| 742 |
} |
|---|
| 743 |
|
|---|
| 744 |
EXPORT_SYMBOL(blkdev_put); |
|---|
| 745 |
|
|---|
| 746 |
static int blkdev_close(struct inode * inode, struct file * filp) |
|---|
| 747 |
{ |
|---|
| 748 |
struct block_device *bdev = I_BDEV(filp->f_mapping->host); |
|---|
| 749 |
if (bdev->bd_holder == filp) |
|---|
| 750 |
bd_release(bdev); |
|---|
| 751 |
return blkdev_put(bdev); |
|---|
| 752 |
} |
|---|
| 753 |
|
|---|
| 754 |
static ssize_t blkdev_file_write(struct file *file, const char __user *buf, |
|---|
| 755 |
size_t count, loff_t *ppos) |
|---|
| 756 |
{ |
|---|
| 757 |
struct iovec local_iov = { .iov_base = (void __user *)buf, .iov_len = count }; |
|---|
| 758 |
|
|---|
| 759 |
return generic_file_write_nolock(file, &local_iov, 1, ppos); |
|---|
| 760 |
} |
|---|
| 761 |
|
|---|
| 762 |
static ssize_t blkdev_file_aio_write(struct kiocb *iocb, const char __user *buf, |
|---|
| 763 |
size_t count, loff_t pos) |
|---|
| 764 |
{ |
|---|
| 765 |
struct iovec local_iov = { .iov_base = (void __user *)buf, .iov_len = count }; |
|---|
| 766 |
|
|---|
| 767 |
return generic_file_aio_write_nolock(iocb, &local_iov, 1, &iocb->ki_pos); |
|---|
| 768 |
} |
|---|
| 769 |
|
|---|
| 770 |
static int block_ioctl(struct inode *inode, struct file *file, unsigned cmd, |
|---|
| 771 |
unsigned long arg) |
|---|
| 772 |
{ |
|---|
| 773 |
return blkdev_ioctl(file->f_mapping->host, file, cmd, arg); |
|---|
| 774 |
} |
|---|
| 775 |
|
|---|
| 776 |
struct address_space_operations def_blk_aops = { |
|---|
| 777 |
.readpage = blkdev_readpage, |
|---|
| 778 |
.writepage = blkdev_writepage, |
|---|
| 779 |
.sync_page = block_sync_page, |
|---|
| 780 |
.prepare_write = blkdev_prepare_write, |
|---|
| 781 |
.commit_write = blkdev_commit_write, |
|---|
| 782 |
.writepages = generic_writepages, |
|---|
| 783 |
.direct_IO = blkdev_direct_IO, |
|---|
| 784 |
}; |
|---|
| 785 |
|
|---|
| 786 |
struct file_operations def_blk_fops = { |
|---|
| 787 |
.open = blkdev_open, |
|---|
| 788 |
.release = blkdev_close, |
|---|
| 789 |
.llseek = block_llseek, |
|---|
| 790 |
.read = generic_file_read, |
|---|
| 791 |
.write = blkdev_file_write, |
|---|
| 792 |
.aio_read = generic_file_aio_read, |
|---|
| 793 |
.aio_write = blkdev_file_aio_write, |
|---|
| 794 |
.mmap = generic_file_mmap, |
|---|
| 795 |
.fsync = block_fsync, |
|---|
| 796 |
.ioctl = block_ioctl, |
|---|
| 797 |
.readv = generic_file_readv, |
|---|
| 798 |
.writev = generic_file_write_nolock, |
|---|
| 799 |
.sendfile = generic_file_sendfile, |
|---|
| 800 |
}; |
|---|
| 801 |
|
|---|
| 802 |
EXPORT_SYMBOL(def_blk_fops); |
|---|
| 803 |
|
|---|
| 804 |
int ioctl_by_bdev(struct block_device *bdev, unsigned cmd, unsigned long arg) |
|---|
| 805 |
{ |
|---|
| 806 |
int res; |
|---|
| 807 |
mm_segment_t old_fs = get_fs(); |
|---|
| 808 |
set_fs(KERNEL_DS); |
|---|
| 809 |
res = blkdev_ioctl(bdev->bd_inode, NULL, cmd, arg); |
|---|
| 810 |
set_fs(old_fs); |
|---|
| 811 |
return res; |
|---|
| 812 |
} |
|---|
| 813 |
|
|---|
| 814 |
EXPORT_SYMBOL(ioctl_by_bdev); |
|---|
| 815 |
|
|---|
| 816 |
|
|---|
| 817 |
|
|---|
| 818 |
|
|---|
| 819 |
|
|---|
| 820 |
|
|---|
| 821 |
|
|---|
| 822 |
|
|---|
| 823 |
|
|---|
| 824 |
|
|---|
| 825 |
struct block_device *lookup_bdev(const char *path) |
|---|
| 826 |
{ |
|---|
| 827 |
struct block_device *bdev; |
|---|
| 828 |
struct inode *inode; |
|---|
| 829 |
struct nameidata nd; |
|---|
| 830 |
int error; |
|---|
| 831 |
|
|---|
| 832 |
if (!path || !*path) |
|---|
| 833 |
return ERR_PTR(-EINVAL); |
|---|
| 834 |
|
|---|
| 835 |
error = path_lookup(path, LOOKUP_FOLLOW, &nd); |
|---|
| 836 |
if (error) |
|---|
| 837 |
return ERR_PTR(error); |
|---|
| 838 |
|
|---|
| 839 |
inode = nd.dentry->d_inode; |
|---|
| 840 |
error = -ENOTBLK; |
|---|
| 841 |
if (!S_ISBLK(inode->i_mode)) |
|---|
| 842 |
goto fail; |
|---|
| 843 |
error = -EACCES; |
|---|
| 844 |
if (nd.mnt->mnt_flags & MNT_NODEV) |
|---|
| 845 |
goto fail; |
|---|
| 846 |
error = -ENOMEM; |
|---|
| 847 |
bdev = bd_acquire(inode); |
|---|
| 848 |
if (!bdev) |
|---|
| 849 |
goto fail; |
|---|
| 850 |
out: |
|---|
| 851 |
path_release(&nd); |
|---|
| 852 |
return bdev; |
|---|
| 853 |
fail: |
|---|
| 854 |
bdev = ERR_PTR(error); |
|---|
| 855 |
goto out; |
|---|
| 856 |
} |
|---|
| 857 |
|
|---|
| 858 |
|
|---|
| 859 |
|
|---|
| 860 |
|
|---|
| 861 |
|
|---|
| 862 |
|
|---|
| 863 |
|
|---|
| 864 |
|
|---|
| 865 |
|
|---|
| 866 |
|
|---|
| 867 |
|
|---|
| 868 |
struct block_device *open_bdev_excl(const char *path, int flags, void *holder) |
|---|
| 869 |
{ |
|---|
| 870 |
struct block_device *bdev; |
|---|
| 871 |
mode_t mode = FMODE_READ; |
|---|
| 872 |
int error = 0; |
|---|
| 873 |
|
|---|
| 874 |
bdev = lookup_bdev(path); |
|---|
| 875 |
if (IS_ERR(bdev)) |
|---|
| 876 |
return bdev; |
|---|
| 877 |
|
|---|
| 878 |
if (!(flags & MS_RDONLY)) |
|---|
| 879 |
mode |= FMODE_WRITE; |
|---|
| 880 |
error = blkdev_get(bdev, mode, 0); |
|---|
| 881 |
if (error) |
|---|
| 882 |
return ERR_PTR(error); |
|---|
| 883 |
error = -EACCES; |
|---|
| 884 |
if (!(flags & MS_RDONLY) && bdev_read_only(bdev)) |
|---|
| 885 |
goto blkdev_put; |
|---|
| 886 |
error = bd_claim(bdev, holder); |
|---|
| 887 |
if (error) |
|---|
| 888 |
goto blkdev_put; |
|---|
| 889 |
|
|---|
| 890 |
return bdev; |
|---|
| 891 |
|
|---|
| 892 |
blkdev_put: |
|---|
| 893 |
blkdev_put(bdev); |
|---|
| 894 |
return ERR_PTR(error); |
|---|
| 895 |
} |
|---|
| 896 |
|
|---|
| 897 |
EXPORT_SYMBOL(open_bdev_excl); |
|---|
| 898 |
|
|---|
| 899 |
|
|---|
| 900 |
|
|---|
| 901 |
|
|---|
| 902 |
|
|---|
| 903 |
|
|---|
| 904 |
|
|---|
| 905 |
|
|---|
| 906 |
void close_bdev_excl(struct block_device *bdev) |
|---|
| 907 |
{ |
|---|
| 908 |
bd_release(bdev); |
|---|
| 909 |
blkdev_put(bdev); |
|---|
| 910 |
} |
|---|
| 911 |
|
|---|
| 912 |
EXPORT_SYMBOL(close_bdev_excl); |
|---|