Skip to contentSkip to conversation

helper for inkernel opening of block devices

PATCH New Christoph Hellwig 1 participant 1 message Nov 26, 2002 VFS

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 helper for inkernel opening of block devices

A large part of get_sb_bdev is used to properly open, setup and claim a block device given it's pathname. This same actions must be taken by other kernel code, like opening of the log and rt volumes in xfs, and volume setup in DM.

I'd suggest to split it out into a helper (and a surrounding close routine). Once this is in I'll use it in XFS (couldn't do it in this patch as there's a big XFS update pending for you), and I'll hope the DM folks start to use it aswell.

(p.s. there also some cosmetics for consistance naming in block_dev.c
in this patch, the old naming just made my eyes burn)

fs/block_dev.c +65 -7
@@ -22,6 +22,7 @@
 #include <linux/mpage.h>
 #include <linux/mount.h>
 #include <linux/uio.h>
+#include <linux/namei.h>
 #include <asm/uaccess.h>
 
 
@@ -151,7 +152,7 @@
  * for a block special file file->f_dentry->d_inode->i_size is zero
  * so we compute the size by hand (just as in block_read/write above)
  */
-static loff_t block_llseek(struct file *file, loff_t offset, int origin)
+static loff_t blkdev_llseek(struct file *file, loff_t offset, int origin)
 {
 	/* ewww */
 	loff_t size = file->f_dentry->d_inode->i_bdev->bd_inode->i_size;
@@ -182,11 +183,9 @@
  *	since the vma has no handle.
  */
  
-static int block_fsync(struct file *filp, struct dentry *dentry, int datasync)
+static int blkdev_fsync(struct file *filp, struct dentry *dentry, int datasync)
 {
-	struct inode * inode = dentry->d_inode;
-
-	return sync_blockdev(inode->i_bdev);
+	return sync_blockdev(dentry->d_inode->i_bdev);
 }
 
 /*
@@ -764,11 +763,11 @@
 struct file_operations def_blk_fops = {
 	.open		= blkdev_open,
 	.release	= blkdev_close,
-	.llseek		= block_llseek,
+	.llseek		= blkdev_llseek,
 	.read		= generic_file_read,
 	.write		= blkdev_file_write,
 	.mmap		= generic_file_mmap,
-	.fsync		= block_fsync,
+	.fsync		= blkdev_fsync,
 	.ioctl		= blkdev_ioctl,
 	.readv		= generic_file_readv,
 	.writev		= generic_file_writev,
@@ -795,4 +794,63 @@
 
 	sprintf(buffer, "%s(%d,%d)", name, MAJOR(dev), MINOR(dev));
 	return buffer;
+}
+
+struct block_device *open_bdev_excl(char *path, int fl, int kind, void *holder)
+{
+	struct inode *inode;
+	struct block_device *bdev;
+	struct nameidata nd;
+	mode_t mode = FMODE_READ;
+	int error = 0;
+
+	if (!path || !*path)
+		return ERR_PTR(-EINVAL);
+
+	error = path_lookup(path, LOOKUP_FOLLOW, &nd);
+	if (error)
+		return ERR_PTR(error);
+
+	inode = nd.dentry->d_inode;
+	error = -ENOTBLK;
+	if (!S_ISBLK(inode->i_mode))
+		goto path_release;
+	error = -EACCES;
+	if (nd.mnt->mnt_flags & MNT_NODEV)
+		goto path_release;
+	error = bd_acquire(inode);
+	if (error)
+		goto path_release;
+	bdev = inode->i_bdev;
+
+	/* Done with lookups */
+	path_release(&nd);
+
+	if (!(fl & MS_RDONLY))
+		mode |= FMODE_WRITE;
+	error = blkdev_get(bdev, mode, 0, kind);
+	if (error)
+		return ERR_PTR(error);
+	error = -EACCES;
+	if (!(fl & MS_RDONLY) && bdev_read_only(bdev))
+		goto blkdev_put;
+	error = bd_claim(bdev, holder);
+	if (error)
+		goto blkdev_put;
+
+	return bdev;
+	
+blkdev_put:
+	blkdev_put(bdev, BDEV_FS);
+	return ERR_PTR(error);
+
+path_release:
+	path_release(&nd);
+	return ERR_PTR(error);
+}
+
+void close_bdev_excl(struct block_device *bdev, int kind)
+{
+	bd_release(bdev);
+	blkdev_put(bdev, kind);
 }
fs/super.c +13 -46

90 lines not on this page · raw message

include/linux/fs.h +6 -1
@@ -1096,15 +1096,20 @@
 extern void bd_release(struct block_device *);
 extern void blk_run_queues(void);
 
-/* fs/devices.c */
+/* fs/char_dev.c */
 extern int register_chrdev(unsigned int, const char *, struct file_operations *);
 extern int unregister_chrdev(unsigned int, const char *);
 extern int chrdev_open(struct inode *, struct file *);
+
+/* fs/block_dev.c */
 extern const char *__bdevname(dev_t);
 extern inline const char *bdevname(struct block_device *bdev)
 {
 	return __bdevname(bdev->bd_dev);
 }
+extern struct block_device *open_bdev_excl(char *, int, int, void *);
+extern void close_bdev_excl(struct block_device *, int);
+
 extern const char * cdevname(kdev_t);
 extern const char * kdevname(kdev_t);
 extern void init_special_inode(struct inode *, umode_t, dev_t);
kernel/ksyms.c +2 -0
@@ -202,6 +202,8 @@
 EXPORT_SYMBOL(bdput);
 EXPORT_SYMBOL(bd_claim);
 EXPORT_SYMBOL(bd_release);
+EXPORT_SYMBOL(open_bdev_excl);
+EXPORT_SYMBOL(close_bdev_excl);
 EXPORT_SYMBOL(__brelse);
 EXPORT_SYMBOL(__bforget);
 EXPORT_SYMBOL(ll_rw_block);