Commit 52034cae authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'vfs-6.9-rc6.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs

Pull vfs fixes from Christian Brauner:
 "This contains a few small fixes for this merge window and the attempt
  to handle the ntfs removal regression that was reported a little while
  ago:

   - After the removal of the legacy ntfs driver we received reports
     about regressions for some people that do mount "ntfs" explicitly
     and expect the driver to be available. Since ntfs3 is a drop-in for
     legacy ntfs we alias legacy ntfs to ntfs3 just like ext3 is aliased
     to ext4.

     We also enforce legacy ntfs is always mounted read-only and give it
     custom file operations to ensure that ioctl()'s can't be abused to
     perform write operations.

   - Fix an unbalanced module_get() in bdev_open().

   - Two smaller fixes for the netfs work done earlier in this cycle.

   - Fix the errno returned from the new FS_IOC_GETUUID and
     FS_IOC_GETFSSYSFSPATH ioctls. Both commands just pull information
     out of the superblock so there's no need to call into the actual
     ioctl handlers.

     So instead of returning ENOIOCTLCMD to indicate to fallback we just
     return ENOTTY directly avoiding that indirection"

* tag 'vfs-6.9-rc6.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs:
  netfs: Fix the pre-flush when appending to a file in writethrough mode
  netfs: Fix writethrough-mode error handling
  ntfs3: add legacy ntfs file operations
  ntfs3: enforce read-only when used as legacy ntfs driver
  ntfs3: serve as alias for the legacy ntfs driver
  block: fix module reference leakage from bdev_open_by_dev error path
  fs: Return ENOTTY directly if FS_IOC_GETUUID or FS_IOC_GETFSSYSFSPATH fail
parents 09ef2957 c97f59e2
...@@ -882,7 +882,7 @@ int bdev_open(struct block_device *bdev, blk_mode_t mode, void *holder, ...@@ -882,7 +882,7 @@ int bdev_open(struct block_device *bdev, blk_mode_t mode, void *holder,
goto abort_claiming; goto abort_claiming;
ret = -EBUSY; ret = -EBUSY;
if (!bdev_may_open(bdev, mode)) if (!bdev_may_open(bdev, mode))
goto abort_claiming; goto put_module;
if (bdev_is_partition(bdev)) if (bdev_is_partition(bdev))
ret = blkdev_get_part(bdev, mode); ret = blkdev_get_part(bdev, mode);
else else
......
...@@ -769,7 +769,7 @@ static int ioctl_getfsuuid(struct file *file, void __user *argp) ...@@ -769,7 +769,7 @@ static int ioctl_getfsuuid(struct file *file, void __user *argp)
struct fsuuid2 u = { .len = sb->s_uuid_len, }; struct fsuuid2 u = { .len = sb->s_uuid_len, };
if (!sb->s_uuid_len) if (!sb->s_uuid_len)
return -ENOIOCTLCMD; return -ENOTTY;
memcpy(&u.uuid[0], &sb->s_uuid, sb->s_uuid_len); memcpy(&u.uuid[0], &sb->s_uuid, sb->s_uuid_len);
...@@ -781,7 +781,7 @@ static int ioctl_get_fs_sysfs_path(struct file *file, void __user *argp) ...@@ -781,7 +781,7 @@ static int ioctl_get_fs_sysfs_path(struct file *file, void __user *argp)
struct super_block *sb = file_inode(file)->i_sb; struct super_block *sb = file_inode(file)->i_sb;
if (!strlen(sb->s_sysfs_name)) if (!strlen(sb->s_sysfs_name))
return -ENOIOCTLCMD; return -ENOTTY;
struct fs_sysfs_path u = {}; struct fs_sysfs_path u = {};
......
...@@ -164,7 +164,7 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, ...@@ -164,7 +164,7 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter,
enum netfs_how_to_modify howto; enum netfs_how_to_modify howto;
enum netfs_folio_trace trace; enum netfs_folio_trace trace;
unsigned int bdp_flags = (iocb->ki_flags & IOCB_SYNC) ? 0: BDP_ASYNC; unsigned int bdp_flags = (iocb->ki_flags & IOCB_SYNC) ? 0: BDP_ASYNC;
ssize_t written = 0, ret; ssize_t written = 0, ret, ret2;
loff_t i_size, pos = iocb->ki_pos, from, to; loff_t i_size, pos = iocb->ki_pos, from, to;
size_t max_chunk = PAGE_SIZE << MAX_PAGECACHE_ORDER; size_t max_chunk = PAGE_SIZE << MAX_PAGECACHE_ORDER;
bool maybe_trouble = false; bool maybe_trouble = false;
...@@ -172,14 +172,13 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, ...@@ -172,14 +172,13 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter,
if (unlikely(test_bit(NETFS_ICTX_WRITETHROUGH, &ctx->flags) || if (unlikely(test_bit(NETFS_ICTX_WRITETHROUGH, &ctx->flags) ||
iocb->ki_flags & (IOCB_DSYNC | IOCB_SYNC)) iocb->ki_flags & (IOCB_DSYNC | IOCB_SYNC))
) { ) {
if (pos < i_size_read(inode)) { wbc_attach_fdatawrite_inode(&wbc, mapping->host);
ret = filemap_write_and_wait_range(mapping, pos, pos + iter->count); ret = filemap_write_and_wait_range(mapping, pos, pos + iter->count);
if (ret < 0) { if (ret < 0) {
wbc_detach_inode(&wbc);
goto out; goto out;
} }
}
wbc_attach_fdatawrite_inode(&wbc, mapping->host);
wreq = netfs_begin_writethrough(iocb, iter->count); wreq = netfs_begin_writethrough(iocb, iter->count);
if (IS_ERR(wreq)) { if (IS_ERR(wreq)) {
...@@ -395,10 +394,12 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, ...@@ -395,10 +394,12 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter,
out: out:
if (unlikely(wreq)) { if (unlikely(wreq)) {
ret = netfs_end_writethrough(wreq, iocb); ret2 = netfs_end_writethrough(wreq, iocb);
wbc_detach_inode(&wbc); wbc_detach_inode(&wbc);
if (ret == -EIOCBQUEUED) if (ret2 == -EIOCBQUEUED)
return ret; return ret2;
if (ret == 0)
ret = ret2;
} }
iocb->ki_pos += written; iocb->ki_pos += written;
......
...@@ -46,3 +46,12 @@ config NTFS3_FS_POSIX_ACL ...@@ -46,3 +46,12 @@ config NTFS3_FS_POSIX_ACL
NOTE: this is linux only feature. Windows will ignore these ACLs. NOTE: this is linux only feature. Windows will ignore these ACLs.
If you don't know what Access Control Lists are, say N. If you don't know what Access Control Lists are, say N.
config NTFS_FS
tristate "NTFS file system support"
select NTFS3_FS
select BUFFER_HEAD
select NLS
help
This config option is here only for backward compatibility. NTFS
filesystem is now handled by the NTFS3 driver.
...@@ -616,4 +616,11 @@ const struct file_operations ntfs_dir_operations = { ...@@ -616,4 +616,11 @@ const struct file_operations ntfs_dir_operations = {
.compat_ioctl = ntfs_compat_ioctl, .compat_ioctl = ntfs_compat_ioctl,
#endif #endif
}; };
const struct file_operations ntfs_legacy_dir_operations = {
.llseek = generic_file_llseek,
.read = generic_read_dir,
.iterate_shared = ntfs_readdir,
.open = ntfs_file_open,
};
// clang-format on // clang-format on
...@@ -1236,4 +1236,12 @@ const struct file_operations ntfs_file_operations = { ...@@ -1236,4 +1236,12 @@ const struct file_operations ntfs_file_operations = {
.fallocate = ntfs_fallocate, .fallocate = ntfs_fallocate,
.release = ntfs_file_release, .release = ntfs_file_release,
}; };
const struct file_operations ntfs_legacy_file_operations = {
.llseek = generic_file_llseek,
.read_iter = ntfs_file_read_iter,
.splice_read = ntfs_file_splice_read,
.open = ntfs_file_open,
.release = ntfs_file_release,
};
// clang-format on // clang-format on
...@@ -440,6 +440,9 @@ static struct inode *ntfs_read_mft(struct inode *inode, ...@@ -440,6 +440,9 @@ static struct inode *ntfs_read_mft(struct inode *inode,
* Usually a hard links to directories are disabled. * Usually a hard links to directories are disabled.
*/ */
inode->i_op = &ntfs_dir_inode_operations; inode->i_op = &ntfs_dir_inode_operations;
if (is_legacy_ntfs(inode->i_sb))
inode->i_fop = &ntfs_legacy_dir_operations;
else
inode->i_fop = &ntfs_dir_operations; inode->i_fop = &ntfs_dir_operations;
ni->i_valid = 0; ni->i_valid = 0;
} else if (S_ISLNK(mode)) { } else if (S_ISLNK(mode)) {
...@@ -450,6 +453,9 @@ static struct inode *ntfs_read_mft(struct inode *inode, ...@@ -450,6 +453,9 @@ static struct inode *ntfs_read_mft(struct inode *inode,
} else if (S_ISREG(mode)) { } else if (S_ISREG(mode)) {
ni->std_fa &= ~FILE_ATTRIBUTE_DIRECTORY; ni->std_fa &= ~FILE_ATTRIBUTE_DIRECTORY;
inode->i_op = &ntfs_file_inode_operations; inode->i_op = &ntfs_file_inode_operations;
if (is_legacy_ntfs(inode->i_sb))
inode->i_fop = &ntfs_legacy_file_operations;
else
inode->i_fop = &ntfs_file_operations; inode->i_fop = &ntfs_file_operations;
inode->i_mapping->a_ops = is_compressed(ni) ? &ntfs_aops_cmpr : inode->i_mapping->a_ops = is_compressed(ni) ? &ntfs_aops_cmpr :
&ntfs_aops; &ntfs_aops;
...@@ -1614,6 +1620,9 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap, struct inode *dir, ...@@ -1614,6 +1620,9 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap, struct inode *dir,
if (S_ISDIR(mode)) { if (S_ISDIR(mode)) {
inode->i_op = &ntfs_dir_inode_operations; inode->i_op = &ntfs_dir_inode_operations;
if (is_legacy_ntfs(inode->i_sb))
inode->i_fop = &ntfs_legacy_dir_operations;
else
inode->i_fop = &ntfs_dir_operations; inode->i_fop = &ntfs_dir_operations;
} else if (S_ISLNK(mode)) { } else if (S_ISLNK(mode)) {
inode->i_op = &ntfs_link_inode_operations; inode->i_op = &ntfs_link_inode_operations;
...@@ -1623,6 +1632,9 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap, struct inode *dir, ...@@ -1623,6 +1632,9 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap, struct inode *dir,
inode_nohighmem(inode); inode_nohighmem(inode);
} else if (S_ISREG(mode)) { } else if (S_ISREG(mode)) {
inode->i_op = &ntfs_file_inode_operations; inode->i_op = &ntfs_file_inode_operations;
if (is_legacy_ntfs(inode->i_sb))
inode->i_fop = &ntfs_legacy_file_operations;
else
inode->i_fop = &ntfs_file_operations; inode->i_fop = &ntfs_file_operations;
inode->i_mapping->a_ops = is_compressed(ni) ? &ntfs_aops_cmpr : inode->i_mapping->a_ops = is_compressed(ni) ? &ntfs_aops_cmpr :
&ntfs_aops; &ntfs_aops;
......
...@@ -493,6 +493,7 @@ struct inode *dir_search_u(struct inode *dir, const struct cpu_str *uni, ...@@ -493,6 +493,7 @@ struct inode *dir_search_u(struct inode *dir, const struct cpu_str *uni,
struct ntfs_fnd *fnd); struct ntfs_fnd *fnd);
bool dir_is_empty(struct inode *dir); bool dir_is_empty(struct inode *dir);
extern const struct file_operations ntfs_dir_operations; extern const struct file_operations ntfs_dir_operations;
extern const struct file_operations ntfs_legacy_dir_operations;
/* Globals from file.c */ /* Globals from file.c */
int ntfs_getattr(struct mnt_idmap *idmap, const struct path *path, int ntfs_getattr(struct mnt_idmap *idmap, const struct path *path,
...@@ -507,6 +508,7 @@ long ntfs_compat_ioctl(struct file *filp, u32 cmd, unsigned long arg); ...@@ -507,6 +508,7 @@ long ntfs_compat_ioctl(struct file *filp, u32 cmd, unsigned long arg);
extern const struct inode_operations ntfs_special_inode_operations; extern const struct inode_operations ntfs_special_inode_operations;
extern const struct inode_operations ntfs_file_inode_operations; extern const struct inode_operations ntfs_file_inode_operations;
extern const struct file_operations ntfs_file_operations; extern const struct file_operations ntfs_file_operations;
extern const struct file_operations ntfs_legacy_file_operations;
/* Globals from frecord.c */ /* Globals from frecord.c */
void ni_remove_mi(struct ntfs_inode *ni, struct mft_inode *mi); void ni_remove_mi(struct ntfs_inode *ni, struct mft_inode *mi);
...@@ -1154,4 +1156,6 @@ static inline void le64_sub_cpu(__le64 *var, u64 val) ...@@ -1154,4 +1156,6 @@ static inline void le64_sub_cpu(__le64 *var, u64 val)
*var = cpu_to_le64(le64_to_cpu(*var) - val); *var = cpu_to_le64(le64_to_cpu(*var) - val);
} }
bool is_legacy_ntfs(struct super_block *sb);
#endif /* _LINUX_NTFS3_NTFS_FS_H */ #endif /* _LINUX_NTFS3_NTFS_FS_H */
...@@ -408,6 +408,12 @@ static int ntfs_fs_reconfigure(struct fs_context *fc) ...@@ -408,6 +408,12 @@ static int ntfs_fs_reconfigure(struct fs_context *fc)
struct ntfs_mount_options *new_opts = fc->fs_private; struct ntfs_mount_options *new_opts = fc->fs_private;
int ro_rw; int ro_rw;
/* If ntfs3 is used as legacy ntfs enforce read-only mode. */
if (is_legacy_ntfs(sb)) {
fc->sb_flags |= SB_RDONLY;
goto out;
}
ro_rw = sb_rdonly(sb) && !(fc->sb_flags & SB_RDONLY); ro_rw = sb_rdonly(sb) && !(fc->sb_flags & SB_RDONLY);
if (ro_rw && (sbi->flags & NTFS_FLAGS_NEED_REPLAY)) { if (ro_rw && (sbi->flags & NTFS_FLAGS_NEED_REPLAY)) {
errorf(fc, errorf(fc,
...@@ -427,8 +433,6 @@ static int ntfs_fs_reconfigure(struct fs_context *fc) ...@@ -427,8 +433,6 @@ static int ntfs_fs_reconfigure(struct fs_context *fc)
fc, fc,
"ntfs3: Cannot use different iocharset when remounting!"); "ntfs3: Cannot use different iocharset when remounting!");
sync_filesystem(sb);
if (ro_rw && (sbi->volume.flags & VOLUME_FLAG_DIRTY) && if (ro_rw && (sbi->volume.flags & VOLUME_FLAG_DIRTY) &&
!new_opts->force) { !new_opts->force) {
errorf(fc, errorf(fc,
...@@ -436,6 +440,8 @@ static int ntfs_fs_reconfigure(struct fs_context *fc) ...@@ -436,6 +440,8 @@ static int ntfs_fs_reconfigure(struct fs_context *fc)
return -EINVAL; return -EINVAL;
} }
out:
sync_filesystem(sb);
swap(sbi->options, fc->fs_private); swap(sbi->options, fc->fs_private);
return 0; return 0;
...@@ -1613,6 +1619,8 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) ...@@ -1613,6 +1619,8 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
} }
#endif #endif
if (is_legacy_ntfs(sb))
sb->s_flags |= SB_RDONLY;
return 0; return 0;
put_inode_out: put_inode_out:
...@@ -1730,7 +1738,7 @@ static const struct fs_context_operations ntfs_context_ops = { ...@@ -1730,7 +1738,7 @@ static const struct fs_context_operations ntfs_context_ops = {
* This will called when mount/remount. We will first initialize * This will called when mount/remount. We will first initialize
* options so that if remount we can use just that. * options so that if remount we can use just that.
*/ */
static int ntfs_init_fs_context(struct fs_context *fc) static int __ntfs_init_fs_context(struct fs_context *fc)
{ {
struct ntfs_mount_options *opts; struct ntfs_mount_options *opts;
struct ntfs_sb_info *sbi; struct ntfs_sb_info *sbi;
...@@ -1778,6 +1786,11 @@ static int ntfs_init_fs_context(struct fs_context *fc) ...@@ -1778,6 +1786,11 @@ static int ntfs_init_fs_context(struct fs_context *fc)
return -ENOMEM; return -ENOMEM;
} }
static int ntfs_init_fs_context(struct fs_context *fc)
{
return __ntfs_init_fs_context(fc);
}
static void ntfs3_kill_sb(struct super_block *sb) static void ntfs3_kill_sb(struct super_block *sb)
{ {
struct ntfs_sb_info *sbi = sb->s_fs_info; struct ntfs_sb_info *sbi = sb->s_fs_info;
...@@ -1798,6 +1811,50 @@ static struct file_system_type ntfs_fs_type = { ...@@ -1798,6 +1811,50 @@ static struct file_system_type ntfs_fs_type = {
.kill_sb = ntfs3_kill_sb, .kill_sb = ntfs3_kill_sb,
.fs_flags = FS_REQUIRES_DEV | FS_ALLOW_IDMAP, .fs_flags = FS_REQUIRES_DEV | FS_ALLOW_IDMAP,
}; };
#if IS_ENABLED(CONFIG_NTFS_FS)
static int ntfs_legacy_init_fs_context(struct fs_context *fc)
{
int ret;
ret = __ntfs_init_fs_context(fc);
/* If ntfs3 is used as legacy ntfs enforce read-only mode. */
fc->sb_flags |= SB_RDONLY;
return ret;
}
static struct file_system_type ntfs_legacy_fs_type = {
.owner = THIS_MODULE,
.name = "ntfs",
.init_fs_context = ntfs_legacy_init_fs_context,
.parameters = ntfs_fs_parameters,
.kill_sb = ntfs3_kill_sb,
.fs_flags = FS_REQUIRES_DEV | FS_ALLOW_IDMAP,
};
MODULE_ALIAS_FS("ntfs");
static inline void register_as_ntfs_legacy(void)
{
int err = register_filesystem(&ntfs_legacy_fs_type);
if (err)
pr_warn("ntfs3: Failed to register legacy ntfs filesystem driver: %d\n", err);
}
static inline void unregister_as_ntfs_legacy(void)
{
unregister_filesystem(&ntfs_legacy_fs_type);
}
bool is_legacy_ntfs(struct super_block *sb)
{
return sb->s_type == &ntfs_legacy_fs_type;
}
#else
static inline void register_as_ntfs_legacy(void) {}
static inline void unregister_as_ntfs_legacy(void) {}
bool is_legacy_ntfs(struct super_block *sb) { return false; }
#endif
// clang-format on // clang-format on
static int __init init_ntfs_fs(void) static int __init init_ntfs_fs(void)
...@@ -1832,6 +1889,7 @@ static int __init init_ntfs_fs(void) ...@@ -1832,6 +1889,7 @@ static int __init init_ntfs_fs(void)
goto out1; goto out1;
} }
register_as_ntfs_legacy();
err = register_filesystem(&ntfs_fs_type); err = register_filesystem(&ntfs_fs_type);
if (err) if (err)
goto out; goto out;
...@@ -1849,6 +1907,7 @@ static void __exit exit_ntfs_fs(void) ...@@ -1849,6 +1907,7 @@ static void __exit exit_ntfs_fs(void)
rcu_barrier(); rcu_barrier();
kmem_cache_destroy(ntfs_inode_cachep); kmem_cache_destroy(ntfs_inode_cachep);
unregister_filesystem(&ntfs_fs_type); unregister_filesystem(&ntfs_fs_type);
unregister_as_ntfs_legacy();
ntfs3_exit_bitmap(); ntfs3_exit_bitmap();
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment