diff options
Diffstat (limited to 'fs/block_dev.c')
-rw-r--r-- | fs/block_dev.c | 55 |
1 files changed, 38 insertions, 17 deletions
diff --git a/fs/block_dev.c b/fs/block_dev.c index 8ae833e00443..7059190732a1 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -26,6 +26,7 @@ #include <linux/mpage.h> #include <linux/mount.h> #include <linux/pseudo_fs.h> +#include <linux/jhash.h> #include <linux/uio.h> #include <linux/namei.h> #include <linux/log2.h> @@ -54,6 +55,38 @@ struct block_device *I_BDEV(struct inode *inode) } EXPORT_SYMBOL(I_BDEV); +static u32 blockdev_key_hash_fn(const void *data, u32 len, u32 seed) +{ + const dev_t *k = data; + + return jhash(k, sizeof(*k), seed); +} + +static u32 blockdev_obj_hash_fn(const void *obj, u32 len, u32 seed) +{ + const struct bdev_inode *ei = + container_of(obj, struct bdev_inode, vfs_inode); + + return jhash(&ei->bdev.bd_dev, sizeof(ei->bdev.bd_dev), seed); +} + +static int blockdev_hash_cmp_fn(struct rhashtable_compare_arg *arg, + const void *obj) +{ + const struct bdev_inode *ei = + container_of(obj, struct bdev_inode, vfs_inode); + const dev_t *k = arg->key; + + return ei->bdev.bd_dev == *k ? 0 : 1; +} + +static const struct rhashtable_params blockdev_inode_table_params = { + .head_offset = offsetof(struct inode, i_hash), + .hashfn = blockdev_key_hash_fn, + .obj_hashfn = blockdev_obj_hash_fn, + .obj_cmpfn = blockdev_hash_cmp_fn, +}; + static void bdev_write_inode(struct block_device *bdev) { struct inode *inode = bdev->bd_inode; @@ -839,24 +872,13 @@ void __init bdev_cache_init(void) if (IS_ERR(bd_mnt)) panic("Cannot create bdev pseudo-fs"); blockdev_superblock = bd_mnt->mnt_sb; /* For writeback */ -} -/* - * Most likely _very_ bad one - but then it's hardly critical for small - * /dev and can be fixed when somebody will need really large one. - * Keep in mind that it will be fed through icache hash function too. - */ -static inline unsigned long hash(dev_t dev) -{ - return MAJOR(dev)+MINOR(dev); -} - -static int bdev_test(struct inode *inode, void *data) -{ - return BDEV_I(inode)->bdev.bd_dev == *(dev_t *)data; + err = super_setup_inode_table(blockdev_superblock, &blockdev_inode_table_params); + if (err) + panic("Cannot initialize bdev inode table"); } -static int bdev_set(struct inode *inode, void *data) +static int bdev_set(struct inode *inode, const void *data) { BDEV_I(inode)->bdev.bd_dev = *(dev_t *)data; return 0; @@ -867,8 +889,7 @@ struct block_device *bdget(dev_t dev) struct block_device *bdev; struct inode *inode; - inode = iget5_locked(blockdev_superblock, hash(dev), - bdev_test, bdev_set, &dev); + inode = iget5_locked(blockdev_superblock, bdev_set, &dev); if (!inode) return NULL; |