From 616730270bf3e0d521451e9b4532a673417df479 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Sun, 3 Jan 2021 02:51:31 +0000 Subject: [PATCH] scst: Rework vdisk_get_file_size() Linux kernel commit 4e7b5671c6a8 ("block: remove i_bdev"; v5.11-rc1) removes the i_bdev member of struct inode. Hence use blkdev_get_by_path() to open block devices when the struct block_device pointer is needed instead of using filp_open(). git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@9316 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- scst/include/backport.h | 23 +++++++ scst/include/scst.h | 3 + scst/src/dev_handlers/scst_vdisk.c | 46 +++---------- scst/src/scst_lib.c | 102 ++++++++++++++++++++--------- scst/src/scst_pres.c | 20 ++---- 5 files changed, 114 insertions(+), 80 deletions(-) diff --git a/scst/include/backport.h b/scst/include/backport.h index 49bc48f66..2d3787c8d 100644 --- a/scst/include/backport.h +++ b/scst/include/backport.h @@ -161,6 +161,29 @@ static inline int bdev_io_opt(struct block_device *bdev) } #endif +/* + * See also commit d4d77629953e ("block: clean up blkdev_get() wrappers and + * their users") # v2.6.38. + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 38) +static inline struct block_device * +blkdev_get_by_path(const char *path, fmode_t mode, void *holder) +{ + struct block_device *bdev; + int err; + + bdev = lookup_bdev(path); + if (IS_ERR(bdev)) + return bdev; + + err = blkdev_get(bdev, mode); + if (err) + return ERR_PTR(err); + + return bdev; +} +#endif + /* */ /* diff --git a/scst/include/scst.h b/scst/include/scst.h index a36053e43..153b8a9e9 100644 --- a/scst/include/scst.h +++ b/scst/include/scst.h @@ -5543,6 +5543,9 @@ struct scst_data_descriptor { uint64_t sdd_blocks; }; +loff_t scst_file_size(const char *path, umode_t *mode); +loff_t scst_bdev_size(const char *path); +loff_t scst_file_or_bdev_size(const char *path); ssize_t scst_readv(struct file *file, const struct kvec *vec, unsigned long vlen, loff_t *pos); ssize_t scst_writev(struct file *file, const struct kvec *vec, diff --git a/scst/src/dev_handlers/scst_vdisk.c b/scst/src/dev_handlers/scst_vdisk.c index 1a2553828..a726a912a 100644 --- a/scst/src/dev_handlers/scst_vdisk.c +++ b/scst/src/dev_handlers/scst_vdisk.c @@ -679,9 +679,7 @@ check: static int vdisk_get_file_size(const struct scst_vdisk_dev *virt_dev, loff_t *file_size) { - struct inode *inode; - int res = 0; - struct file *fd; + loff_t res; TRACE_ENTRY(); @@ -694,42 +692,18 @@ static int vdisk_get_file_size(const struct scst_vdisk_dev *virt_dev, goto out; } - *file_size = 0; - - fd = filp_open(virt_dev->filename, O_LARGEFILE | O_RDONLY, 0600); - if (IS_ERR(fd)) { - res = PTR_ERR(fd); - if ((res == -EMEDIUMTYPE) && virt_dev->blockio) - TRACE(TRACE_MINOR, "Unable to open %s with EMEDIUMTYPE, " - "DRBD passive?", virt_dev->filename); - else - PRINT_ERROR("filp_open(%s) failed: %d", virt_dev->filename, res); + res = scst_file_or_bdev_size(virt_dev->filename); + if (res == -EMEDIUMTYPE && virt_dev->blockio) { + TRACE(TRACE_MINOR, + "Unable to open %s with EMEDIUMTYPE, DRBD passive?", + virt_dev->filename); goto out; } - - inode = file_inode(fd); - - if (virt_dev->blockio && !S_ISBLK(inode->i_mode)) { - PRINT_ERROR("File %s is NOT a block device", virt_dev->filename); - res = -EINVAL; - goto out_close; + if (res < 0) { + PRINT_ERROR("opening %s failed: %lld", virt_dev->filename, res); + goto out; } - - if (S_ISREG(inode->i_mode)) { - /* Nothing to do */ - } else if (S_ISBLK(inode->i_mode)) { - inode = inode->i_bdev->bd_inode; - } else { - PRINT_ERROR("File %s unsupported mode: mode=0%o\n", - virt_dev->filename, inode->i_mode); - res = -EINVAL; - goto out_close; - } - - *file_size = inode->i_size; - -out_close: - filp_close(fd, NULL); + *file_size = res; out: TRACE_EXIT_RES(res); diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index 0a23fcfe3..23a4f0acd 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -6015,6 +6015,66 @@ ssize_t kernel_write(struct file *file, const void *buf, size_t count, EXPORT_SYMBOL(kernel_write); #endif +/** + * scst_file_size - returns the size of a regular file + * @path: Path of the file. + * @mode: If not NULL, the file mode will be stored in *@mode. + * + * Returns the file size or an error code. + */ +loff_t scst_file_size(const char *path, umode_t *mode) +{ + struct file *filp; + struct inode *inode; + loff_t res; + + filp = filp_open(path, O_LARGEFILE | O_RDONLY, 0600); + if (IS_ERR(filp)) + return PTR_ERR(filp); + inode = file_inode(filp); + if (mode) + *mode = inode->i_mode; + res = S_ISREG(inode->i_mode) ? i_size_read(file_inode(filp)) : -ENOTTY; + filp_close(filp, NULL); + return res; +} +EXPORT_SYMBOL(scst_file_size); + +/** + * scst_bdev_size - returns the size of a block device + * @path: Path of the block device. + * + * Returns the block device size or an error code. + */ +loff_t scst_bdev_size(const char *path) +{ + struct block_device *bdev; + loff_t res; + + bdev = blkdev_get_by_path(path, FMODE_READ, (void *)__func__); + if (IS_ERR(bdev)) + return PTR_ERR(bdev); + res = i_size_read(bdev->bd_inode); + blkdev_put(bdev, FMODE_READ); + return res; +} +EXPORT_SYMBOL(scst_bdev_size); + +loff_t scst_file_or_bdev_size(const char *path) +{ + enum { INVALID_FILE_MODE = 0 }; + umode_t mode = INVALID_FILE_MODE; + loff_t res; + + res = scst_file_size(path, &mode); + if (S_ISREG(mode)) + return res; + if (mode != INVALID_FILE_MODE && !S_ISBLK(mode)) + return -EINVAL; + return scst_bdev_size(path); +} +EXPORT_SYMBOL(scst_file_or_bdev_size); + /** * scst_readv - read data from a file into a kernel buffer * @file: File to read from. @@ -15133,7 +15193,6 @@ EXPORT_SYMBOL(scst_path_put); int scst_copy_file(const char *src, const char *dest) { int res = 0; - struct inode *inode; loff_t file_size, pos; uint8_t *buf = NULL; struct file *file_src = NULL, *file_dest = NULL; @@ -15149,6 +15208,12 @@ int scst_copy_file(const char *src, const char *dest) TRACE_DBG("Copying '%s' into '%s'", src, dest); + file_size = scst_file_or_bdev_size(src); + if (file_size < 0) { + res = file_size; + goto out; + } + file_src = filp_open(src, O_RDONLY, 0); if (IS_ERR(file_src)) { res = PTR_ERR(file_src); @@ -15164,20 +15229,6 @@ int scst_copy_file(const char *src, const char *dest) goto out_close; } - inode = file_inode(file_src); - - if (S_ISREG(inode->i_mode)) { - /* Nothing to do */ - } else if (S_ISBLK(inode->i_mode)) { - inode = inode->i_bdev->bd_inode; - } else { - PRINT_ERROR("Invalid file mode 0x%x", inode->i_mode); - res = -EINVAL; - goto out_skip; - } - - file_size = inode->i_size; - buf = vmalloc(file_size); if (buf == NULL) { res = -ENOMEM; @@ -15332,13 +15383,18 @@ static int __scst_read_file_transactional(const char *file_name, { int res; struct file *file = NULL; - struct inode *inode; loff_t file_size, pos; TRACE_ENTRY(); TRACE_DBG("Loading file '%s'", file_name); + file_size = scst_file_or_bdev_size(file_name); + if (file_size < 0) { + res = file_size; + goto out; + } + file = filp_open(file_name, O_RDONLY, 0); if (IS_ERR(file)) { res = PTR_ERR(file); @@ -15346,20 +15402,6 @@ static int __scst_read_file_transactional(const char *file_name, goto out; } - inode = file_inode(file); - - if (S_ISREG(inode->i_mode)) { - /* Nothing to do */ - } else if (S_ISBLK(inode->i_mode)) { - inode = inode->i_bdev->bd_inode; - } else { - PRINT_ERROR("Invalid file mode 0x%x", inode->i_mode); - res = -EINVAL; - goto out_close; - } - - file_size = inode->i_size; - if (file_size > size) { PRINT_ERROR("Supplied buffer (%d) too small (need %d)", size, (int)file_size); diff --git a/scst/src/scst_pres.c b/scst/src/scst_pres.c index 96f3d77df..f38b53cdc 100644 --- a/scst/src/scst_pres.c +++ b/scst/src/scst_pres.c @@ -660,7 +660,6 @@ static int scst_pr_do_load_device_file(struct scst_device *dev, { int res = 0, rc; struct file *file = NULL; - struct inode *inode; char *buf = NULL; loff_t file_size, pos, data_size; uint64_t sign, version; @@ -676,6 +675,12 @@ static int scst_pr_do_load_device_file(struct scst_device *dev, TRACE_PR("Loading persistent file '%s'", file_name); + file_size = scst_file_or_bdev_size(file_name); + if (file_size < 0) { + res = file_size; + goto out; + } + file = filp_open(file_name, O_RDONLY, 0); if (IS_ERR(file)) { res = PTR_ERR(file); @@ -683,19 +688,6 @@ static int scst_pr_do_load_device_file(struct scst_device *dev, goto out; } - inode = file_inode(file); - - if (S_ISREG(inode->i_mode)) { - /* Nothing to do */ - } else if (S_ISBLK(inode->i_mode)) { - inode = inode->i_bdev->bd_inode; - } else { - PRINT_ERROR("Invalid file mode 0x%x", inode->i_mode); - goto out_close; - } - - file_size = inode->i_size; - /* Let's limit the file size by some reasonable number */ if ((file_size == 0) || (file_size >= 15*1024*1024)) { PRINT_ERROR("Invalid PR file size %d", (int)file_size);