This patch adds bdlookup() and bdlookup_disk().
They are lookup-only variant of bdget()/bdget_disk().
The function can be used when
- the caller wants to get bdev only if somebody already got it
(i.e. there is already bd_inode allocated in memory)
- the race between bdlookup() and bdget() is acceptable
The patch is a preparation for the 2nd part of this patchset.
Background:
inode is initialized with I_LOCK and I_NEW turned on.
After initialization, both flags are turned off.
bdget() uses iget5_locked(), which waits until I_LOCK is removed.
It could take so long or forever.
Signed-off-by: Jun'ichi Nomura <[email protected]>
---
fs/block_dev.c | 27 +++++++++++++++++++++++++++
include/linux/fs.h | 4 +++-
include/linux/genhd.h | 6 ++++++
3 files changed, 36 insertions(+), 1 deletion(-)
Index: linux-2.6.23.work/fs/block_dev.c
===================================================================
--- linux-2.6.23.work.orig/fs/block_dev.c
+++ linux-2.6.23.work/fs/block_dev.c
@@ -586,6 +586,33 @@ struct block_device *bdget(dev_t dev)
EXPORT_SYMBOL(bdget);
+/*
+ * Variant of bdget(), which returns bdev only when it is already gotten.
+ *
+ * The function can be used when:
+ * - the caller wants to get bdev only if somebody already got it
+ * (i.e. there is already bd_inode allocated in memory)
+ * and
+ * - the race between bdlookup() and bdget() is acceptable
+ */
+struct block_device *bdlookup(dev_t dev)
+{
+ struct inode *inode;
+
+ might_sleep();
+
+ /* Use _nowait because we don't want to wait for I_LOCK */
+ inode = ilookup5_nowait(bd_mnt->mnt_sb, hash(dev), bdev_test, &dev);
+
+ if (!inode)
+ return NULL;
+
+ wait_on_bit(&inode->i_state, __I_NEW, inode_wait, TASK_UNINTERRUPTIBLE);
+
+ return &BDEV_I(inode)->bdev;
+}
+EXPORT_SYMBOL(bdlookup);
+
long nr_blockdev_pages(void)
{
struct block_device *bdev;
Index: linux-2.6.23.work/include/linux/fs.h
===================================================================
--- linux-2.6.23.work.orig/include/linux/fs.h
+++ linux-2.6.23.work/include/linux/fs.h
@@ -1211,10 +1211,11 @@ struct super_operations {
#define I_DIRTY_DATASYNC 2 /* Data-related inode changes pending */
#define I_DIRTY_PAGES 4 /* Data-related inode changes pending */
#define __I_LOCK 3
+#define __I_NEW 6
#define I_LOCK (1 << __I_LOCK)
#define I_FREEING 16
#define I_CLEAR 32
-#define I_NEW 64
+#define I_NEW (1 << __I_NEW)
#define I_WILL_FREE 128
#define I_DIRTY (I_DIRTY_SYNC | I_DIRTY_DATASYNC | I_DIRTY_PAGES)
@@ -1431,6 +1432,7 @@ extern void putname(const char *name);
extern int register_blkdev(unsigned int, const char *);
extern void unregister_blkdev(unsigned int, const char *);
extern struct block_device *bdget(dev_t);
+extern struct block_device *bdlookup(dev_t);
extern void bd_set_size(struct block_device *, loff_t size);
extern void bd_forget(struct inode *inode);
extern void bdput(struct block_device *);
Index: linux-2.6.23.work/include/linux/genhd.h
===================================================================
--- linux-2.6.23.work.orig/include/linux/genhd.h
+++ linux-2.6.23.work/include/linux/genhd.h
@@ -435,6 +435,12 @@ static inline struct block_device *bdget
return bdget(MKDEV(disk->major, disk->first_minor) + index);
}
+static inline struct block_device *bdlookup_disk(struct gendisk *disk,
+ int index)
+{
+ return bdlookup(MKDEV(disk->major, disk->first_minor) + index);
+}
+
#endif
#else /* CONFIG_BLOCK */