summaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorAlexei Starovoitov <ast@kernel.org>2026-03-01 20:03:45 +0300
committerAlexei Starovoitov <ast@kernel.org>2026-03-01 20:04:00 +0300
commit309d8808eef93d29b65ae69241a4475b2c8bd6fe (patch)
treec42851bcd612348cfeee1857c0b92a5cfc53bf50 /fs
parentf620af11c27b8ec9994a39fe968aa778112d1566 (diff)
parenteb71ab2bf72260054677e348498ba995a057c463 (diff)
downloadlinux-309d8808eef93d29b65ae69241a4475b2c8bd6fe.tar.xz
Merge git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf before 7.0-rc2
Cross-merge BPF and other fixes after downstream PR. No conflicts. Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Diffstat (limited to 'fs')
-rw-r--r--fs/erofs/inode.c7
-rw-r--r--fs/erofs/internal.h16
-rw-r--r--fs/erofs/ishare.c14
-rw-r--r--fs/erofs/super.c85
-rw-r--r--fs/erofs/zmap.c9
-rw-r--r--fs/eventpoll.c5
-rw-r--r--fs/file_attr.c2
-rw-r--r--fs/fs-writeback.c9
-rw-r--r--fs/iomap/buffered-io.c1
-rw-r--r--fs/iomap/ioend.c46
-rw-r--r--fs/minix/bitmap.c2
-rw-r--r--fs/namespace.c133
-rw-r--r--fs/pidfs.c10
-rw-r--r--fs/proc/base.c3
-rw-r--r--fs/smb/client/cached_dir.c2
-rw-r--r--fs/smb/client/cifs_fs_sb.h2
-rw-r--r--fs/smb/client/cifs_ioctl.h8
-rw-r--r--fs/smb/client/cifs_unicode.c14
-rw-r--r--fs/smb/client/cifs_unicode.h14
-rw-r--r--fs/smb/client/cifsacl.c17
-rw-r--r--fs/smb/client/cifsfs.c84
-rw-r--r--fs/smb/client/cifsglob.h61
-rw-r--r--fs/smb/client/connect.c80
-rw-r--r--fs/smb/client/dfs_cache.c2
-rw-r--r--fs/smb/client/dir.c53
-rw-r--r--fs/smb/client/file.c90
-rw-r--r--fs/smb/client/fs_context.c149
-rw-r--r--fs/smb/client/fs_context.h2
-rw-r--r--fs/smb/client/inode.c142
-rw-r--r--fs/smb/client/ioctl.c2
-rw-r--r--fs/smb/client/link.c14
-rw-r--r--fs/smb/client/misc.c16
-rw-r--r--fs/smb/client/readdir.c39
-rw-r--r--fs/smb/client/reparse.c27
-rw-r--r--fs/smb/client/reparse.h4
-rw-r--r--fs/smb/client/smb1ops.c22
-rw-r--r--fs/smb/client/smb2file.c2
-rw-r--r--fs/smb/client/smb2misc.c18
-rw-r--r--fs/smb/client/smb2ops.c8
-rw-r--r--fs/smb/client/smb2pdu.c35
-rw-r--r--fs/smb/client/transport.c21
-rw-r--r--fs/smb/client/xattr.c6
-rw-r--r--fs/smb/server/Kconfig1
-rw-r--r--fs/smb/server/auth.c4
-rw-r--r--fs/smb/server/smb2pdu.c5
-rw-r--r--fs/smb/server/transport_rdma.c4
-rw-r--r--fs/squashfs/cache.c3
-rw-r--r--fs/xfs/libxfs/xfs_ag.c28
-rw-r--r--fs/xfs/libxfs/xfs_ag.h3
-rw-r--r--fs/xfs/libxfs/xfs_inode_buf.c4
-rw-r--r--fs/xfs/libxfs/xfs_metafile.c5
-rw-r--r--fs/xfs/libxfs/xfs_ondisk.h52
-rw-r--r--fs/xfs/libxfs/xfs_sb.c3
-rw-r--r--fs/xfs/scrub/dir_repair.c2
-rw-r--r--fs/xfs/scrub/orphanage.c7
-rw-r--r--fs/xfs/xfs_fsops.c17
-rw-r--r--fs/xfs/xfs_health.c20
-rw-r--r--fs/xfs/xfs_healthmon.c11
-rw-r--r--fs/xfs/xfs_icache.c18
-rw-r--r--fs/xfs/xfs_mount.h2
-rw-r--r--fs/xfs/xfs_notify_failure.c4
-rw-r--r--fs/xfs/xfs_platform.h9
-rw-r--r--fs/xfs/xfs_rtalloc.c44
-rw-r--r--fs/xfs/xfs_stats.c17
-rw-r--r--fs/xfs/xfs_stats.h19
-rw-r--r--fs/xfs/xfs_super.c4
-rw-r--r--fs/xfs/xfs_verify_media.c4
-rw-r--r--fs/xfs/xfs_zone_alloc.c6
-rw-r--r--fs/xfs/xfs_zone_gc.c10
69 files changed, 911 insertions, 671 deletions
diff --git a/fs/erofs/inode.c b/fs/erofs/inode.c
index 4f86169c23f1..4b3d21402e10 100644
--- a/fs/erofs/inode.c
+++ b/fs/erofs/inode.c
@@ -222,6 +222,7 @@ err_out:
static int erofs_fill_inode(struct inode *inode)
{
+ const struct address_space_operations *aops;
int err;
trace_erofs_fill_inode(inode);
@@ -254,7 +255,11 @@ static int erofs_fill_inode(struct inode *inode)
}
mapping_set_large_folios(inode->i_mapping);
- return erofs_inode_set_aops(inode, inode, false);
+ aops = erofs_get_aops(inode, false);
+ if (IS_ERR(aops))
+ return PTR_ERR(aops);
+ inode->i_mapping->a_ops = aops;
+ return 0;
}
/*
diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h
index d1634455e389..a4f0a42cf8c3 100644
--- a/fs/erofs/internal.h
+++ b/fs/erofs/internal.h
@@ -471,26 +471,24 @@ static inline void *erofs_vm_map_ram(struct page **pages, unsigned int count)
return NULL;
}
-static inline int erofs_inode_set_aops(struct inode *inode,
- struct inode *realinode, bool no_fscache)
+static inline const struct address_space_operations *
+erofs_get_aops(struct inode *realinode, bool no_fscache)
{
if (erofs_inode_is_data_compressed(EROFS_I(realinode)->datalayout)) {
if (!IS_ENABLED(CONFIG_EROFS_FS_ZIP))
- return -EOPNOTSUPP;
+ return ERR_PTR(-EOPNOTSUPP);
DO_ONCE_LITE_IF(realinode->i_blkbits != PAGE_SHIFT,
erofs_info, realinode->i_sb,
"EXPERIMENTAL EROFS subpage compressed block support in use. Use at your own risk!");
- inode->i_mapping->a_ops = &z_erofs_aops;
- return 0;
+ return &z_erofs_aops;
}
- inode->i_mapping->a_ops = &erofs_aops;
if (IS_ENABLED(CONFIG_EROFS_FS_ONDEMAND) && !no_fscache &&
erofs_is_fscache_mode(realinode->i_sb))
- inode->i_mapping->a_ops = &erofs_fscache_access_aops;
+ return &erofs_fscache_access_aops;
if (IS_ENABLED(CONFIG_EROFS_FS_BACKED_BY_FILE) &&
erofs_is_fileio_mode(EROFS_SB(realinode->i_sb)))
- inode->i_mapping->a_ops = &erofs_fileio_aops;
- return 0;
+ return &erofs_fileio_aops;
+ return &erofs_aops;
}
int erofs_register_sysfs(struct super_block *sb);
diff --git a/fs/erofs/ishare.c b/fs/erofs/ishare.c
index ce980320a8b9..829d50d5c717 100644
--- a/fs/erofs/ishare.c
+++ b/fs/erofs/ishare.c
@@ -40,10 +40,14 @@ bool erofs_ishare_fill_inode(struct inode *inode)
{
struct erofs_sb_info *sbi = EROFS_SB(inode->i_sb);
struct erofs_inode *vi = EROFS_I(inode);
+ const struct address_space_operations *aops;
struct erofs_inode_fingerprint fp;
struct inode *sharedinode;
unsigned long hash;
+ aops = erofs_get_aops(inode, true);
+ if (IS_ERR(aops))
+ return false;
if (erofs_xattr_fill_inode_fingerprint(&fp, inode, sbi->domain_id))
return false;
hash = xxh32(fp.opaque, fp.size, 0);
@@ -56,15 +60,15 @@ bool erofs_ishare_fill_inode(struct inode *inode)
}
if (inode_state_read_once(sharedinode) & I_NEW) {
- if (erofs_inode_set_aops(sharedinode, inode, true)) {
- iget_failed(sharedinode);
- kfree(fp.opaque);
- return false;
- }
+ sharedinode->i_mapping->a_ops = aops;
sharedinode->i_size = vi->vfs_inode.i_size;
unlock_new_inode(sharedinode);
} else {
kfree(fp.opaque);
+ if (aops != sharedinode->i_mapping->a_ops) {
+ iput(sharedinode);
+ return false;
+ }
if (sharedinode->i_size != vi->vfs_inode.i_size) {
_erofs_printk(inode->i_sb, KERN_WARNING
"size(%lld:%lld) not matches for the same fingerprint\n",
diff --git a/fs/erofs/super.c b/fs/erofs/super.c
index d4995686ac6c..972a0c82198d 100644
--- a/fs/erofs/super.c
+++ b/fs/erofs/super.c
@@ -424,26 +424,23 @@ static const struct fs_parameter_spec erofs_fs_parameters[] = {
static bool erofs_fc_set_dax_mode(struct fs_context *fc, unsigned int mode)
{
-#ifdef CONFIG_FS_DAX
- struct erofs_sb_info *sbi = fc->s_fs_info;
-
- switch (mode) {
- case EROFS_MOUNT_DAX_ALWAYS:
- set_opt(&sbi->opt, DAX_ALWAYS);
- clear_opt(&sbi->opt, DAX_NEVER);
- return true;
- case EROFS_MOUNT_DAX_NEVER:
- set_opt(&sbi->opt, DAX_NEVER);
- clear_opt(&sbi->opt, DAX_ALWAYS);
- return true;
- default:
+ if (IS_ENABLED(CONFIG_FS_DAX)) {
+ struct erofs_sb_info *sbi = fc->s_fs_info;
+
+ if (mode == EROFS_MOUNT_DAX_ALWAYS) {
+ set_opt(&sbi->opt, DAX_ALWAYS);
+ clear_opt(&sbi->opt, DAX_NEVER);
+ return true;
+ } else if (mode == EROFS_MOUNT_DAX_NEVER) {
+ set_opt(&sbi->opt, DAX_NEVER);
+ clear_opt(&sbi->opt, DAX_ALWAYS);
+ return true;
+ }
DBG_BUGON(1);
return false;
}
-#else
errorfc(fc, "dax options not supported");
return false;
-#endif
}
static int erofs_fc_parse_param(struct fs_context *fc,
@@ -460,31 +457,26 @@ static int erofs_fc_parse_param(struct fs_context *fc,
switch (opt) {
case Opt_user_xattr:
-#ifdef CONFIG_EROFS_FS_XATTR
- if (result.boolean)
+ if (!IS_ENABLED(CONFIG_EROFS_FS_XATTR))
+ errorfc(fc, "{,no}user_xattr options not supported");
+ else if (result.boolean)
set_opt(&sbi->opt, XATTR_USER);
else
clear_opt(&sbi->opt, XATTR_USER);
-#else
- errorfc(fc, "{,no}user_xattr options not supported");
-#endif
break;
case Opt_acl:
-#ifdef CONFIG_EROFS_FS_POSIX_ACL
- if (result.boolean)
+ if (!IS_ENABLED(CONFIG_EROFS_FS_POSIX_ACL))
+ errorfc(fc, "{,no}acl options not supported");
+ else if (result.boolean)
set_opt(&sbi->opt, POSIX_ACL);
else
clear_opt(&sbi->opt, POSIX_ACL);
-#else
- errorfc(fc, "{,no}acl options not supported");
-#endif
break;
case Opt_cache_strategy:
-#ifdef CONFIG_EROFS_FS_ZIP
- sbi->opt.cache_strategy = result.uint_32;
-#else
- errorfc(fc, "compression not supported, cache_strategy ignored");
-#endif
+ if (!IS_ENABLED(CONFIG_EROFS_FS_ZIP))
+ errorfc(fc, "compression not supported, cache_strategy ignored");
+ else
+ sbi->opt.cache_strategy = result.uint_32;
break;
case Opt_dax:
if (!erofs_fc_set_dax_mode(fc, EROFS_MOUNT_DAX_ALWAYS))
@@ -533,24 +525,21 @@ static int erofs_fc_parse_param(struct fs_context *fc,
break;
#endif
case Opt_directio:
-#ifdef CONFIG_EROFS_FS_BACKED_BY_FILE
- if (result.boolean)
+ if (!IS_ENABLED(CONFIG_EROFS_FS_BACKED_BY_FILE))
+ errorfc(fc, "%s option not supported", erofs_fs_parameters[opt].name);
+ else if (result.boolean)
set_opt(&sbi->opt, DIRECT_IO);
else
clear_opt(&sbi->opt, DIRECT_IO);
-#else
- errorfc(fc, "%s option not supported", erofs_fs_parameters[opt].name);
-#endif
break;
case Opt_fsoffset:
sbi->dif0.fsoff = result.uint_64;
break;
case Opt_inode_share:
-#ifdef CONFIG_EROFS_FS_PAGE_CACHE_SHARE
- set_opt(&sbi->opt, INODE_SHARE);
-#else
- errorfc(fc, "%s option not supported", erofs_fs_parameters[opt].name);
-#endif
+ if (!IS_ENABLED(CONFIG_EROFS_FS_PAGE_CACHE_SHARE))
+ errorfc(fc, "%s option not supported", erofs_fs_parameters[opt].name);
+ else
+ set_opt(&sbi->opt, INODE_SHARE);
break;
}
return 0;
@@ -809,8 +798,7 @@ static int erofs_fc_get_tree(struct fs_context *fc)
ret = get_tree_bdev_flags(fc, erofs_fc_fill_super,
IS_ENABLED(CONFIG_EROFS_FS_BACKED_BY_FILE) ?
GET_TREE_BDEV_QUIET_LOOKUP : 0);
-#ifdef CONFIG_EROFS_FS_BACKED_BY_FILE
- if (ret == -ENOTBLK) {
+ if (IS_ENABLED(CONFIG_EROFS_FS_BACKED_BY_FILE) && ret == -ENOTBLK) {
struct file *file;
if (!fc->source)
@@ -824,7 +812,6 @@ static int erofs_fc_get_tree(struct fs_context *fc)
sbi->dif0.file->f_mapping->a_ops->read_folio)
return get_tree_nodev(fc, erofs_fc_fill_super);
}
-#endif
return ret;
}
@@ -1108,12 +1095,12 @@ static int erofs_show_options(struct seq_file *seq, struct dentry *root)
seq_puts(seq, ",dax=never");
if (erofs_is_fileio_mode(sbi) && test_opt(opt, DIRECT_IO))
seq_puts(seq, ",directio");
-#ifdef CONFIG_EROFS_FS_ONDEMAND
- if (sbi->fsid)
- seq_printf(seq, ",fsid=%s", sbi->fsid);
- if (sbi->domain_id)
- seq_printf(seq, ",domain_id=%s", sbi->domain_id);
-#endif
+ if (IS_ENABLED(CONFIG_EROFS_FS_ONDEMAND)) {
+ if (sbi->fsid)
+ seq_printf(seq, ",fsid=%s", sbi->fsid);
+ if (sbi->domain_id)
+ seq_printf(seq, ",domain_id=%s", sbi->domain_id);
+ }
if (sbi->dif0.fsoff)
seq_printf(seq, ",fsoffset=%llu", sbi->dif0.fsoff);
if (test_opt(opt, INODE_SHARE))
diff --git a/fs/erofs/zmap.c b/fs/erofs/zmap.c
index c8d8e129eb4b..30775502b56d 100644
--- a/fs/erofs/zmap.c
+++ b/fs/erofs/zmap.c
@@ -513,6 +513,7 @@ static int z_erofs_map_blocks_ext(struct inode *inode,
unsigned int recsz = z_erofs_extent_recsize(vi->z_advise);
erofs_off_t pos = round_up(Z_EROFS_MAP_HEADER_END(erofs_iloc(inode) +
vi->inode_isize + vi->xattr_isize), recsz);
+ unsigned int bmask = sb->s_blocksize - 1;
bool in_mbox = erofs_inode_in_metabox(inode);
erofs_off_t lend = inode->i_size;
erofs_off_t l, r, mid, pa, la, lstart;
@@ -596,17 +597,17 @@ static int z_erofs_map_blocks_ext(struct inode *inode,
map->m_flags |= EROFS_MAP_MAPPED |
EROFS_MAP_FULL_MAPPED | EROFS_MAP_ENCODED;
fmt = map->m_plen >> Z_EROFS_EXTENT_PLEN_FMT_BIT;
+ if (map->m_plen & Z_EROFS_EXTENT_PLEN_PARTIAL)
+ map->m_flags |= EROFS_MAP_PARTIAL_REF;
+ map->m_plen &= Z_EROFS_EXTENT_PLEN_MASK;
if (fmt)
map->m_algorithmformat = fmt - 1;
- else if (interlaced && !erofs_blkoff(sb, map->m_pa))
+ else if (interlaced && !((map->m_pa | map->m_plen) & bmask))
map->m_algorithmformat =
Z_EROFS_COMPRESSION_INTERLACED;
else
map->m_algorithmformat =
Z_EROFS_COMPRESSION_SHIFTED;
- if (map->m_plen & Z_EROFS_EXTENT_PLEN_PARTIAL)
- map->m_flags |= EROFS_MAP_PARTIAL_REF;
- map->m_plen &= Z_EROFS_EXTENT_PLEN_MASK;
}
}
map->m_llen = lend - map->m_la;
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
index a8c278c50083..5714e900567c 100644
--- a/fs/eventpoll.c
+++ b/fs/eventpoll.c
@@ -2061,7 +2061,8 @@ static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events,
* @ep: the &struct eventpoll to be currently checked.
* @depth: Current depth of the path being checked.
*
- * Return: depth of the subtree, or INT_MAX if we found a loop or went too deep.
+ * Return: depth of the subtree, or a value bigger than EP_MAX_NESTS if we found
+ * a loop or went too deep.
*/
static int ep_loop_check_proc(struct eventpoll *ep, int depth)
{
@@ -2080,7 +2081,7 @@ static int ep_loop_check_proc(struct eventpoll *ep, int depth)
struct eventpoll *ep_tovisit;
ep_tovisit = epi->ffd.file->private_data;
if (ep_tovisit == inserting_into || depth > EP_MAX_NESTS)
- result = INT_MAX;
+ result = EP_MAX_NESTS+1;
else
result = max(result, ep_loop_check_proc(ep_tovisit, depth + 1) + 1);
if (result > EP_MAX_NESTS)
diff --git a/fs/file_attr.c b/fs/file_attr.c
index 6d2a298a786d..da983e105d70 100644
--- a/fs/file_attr.c
+++ b/fs/file_attr.c
@@ -378,7 +378,7 @@ SYSCALL_DEFINE5(file_getattr, int, dfd, const char __user *, filename,
struct path filepath __free(path_put) = {};
unsigned int lookup_flags = 0;
struct file_attr fattr;
- struct file_kattr fa;
+ struct file_kattr fa = { .flags_valid = true }; /* hint only */
int error;
BUILD_BUG_ON(sizeof(struct file_attr) < FILE_ATTR_SIZE_VER0);
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index 8f8069fb76ba..7c75ed7e8979 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -198,10 +198,11 @@ static void wb_queue_work(struct bdi_writeback *wb,
static bool wb_wait_for_completion_cb(struct wb_completion *done)
{
+ unsigned long timeout = sysctl_hung_task_timeout_secs;
unsigned long waited_secs = (jiffies - done->wait_start) / HZ;
done->progress_stamp = jiffies;
- if (waited_secs > sysctl_hung_task_timeout_secs)
+ if (timeout && (waited_secs > timeout))
pr_info("INFO: The task %s:%d has been waiting for writeback "
"completion for more than %lu seconds.",
current->comm, current->pid, waited_secs);
@@ -1954,6 +1955,7 @@ static long writeback_sb_inodes(struct super_block *sb,
.range_end = LLONG_MAX,
};
unsigned long start_time = jiffies;
+ unsigned long timeout = sysctl_hung_task_timeout_secs;
long write_chunk;
long total_wrote = 0; /* count both pages and inodes */
unsigned long dirtied_before = jiffies;
@@ -2040,9 +2042,8 @@ static long writeback_sb_inodes(struct super_block *sb,
__writeback_single_inode(inode, &wbc);
/* Report progress to inform the hung task detector of the progress. */
- if (work->done && work->done->progress_stamp &&
- (jiffies - work->done->progress_stamp) > HZ *
- sysctl_hung_task_timeout_secs / 2)
+ if (work->done && work->done->progress_stamp && timeout &&
+ (jiffies - work->done->progress_stamp) > HZ * timeout / 2)
wake_up_all(work->done->waitq);
wbc_detach_inode(&wbc);
diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c
index a0c46aadb97d..bc82083e420a 100644
--- a/fs/iomap/buffered-io.c
+++ b/fs/iomap/buffered-io.c
@@ -624,6 +624,7 @@ static int iomap_readahead_iter(struct iomap_iter *iter,
* iomap_readahead - Attempt to read pages from a file.
* @ops: The operations vector for the filesystem.
* @ctx: The ctx used for issuing readahead.
+ * @private: The filesystem-specific information for issuing iomap_iter.
*
* This function is for filesystems to call to implement their readahead
* address_space operation.
diff --git a/fs/iomap/ioend.c b/fs/iomap/ioend.c
index e4d57cb969f1..4d1ef8a2cee9 100644
--- a/fs/iomap/ioend.c
+++ b/fs/iomap/ioend.c
@@ -69,11 +69,57 @@ static u32 iomap_finish_ioend_buffered(struct iomap_ioend *ioend)
return folio_count;
}
+static DEFINE_SPINLOCK(failed_ioend_lock);
+static LIST_HEAD(failed_ioend_list);
+
+static void
+iomap_fail_ioends(
+ struct work_struct *work)
+{
+ struct iomap_ioend *ioend;
+ struct list_head tmp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&failed_ioend_lock, flags);
+ list_replace_init(&failed_ioend_list, &tmp);
+ spin_unlock_irqrestore(&failed_ioend_lock, flags);
+
+ while ((ioend = list_first_entry_or_null(&tmp, struct iomap_ioend,
+ io_list))) {
+ list_del_init(&ioend->io_list);
+ iomap_finish_ioend_buffered(ioend);
+ cond_resched();
+ }
+}
+
+static DECLARE_WORK(failed_ioend_work, iomap_fail_ioends);
+
+static void iomap_fail_ioend_buffered(struct iomap_ioend *ioend)
+{
+ unsigned long flags;
+
+ /*
+ * Bounce I/O errors to a workqueue to avoid nested i_lock acquisitions
+ * in the fserror code. The caller no longer owns the ioend reference
+ * after the spinlock drops.
+ */
+ spin_lock_irqsave(&failed_ioend_lock, flags);
+ if (list_empty(&failed_ioend_list))
+ WARN_ON_ONCE(!schedule_work(&failed_ioend_work));
+ list_add_tail(&ioend->io_list, &failed_ioend_list);
+ spin_unlock_irqrestore(&failed_ioend_lock, flags);
+}
+
static void ioend_writeback_end_bio(struct bio *bio)
{
struct iomap_ioend *ioend = iomap_ioend_from_bio(bio);
ioend->io_error = blk_status_to_errno(bio->bi_status);
+ if (ioend->io_error) {
+ iomap_fail_ioend_buffered(ioend);
+ return;
+ }
+
iomap_finish_ioend_buffered(ioend);
}
diff --git a/fs/minix/bitmap.c b/fs/minix/bitmap.c
index 7da66ca184f4..abec438330a7 100644
--- a/fs/minix/bitmap.c
+++ b/fs/minix/bitmap.c
@@ -247,7 +247,7 @@ struct inode *minix_new_inode(const struct inode *dir, umode_t mode)
j += i * bits_per_zone;
if (!j || j > sbi->s_ninodes) {
iput(inode);
- return ERR_PTR(-ENOSPC);
+ return ERR_PTR(-EFSCORRUPTED);
}
inode_init_owner(&nop_mnt_idmap, inode, dir, mode);
inode->i_ino = j;
diff --git a/fs/namespace.c b/fs/namespace.c
index ebe19ded293a..854f4fc66469 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1531,23 +1531,33 @@ static struct mount *mnt_find_id_at_reverse(struct mnt_namespace *ns, u64 mnt_id
static void *m_start(struct seq_file *m, loff_t *pos)
{
struct proc_mounts *p = m->private;
+ struct mount *mnt;
down_read(&namespace_sem);
- return mnt_find_id_at(p->ns, *pos);
+ mnt = mnt_find_id_at(p->ns, *pos);
+ if (mnt)
+ *pos = mnt->mnt_id_unique;
+ return mnt;
}
static void *m_next(struct seq_file *m, void *v, loff_t *pos)
{
- struct mount *next = NULL, *mnt = v;
+ struct mount *mnt = v;
struct rb_node *node = rb_next(&mnt->mnt_node);
- ++*pos;
if (node) {
- next = node_to_mount(node);
+ struct mount *next = node_to_mount(node);
*pos = next->mnt_id_unique;
+ return next;
}
- return next;
+
+ /*
+ * No more mounts. Set pos past current mount's ID so that if
+ * iteration restarts, mnt_find_id_at() returns NULL.
+ */
+ *pos = mnt->mnt_id_unique + 1;
+ return NULL;
}
static void m_stop(struct seq_file *m, void *v)
@@ -2791,7 +2801,8 @@ static inline void unlock_mount(struct pinned_mountpoint *m)
}
static void lock_mount_exact(const struct path *path,
- struct pinned_mountpoint *mp);
+ struct pinned_mountpoint *mp, bool copy_mount,
+ unsigned int copy_flags);
#define LOCK_MOUNT_MAYBE_BENEATH(mp, path, beneath) \
struct pinned_mountpoint mp __cleanup(unlock_mount) = {}; \
@@ -2799,7 +2810,10 @@ static void lock_mount_exact(const struct path *path,
#define LOCK_MOUNT(mp, path) LOCK_MOUNT_MAYBE_BENEATH(mp, (path), false)
#define LOCK_MOUNT_EXACT(mp, path) \
struct pinned_mountpoint mp __cleanup(unlock_mount) = {}; \
- lock_mount_exact((path), &mp)
+ lock_mount_exact((path), &mp, false, 0)
+#define LOCK_MOUNT_EXACT_COPY(mp, path, copy_flags) \
+ struct pinned_mountpoint mp __cleanup(unlock_mount) = {}; \
+ lock_mount_exact((path), &mp, true, (copy_flags))
static int graft_tree(struct mount *mnt, const struct pinned_mountpoint *mp)
{
@@ -3073,16 +3087,13 @@ static struct file *open_detached_copy(struct path *path, unsigned int flags)
return file;
}
-DEFINE_FREE(put_empty_mnt_ns, struct mnt_namespace *,
- if (!IS_ERR_OR_NULL(_T)) free_mnt_ns(_T))
-
static struct mnt_namespace *create_new_namespace(struct path *path, unsigned int flags)
{
- struct mnt_namespace *new_ns __free(put_empty_mnt_ns) = NULL;
- struct path to_path __free(path_put) = {};
struct mnt_namespace *ns = current->nsproxy->mnt_ns;
struct user_namespace *user_ns = current_user_ns();
- struct mount *new_ns_root;
+ struct mnt_namespace *new_ns;
+ struct mount *new_ns_root, *old_ns_root;
+ struct path to_path;
struct mount *mnt;
unsigned int copy_flags = 0;
bool locked = false;
@@ -3094,71 +3105,63 @@ static struct mnt_namespace *create_new_namespace(struct path *path, unsigned in
if (IS_ERR(new_ns))
return ERR_CAST(new_ns);
- scoped_guard(namespace_excl) {
- new_ns_root = clone_mnt(ns->root, ns->root->mnt.mnt_root, copy_flags);
- if (IS_ERR(new_ns_root))
- return ERR_CAST(new_ns_root);
+ old_ns_root = ns->root;
+ to_path.mnt = &old_ns_root->mnt;
+ to_path.dentry = old_ns_root->mnt.mnt_root;
- /*
- * If the real rootfs had a locked mount on top of it somewhere
- * in the stack, lock the new mount tree as well so it can't be
- * exposed.
- */
- mnt = ns->root;
- while (mnt->overmount) {
- mnt = mnt->overmount;
- if (mnt->mnt.mnt_flags & MNT_LOCKED)
- locked = true;
- }
+ VFS_WARN_ON_ONCE(old_ns_root->mnt.mnt_sb->s_type != &nullfs_fs_type);
+
+ LOCK_MOUNT_EXACT_COPY(mp, &to_path, copy_flags);
+ if (IS_ERR(mp.parent)) {
+ free_mnt_ns(new_ns);
+ return ERR_CAST(mp.parent);
}
+ new_ns_root = mp.parent;
/*
- * We dropped the namespace semaphore so we can actually lock
- * the copy for mounting. The copied mount isn't attached to any
- * mount namespace and it is thus excluded from any propagation.
- * So realistically we're isolated and the mount can't be
- * overmounted.
+ * If the real rootfs had a locked mount on top of it somewhere
+ * in the stack, lock the new mount tree as well so it can't be
+ * exposed.
*/
-
- /* Borrow the reference from clone_mnt(). */
- to_path.mnt = &new_ns_root->mnt;
- to_path.dentry = dget(new_ns_root->mnt.mnt_root);
-
- /* Now lock for actual mounting. */
- LOCK_MOUNT_EXACT(mp, &to_path);
- if (unlikely(IS_ERR(mp.parent)))
- return ERR_CAST(mp.parent);
+ mnt = old_ns_root;
+ while (mnt->overmount) {
+ mnt = mnt->overmount;
+ if (mnt->mnt.mnt_flags & MNT_LOCKED)
+ locked = true;
+ }
/*
- * We don't emulate unshare()ing a mount namespace. We stick to the
- * restrictions of creating detached bind-mounts. It has a lot
- * saner and simpler semantics.
+ * We don't emulate unshare()ing a mount namespace. We stick
+ * to the restrictions of creating detached bind-mounts. It
+ * has a lot saner and simpler semantics.
*/
mnt = __do_loopback(path, flags, copy_flags);
- if (IS_ERR(mnt))
- return ERR_CAST(mnt);
-
scoped_guard(mount_writer) {
+ if (IS_ERR(mnt)) {
+ emptied_ns = new_ns;
+ umount_tree(new_ns_root, 0);
+ return ERR_CAST(mnt);
+ }
+
if (locked)
mnt->mnt.mnt_flags |= MNT_LOCKED;
/*
- * Now mount the detached tree on top of the copy of the
- * real rootfs we created.
+ * now mount the detached tree on top of the copy
+ * of the real rootfs we created.
*/
attach_mnt(mnt, new_ns_root, mp.mp);
if (user_ns != ns->user_ns)
lock_mnt_tree(new_ns_root);
}
- /* Add all mounts to the new namespace. */
- for (struct mount *p = new_ns_root; p; p = next_mnt(p, new_ns_root)) {
- mnt_add_to_ns(new_ns, p);
+ for (mnt = new_ns_root; mnt; mnt = next_mnt(mnt, new_ns_root)) {
+ mnt_add_to_ns(new_ns, mnt);
new_ns->nr_mounts++;
}
- new_ns->root = real_mount(no_free_ptr(to_path.mnt));
+ new_ns->root = new_ns_root;
ns_tree_add_raw(new_ns);
- return no_free_ptr(new_ns);
+ return new_ns;
}
static struct file *open_new_namespace(struct path *path, unsigned int flags)
@@ -3840,16 +3843,20 @@ static int do_new_mount(const struct path *path, const char *fstype,
}
static void lock_mount_exact(const struct path *path,
- struct pinned_mountpoint *mp)
+ struct pinned_mountpoint *mp, bool copy_mount,
+ unsigned int copy_flags)
{
struct dentry *dentry = path->dentry;
int err;
+ /* Assert that inode_lock() locked the correct inode. */
+ VFS_WARN_ON_ONCE(copy_mount && !path_mounted(path));
+
inode_lock(dentry->d_inode);
namespace_lock();
if (unlikely(cant_mount(dentry)))
err = -ENOENT;
- else if (path_overmounted(path))
+ else if (!copy_mount && path_overmounted(path))
err = -EBUSY;
else
err = get_mountpoint(dentry, mp);
@@ -3857,9 +3864,15 @@ static void lock_mount_exact(const struct path *path,
namespace_unlock();
inode_unlock(dentry->d_inode);
mp->parent = ERR_PTR(err);
- } else {
- mp->parent = real_mount(path->mnt);
+ return;
}
+
+ if (copy_mount)
+ mp->parent = clone_mnt(real_mount(path->mnt), dentry, copy_flags);
+ else
+ mp->parent = real_mount(path->mnt);
+ if (unlikely(IS_ERR(mp->parent)))
+ __unlock_mount(mp);
}
int finish_automount(struct vfsmount *__m, const struct path *path)
@@ -5678,6 +5691,8 @@ static int do_statmount(struct kstatmount *s, u64 mnt_id, u64 mnt_ns_id,
s->mnt = mnt_file->f_path.mnt;
ns = real_mount(s->mnt)->mnt_ns;
+ if (IS_ERR(ns))
+ return PTR_ERR(ns);
if (!ns)
/*
* We can't set mount point and mnt_ns_id since we don't have a
diff --git a/fs/pidfs.c b/fs/pidfs.c
index 318253344b5c..e3825ee246be 100644
--- a/fs/pidfs.c
+++ b/fs/pidfs.c
@@ -608,9 +608,8 @@ static long pidfd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
struct user_namespace *user_ns;
user_ns = task_cred_xxx(task, user_ns);
- if (!ns_ref_get(user_ns))
- break;
- ns_common = to_ns_common(user_ns);
+ if (ns_ref_get(user_ns))
+ ns_common = to_ns_common(user_ns);
}
#endif
break;
@@ -620,9 +619,8 @@ static long pidfd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
struct pid_namespace *pid_ns;
pid_ns = task_active_pid_ns(task);
- if (!ns_ref_get(pid_ns))
- break;
- ns_common = to_ns_common(pid_ns);
+ if (ns_ref_get(pid_ns))
+ ns_common = to_ns_common(pid_ns);
}
#endif
break;
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 4eec684baca9..4c863d17dfb4 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -2128,6 +2128,9 @@ bool proc_fill_cache(struct file *file, struct dir_context *ctx,
ino_t ino = 1;
child = try_lookup_noperm(&qname, dir);
+ if (IS_ERR(child))
+ goto end_instantiate;
+
if (!child) {
DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
child = d_alloc_parallel(dir, &qname, &wq);
diff --git a/fs/smb/client/cached_dir.c b/fs/smb/client/cached_dir.c
index c327c246a9b4..04bb95091f49 100644
--- a/fs/smb/client/cached_dir.c
+++ b/fs/smb/client/cached_dir.c
@@ -118,7 +118,7 @@ static const char *path_no_prefix(struct cifs_sb_info *cifs_sb,
if (!*path)
return path;
- if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH) &&
+ if ((cifs_sb_flags(cifs_sb) & CIFS_MOUNT_USE_PREFIX_PATH) &&
cifs_sb->prepath) {
len = strlen(cifs_sb->prepath) + 1;
if (unlikely(len > strlen(path)))
diff --git a/fs/smb/client/cifs_fs_sb.h b/fs/smb/client/cifs_fs_sb.h
index 5e8d163cb5f8..84e7e366b0ff 100644
--- a/fs/smb/client/cifs_fs_sb.h
+++ b/fs/smb/client/cifs_fs_sb.h
@@ -55,7 +55,7 @@ struct cifs_sb_info {
struct nls_table *local_nls;
struct smb3_fs_context *ctx;
atomic_t active;
- unsigned int mnt_cifs_flags;
+ atomic_t mnt_cifs_flags;
struct delayed_work prune_tlinks;
struct rcu_head rcu;
diff --git a/fs/smb/client/cifs_ioctl.h b/fs/smb/client/cifs_ioctl.h
index b51ce64fcccf..147496ac9f9f 100644
--- a/fs/smb/client/cifs_ioctl.h
+++ b/fs/smb/client/cifs_ioctl.h
@@ -122,11 +122,3 @@ struct smb3_notify_info {
#define CIFS_GOING_FLAGS_DEFAULT 0x0 /* going down */
#define CIFS_GOING_FLAGS_LOGFLUSH 0x1 /* flush log but not data */
#define CIFS_GOING_FLAGS_NOLOGFLUSH 0x2 /* don't flush log nor data */
-
-static inline bool cifs_forced_shutdown(struct cifs_sb_info *sbi)
-{
- if (CIFS_MOUNT_SHUTDOWN & sbi->mnt_cifs_flags)
- return true;
- else
- return false;
-}
diff --git a/fs/smb/client/cifs_unicode.c b/fs/smb/client/cifs_unicode.c
index e7891b4406f2..e2edc207cef2 100644
--- a/fs/smb/client/cifs_unicode.c
+++ b/fs/smb/client/cifs_unicode.c
@@ -11,20 +11,6 @@
#include "cifsglob.h"
#include "cifs_debug.h"
-int cifs_remap(struct cifs_sb_info *cifs_sb)
-{
- int map_type;
-
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SFM_CHR)
- map_type = SFM_MAP_UNI_RSVD;
- else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR)
- map_type = SFU_MAP_UNI_RSVD;
- else
- map_type = NO_MAP_UNI_RSVD;
-
- return map_type;
-}
-
/* Convert character using the SFU - "Services for Unix" remapping range */
static bool
convert_sfu_char(const __u16 src_char, char *target)
diff --git a/fs/smb/client/cifs_unicode.h b/fs/smb/client/cifs_unicode.h
index 9249db3b78c3..3e9cd9acf0a9 100644
--- a/fs/smb/client/cifs_unicode.h
+++ b/fs/smb/client/cifs_unicode.h
@@ -22,6 +22,7 @@
#include <linux/types.h>
#include <linux/nls.h>
#include "../../nls/nls_ucs2_utils.h"
+#include "cifsglob.h"
/*
* Macs use an older "SFM" mapping of the symbols above. Fortunately it does
@@ -65,10 +66,21 @@ char *cifs_strndup_from_utf16(const char *src, const int maxlen,
const struct nls_table *codepage);
int cifsConvertToUTF16(__le16 *target, const char *source, int srclen,
const struct nls_table *cp, int map_chars);
-int cifs_remap(struct cifs_sb_info *cifs_sb);
__le16 *cifs_strndup_to_utf16(const char *src, const int maxlen,
int *utf16_len, const struct nls_table *cp,
int remap);
wchar_t cifs_toupper(wchar_t in);
+static inline int cifs_remap(const struct cifs_sb_info *cifs_sb)
+{
+ unsigned int sbflags = cifs_sb_flags(cifs_sb);
+
+ if (sbflags & CIFS_MOUNT_MAP_SFM_CHR)
+ return SFM_MAP_UNI_RSVD;
+ if (sbflags & CIFS_MOUNT_MAP_SPECIAL_CHR)
+ return SFU_MAP_UNI_RSVD;
+
+ return NO_MAP_UNI_RSVD;
+}
+
#endif /* _CIFS_UNICODE_H */
diff --git a/fs/smb/client/cifsacl.c b/fs/smb/client/cifsacl.c
index 6fa12c901c14..f4cb3018a358 100644
--- a/fs/smb/client/cifsacl.c
+++ b/fs/smb/client/cifsacl.c
@@ -356,7 +356,7 @@ sid_to_id(struct cifs_sb_info *cifs_sb, struct smb_sid *psid,
psid->num_subauth, SID_MAX_SUB_AUTHORITIES);
}
- if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UID_FROM_ACL) ||
+ if ((cifs_sb_flags(cifs_sb) & CIFS_MOUNT_UID_FROM_ACL) ||
(cifs_sb_master_tcon(cifs_sb)->posix_extensions)) {
uint32_t unix_id;
bool is_group;
@@ -1612,7 +1612,8 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,
struct smb_acl *dacl_ptr = NULL;
struct smb_ntsd *pntsd = NULL; /* acl obtained from server */
struct smb_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
- struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode);
+ unsigned int sbflags;
struct tcon_link *tlink;
struct smb_version_operations *ops;
bool mode_from_sid, id_from_sid;
@@ -1643,15 +1644,9 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,
return rc;
}
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID)
- mode_from_sid = true;
- else
- mode_from_sid = false;
-
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UID_FROM_ACL)
- id_from_sid = true;
- else
- id_from_sid = false;
+ sbflags = cifs_sb_flags(cifs_sb);
+ mode_from_sid = sbflags & CIFS_MOUNT_MODE_FROM_SID;
+ id_from_sid = sbflags & CIFS_MOUNT_UID_FROM_ACL;
/* Potentially, five new ACEs can be added to the ACL for U,G,O mapping */
if (pnmode && *pnmode != NO_CHANGE_64) { /* chmod */
diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c
index 99b04234a08e..427558404aa5 100644
--- a/fs/smb/client/cifsfs.c
+++ b/fs/smb/client/cifsfs.c
@@ -226,16 +226,18 @@ cifs_sb_deactive(struct super_block *sb)
static int
cifs_read_super(struct super_block *sb)
{
- struct inode *inode;
struct cifs_sb_info *cifs_sb;
struct cifs_tcon *tcon;
+ unsigned int sbflags;
struct timespec64 ts;
+ struct inode *inode;
int rc = 0;
cifs_sb = CIFS_SB(sb);
tcon = cifs_sb_master_tcon(cifs_sb);
+ sbflags = cifs_sb_flags(cifs_sb);
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIXACL)
+ if (sbflags & CIFS_MOUNT_POSIXACL)
sb->s_flags |= SB_POSIXACL;
if (tcon->snapshot_time)
@@ -311,7 +313,7 @@ cifs_read_super(struct super_block *sb)
}
#ifdef CONFIG_CIFS_NFSD_EXPORT
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
+ if (sbflags & CIFS_MOUNT_SERVER_INUM) {
cifs_dbg(FYI, "export ops supported\n");
sb->s_export_op = &cifs_export_ops;
}
@@ -389,8 +391,7 @@ statfs_out:
static long cifs_fallocate(struct file *file, int mode, loff_t off, loff_t len)
{
- struct cifs_sb_info *cifs_sb = CIFS_FILE_SB(file);
- struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
+ struct cifs_tcon *tcon = cifs_sb_master_tcon(CIFS_SB(file));
struct TCP_Server_Info *server = tcon->ses->server;
struct inode *inode = file_inode(file);
int rc;
@@ -418,11 +419,9 @@ out_unlock:
static int cifs_permission(struct mnt_idmap *idmap,
struct inode *inode, int mask)
{
- struct cifs_sb_info *cifs_sb;
+ unsigned int sbflags = cifs_sb_flags(CIFS_SB(inode));
- cifs_sb = CIFS_SB(inode->i_sb);
-
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) {
+ if (sbflags & CIFS_MOUNT_NO_PERM) {
if ((mask & MAY_EXEC) && !execute_ok(inode))
return -EACCES;
else
@@ -568,15 +567,17 @@ cifs_show_security(struct seq_file *s, struct cifs_ses *ses)
static void
cifs_show_cache_flavor(struct seq_file *s, struct cifs_sb_info *cifs_sb)
{
+ unsigned int sbflags = cifs_sb_flags(cifs_sb);
+
seq_puts(s, ",cache=");
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO)
+ if (sbflags & CIFS_MOUNT_STRICT_IO)
seq_puts(s, "strict");
- else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO)
+ else if (sbflags & CIFS_MOUNT_DIRECT_IO)
seq_puts(s, "none");
- else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RW_CACHE)
+ else if (sbflags & CIFS_MOUNT_RW_CACHE)
seq_puts(s, "singleclient"); /* assume only one client access */
- else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RO_CACHE)
+ else if (sbflags & CIFS_MOUNT_RO_CACHE)
seq_puts(s, "ro"); /* read only caching assumed */
else
seq_puts(s, "loose");
@@ -637,6 +638,8 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
struct cifs_sb_info *cifs_sb = CIFS_SB(root->d_sb);
struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
struct sockaddr *srcaddr;
+ unsigned int sbflags;
+
srcaddr = (struct sockaddr *)&tcon->ses->server->srcaddr;
seq_show_option(s, "vers", tcon->ses->server->vals->version_string);
@@ -670,16 +673,17 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
(int)(srcaddr->sa_family));
}
+ sbflags = cifs_sb_flags(cifs_sb);
seq_printf(s, ",uid=%u",
from_kuid_munged(&init_user_ns, cifs_sb->ctx->linux_uid));
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)
+ if (sbflags & CIFS_MOUNT_OVERR_UID)
seq_puts(s, ",forceuid");
else
seq_puts(s, ",noforceuid");
seq_printf(s, ",gid=%u",
from_kgid_munged(&init_user_ns, cifs_sb->ctx->linux_gid));
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)
+ if (sbflags & CIFS_MOUNT_OVERR_GID)
seq_puts(s, ",forcegid");
else
seq_puts(s, ",noforcegid");
@@ -722,53 +726,53 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
seq_puts(s, ",unix");
else
seq_puts(s, ",nounix");
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS)
+ if (sbflags & CIFS_MOUNT_NO_DFS)
seq_puts(s, ",nodfs");
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
+ if (sbflags & CIFS_MOUNT_POSIX_PATHS)
seq_puts(s, ",posixpaths");
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)
+ if (sbflags & CIFS_MOUNT_SET_UID)
seq_puts(s, ",setuids");
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UID_FROM_ACL)
+ if (sbflags & CIFS_MOUNT_UID_FROM_ACL)
seq_puts(s, ",idsfromsid");
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
+ if (sbflags & CIFS_MOUNT_SERVER_INUM)
seq_puts(s, ",serverino");
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
+ if (sbflags & CIFS_MOUNT_RWPIDFORWARD)
seq_puts(s, ",rwpidforward");
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL)
+ if (sbflags & CIFS_MOUNT_NOPOSIXBRL)
seq_puts(s, ",forcemand");
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
+ if (sbflags & CIFS_MOUNT_NO_XATTR)
seq_puts(s, ",nouser_xattr");
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR)
+ if (sbflags & CIFS_MOUNT_MAP_SPECIAL_CHR)
seq_puts(s, ",mapchars");
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SFM_CHR)
+ if (sbflags & CIFS_MOUNT_MAP_SFM_CHR)
seq_puts(s, ",mapposix");
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)
+ if (sbflags & CIFS_MOUNT_UNX_EMUL)
seq_puts(s, ",sfu");
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+ if (sbflags & CIFS_MOUNT_NO_BRL)
seq_puts(s, ",nobrl");
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_HANDLE_CACHE)
+ if (sbflags & CIFS_MOUNT_NO_HANDLE_CACHE)
seq_puts(s, ",nohandlecache");
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID)
+ if (sbflags & CIFS_MOUNT_MODE_FROM_SID)
seq_puts(s, ",modefromsid");
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL)
+ if (sbflags & CIFS_MOUNT_CIFS_ACL)
seq_puts(s, ",cifsacl");
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
+ if (sbflags & CIFS_MOUNT_DYNPERM)
seq_puts(s, ",dynperm");
if (root->d_sb->s_flags & SB_POSIXACL)
seq_puts(s, ",acl");
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS)
+ if (sbflags & CIFS_MOUNT_MF_SYMLINKS)
seq_puts(s, ",mfsymlinks");
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_FSCACHE)
+ if (sbflags & CIFS_MOUNT_FSCACHE)
seq_puts(s, ",fsc");
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)
+ if (sbflags & CIFS_MOUNT_NOSSYNC)
seq_puts(s, ",nostrictsync");
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
+ if (sbflags & CIFS_MOUNT_NO_PERM)
seq_puts(s, ",noperm");
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_BACKUPUID)
+ if (sbflags & CIFS_MOUNT_CIFS_BACKUPUID)
seq_printf(s, ",backupuid=%u",
from_kuid_munged(&init_user_ns,
cifs_sb->ctx->backupuid));
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_BACKUPGID)
+ if (sbflags & CIFS_MOUNT_CIFS_BACKUPGID)
seq_printf(s, ",backupgid=%u",
from_kgid_munged(&init_user_ns,
cifs_sb->ctx->backupgid));
@@ -909,10 +913,10 @@ static int cifs_write_inode(struct inode *inode, struct writeback_control *wbc)
static int cifs_drop_inode(struct inode *inode)
{
- struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+ unsigned int sbflags = cifs_sb_flags(CIFS_SB(inode));
/* no serverino => unconditional eviction */
- return !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) ||
+ return !(sbflags & CIFS_MOUNT_SERVER_INUM) ||
inode_generic_drop(inode);
}
@@ -950,7 +954,7 @@ cifs_get_root(struct smb3_fs_context *ctx, struct super_block *sb)
char *s, *p;
char sep;
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH)
+ if (cifs_sb_flags(cifs_sb) & CIFS_MOUNT_USE_PREFIX_PATH)
return dget(sb->s_root);
full_path = cifs_build_path_to_root(ctx, cifs_sb,
diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
index 080ea601c209..6f9b6c72962b 100644
--- a/fs/smb/client/cifsglob.h
+++ b/fs/smb/client/cifsglob.h
@@ -1580,24 +1580,59 @@ CIFS_I(struct inode *inode)
return container_of(inode, struct cifsInodeInfo, netfs.inode);
}
-static inline struct cifs_sb_info *
-CIFS_SB(struct super_block *sb)
+static inline void *cinode_to_fsinfo(struct cifsInodeInfo *cinode)
+{
+ return cinode->netfs.inode.i_sb->s_fs_info;
+}
+
+static inline void *super_to_fsinfo(struct super_block *sb)
{
return sb->s_fs_info;
}
-static inline struct cifs_sb_info *
-CIFS_FILE_SB(struct file *file)
+static inline void *inode_to_fsinfo(struct inode *inode)
+{
+ return inode->i_sb->s_fs_info;
+}
+
+static inline void *file_to_fsinfo(struct file *file)
+{
+ return file_inode(file)->i_sb->s_fs_info;
+}
+
+static inline void *dentry_to_fsinfo(struct dentry *dentry)
+{
+ return dentry->d_sb->s_fs_info;
+}
+
+static inline void *const_dentry_to_fsinfo(const struct dentry *dentry)
{
- return CIFS_SB(file_inode(file)->i_sb);
+ return dentry->d_sb->s_fs_info;
+}
+
+#define CIFS_SB(_ptr) \
+ ((struct cifs_sb_info *) \
+ _Generic((_ptr), \
+ struct cifsInodeInfo * : cinode_to_fsinfo, \
+ const struct dentry * : const_dentry_to_fsinfo, \
+ struct super_block * : super_to_fsinfo, \
+ struct dentry * : dentry_to_fsinfo, \
+ struct inode * : inode_to_fsinfo, \
+ struct file * : file_to_fsinfo)(_ptr))
+
+/*
+ * Use atomic_t for @cifs_sb->mnt_cifs_flags as it is currently accessed
+ * locklessly and may be changed concurrently by mount/remount and reconnect
+ * paths.
+ */
+static inline unsigned int cifs_sb_flags(const struct cifs_sb_info *cifs_sb)
+{
+ return atomic_read(&cifs_sb->mnt_cifs_flags);
}
static inline char CIFS_DIR_SEP(const struct cifs_sb_info *cifs_sb)
{
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
- return '/';
- else
- return '\\';
+ return (cifs_sb_flags(cifs_sb) & CIFS_MOUNT_POSIX_PATHS) ? '/' : '\\';
}
static inline void
@@ -2314,9 +2349,8 @@ static inline bool __cifs_cache_state_check(struct cifsInodeInfo *cinode,
unsigned int oplock_flags,
unsigned int sb_flags)
{
- struct cifs_sb_info *cifs_sb = CIFS_SB(cinode->netfs.inode.i_sb);
+ unsigned int sflags = cifs_sb_flags(CIFS_SB(cinode));
unsigned int oplock = READ_ONCE(cinode->oplock);
- unsigned int sflags = cifs_sb->mnt_cifs_flags;
return (oplock & oplock_flags) || (sflags & sb_flags);
}
@@ -2336,4 +2370,9 @@ static inline void cifs_reset_oplock(struct cifsInodeInfo *cinode)
WRITE_ONCE(cinode->oplock, 0);
}
+static inline bool cifs_forced_shutdown(const struct cifs_sb_info *sbi)
+{
+ return cifs_sb_flags(sbi) & CIFS_MOUNT_SHUTDOWN;
+}
+
#endif /* _CIFS_GLOB_H */
diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c
index 33dfe116ca52..3bad2c5c523d 100644
--- a/fs/smb/client/connect.c
+++ b/fs/smb/client/connect.c
@@ -2167,9 +2167,6 @@ void __cifs_put_smb_ses(struct cifs_ses *ses)
#ifdef CONFIG_KEYS
-/* strlen("cifs:a:") + CIFS_MAX_DOMAINNAME_LEN + 1 */
-#define CIFSCREDS_DESC_SIZE (7 + CIFS_MAX_DOMAINNAME_LEN + 1)
-
/* Populate username and pw fields from keyring if possible */
static int
cifs_set_cifscreds(struct smb3_fs_context *ctx, struct cifs_ses *ses)
@@ -2177,6 +2174,7 @@ cifs_set_cifscreds(struct smb3_fs_context *ctx, struct cifs_ses *ses)
int rc = 0;
int is_domain = 0;
const char *delim, *payload;
+ size_t desc_sz;
char *desc;
ssize_t len;
struct key *key;
@@ -2185,7 +2183,9 @@ cifs_set_cifscreds(struct smb3_fs_context *ctx, struct cifs_ses *ses)
struct sockaddr_in6 *sa6;
const struct user_key_payload *upayload;
- desc = kmalloc(CIFSCREDS_DESC_SIZE, GFP_KERNEL);
+ /* "cifs:a:" and "cifs:d:" are the same length; +1 for NUL terminator */
+ desc_sz = strlen("cifs:a:") + CIFS_MAX_DOMAINNAME_LEN + 1;
+ desc = kmalloc(desc_sz, GFP_KERNEL);
if (!desc)
return -ENOMEM;
@@ -2193,11 +2193,11 @@ cifs_set_cifscreds(struct smb3_fs_context *ctx, struct cifs_ses *ses)
switch (server->dstaddr.ss_family) {
case AF_INET:
sa = (struct sockaddr_in *)&server->dstaddr;
- sprintf(desc, "cifs:a:%pI4", &sa->sin_addr.s_addr);
+ snprintf(desc, desc_sz, "cifs:a:%pI4", &sa->sin_addr.s_addr);
break;
case AF_INET6:
sa6 = (struct sockaddr_in6 *)&server->dstaddr;
- sprintf(desc, "cifs:a:%pI6c", &sa6->sin6_addr.s6_addr);
+ snprintf(desc, desc_sz, "cifs:a:%pI6c", &sa6->sin6_addr.s6_addr);
break;
default:
cifs_dbg(FYI, "Bad ss_family (%hu)\n",
@@ -2216,7 +2216,7 @@ cifs_set_cifscreds(struct smb3_fs_context *ctx, struct cifs_ses *ses)
}
/* didn't work, try to find a domain key */
- sprintf(desc, "cifs:d:%s", ses->domainName);
+ snprintf(desc, desc_sz, "cifs:d:%s", ses->domainName);
cifs_dbg(FYI, "%s: desc=%s\n", __func__, desc);
key = request_key(&key_type_logon, desc, "");
if (IS_ERR(key)) {
@@ -2236,7 +2236,6 @@ cifs_set_cifscreds(struct smb3_fs_context *ctx, struct cifs_ses *ses)
/* find first : in payload */
payload = upayload->data;
delim = strnchr(payload, upayload->datalen, ':');
- cifs_dbg(FYI, "payload=%s\n", payload);
if (!delim) {
cifs_dbg(FYI, "Unable to find ':' in payload (datalen=%d)\n",
upayload->datalen);
@@ -2915,8 +2914,8 @@ compare_mount_options(struct super_block *sb, struct cifs_mnt_data *mnt_data)
{
struct cifs_sb_info *old = CIFS_SB(sb);
struct cifs_sb_info *new = mnt_data->cifs_sb;
- unsigned int oldflags = old->mnt_cifs_flags & CIFS_MOUNT_MASK;
- unsigned int newflags = new->mnt_cifs_flags & CIFS_MOUNT_MASK;
+ unsigned int oldflags = cifs_sb_flags(old) & CIFS_MOUNT_MASK;
+ unsigned int newflags = cifs_sb_flags(new) & CIFS_MOUNT_MASK;
if ((sb->s_flags & CIFS_MS_MASK) != (mnt_data->flags & CIFS_MS_MASK))
return 0;
@@ -2971,9 +2970,9 @@ static int match_prepath(struct super_block *sb,
struct smb3_fs_context *ctx = mnt_data->ctx;
struct cifs_sb_info *old = CIFS_SB(sb);
struct cifs_sb_info *new = mnt_data->cifs_sb;
- bool old_set = (old->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH) &&
+ bool old_set = (cifs_sb_flags(old) & CIFS_MOUNT_USE_PREFIX_PATH) &&
old->prepath;
- bool new_set = (new->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH) &&
+ bool new_set = (cifs_sb_flags(new) & CIFS_MOUNT_USE_PREFIX_PATH) &&
new->prepath;
if (tcon->origin_fullpath &&
@@ -3004,7 +3003,7 @@ cifs_match_super(struct super_block *sb, void *data)
cifs_sb = CIFS_SB(sb);
/* We do not want to use a superblock that has been shutdown */
- if (CIFS_MOUNT_SHUTDOWN & cifs_sb->mnt_cifs_flags) {
+ if (cifs_forced_shutdown(cifs_sb)) {
spin_unlock(&cifs_tcp_ses_lock);
return 0;
}
@@ -3469,6 +3468,8 @@ ip_connect(struct TCP_Server_Info *server)
int cifs_setup_cifs_sb(struct cifs_sb_info *cifs_sb)
{
struct smb3_fs_context *ctx = cifs_sb->ctx;
+ unsigned int sbflags;
+ int rc = 0;
INIT_DELAYED_WORK(&cifs_sb->prune_tlinks, cifs_prune_tlinks);
INIT_LIST_HEAD(&cifs_sb->tcon_sb_link);
@@ -3493,17 +3494,16 @@ int cifs_setup_cifs_sb(struct cifs_sb_info *cifs_sb)
}
ctx->local_nls = cifs_sb->local_nls;
- smb3_update_mnt_flags(cifs_sb);
+ sbflags = smb3_update_mnt_flags(cifs_sb);
if (ctx->direct_io)
cifs_dbg(FYI, "mounting share using direct i/o\n");
if (ctx->cache_ro) {
cifs_dbg(VFS, "mounting share with read only caching. Ensure that the share will not be modified while in use.\n");
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_RO_CACHE;
+ sbflags |= CIFS_MOUNT_RO_CACHE;
} else if (ctx->cache_rw) {
cifs_dbg(VFS, "mounting share in single client RW caching mode. Ensure that no other systems will be accessing the share.\n");
- cifs_sb->mnt_cifs_flags |= (CIFS_MOUNT_RO_CACHE |
- CIFS_MOUNT_RW_CACHE);
+ sbflags |= CIFS_MOUNT_RO_CACHE | CIFS_MOUNT_RW_CACHE;
}
if ((ctx->cifs_acl) && (ctx->dynperm))
@@ -3512,16 +3512,19 @@ int cifs_setup_cifs_sb(struct cifs_sb_info *cifs_sb)
if (ctx->prepath) {
cifs_sb->prepath = kstrdup(ctx->prepath, GFP_KERNEL);
if (cifs_sb->prepath == NULL)
- return -ENOMEM;
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
+ rc = -ENOMEM;
+ else
+ sbflags |= CIFS_MOUNT_USE_PREFIX_PATH;
}
- return 0;
+ atomic_set(&cifs_sb->mnt_cifs_flags, sbflags);
+ return rc;
}
/* Release all succeed connections */
void cifs_mount_put_conns(struct cifs_mount_ctx *mnt_ctx)
{
+ struct cifs_sb_info *cifs_sb = mnt_ctx->cifs_sb;
int rc = 0;
if (mnt_ctx->tcon)
@@ -3533,7 +3536,7 @@ void cifs_mount_put_conns(struct cifs_mount_ctx *mnt_ctx)
mnt_ctx->ses = NULL;
mnt_ctx->tcon = NULL;
mnt_ctx->server = NULL;
- mnt_ctx->cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_POSIX_PATHS;
+ atomic_andnot(CIFS_MOUNT_POSIX_PATHS, &cifs_sb->mnt_cifs_flags);
free_xid(mnt_ctx->xid);
}
@@ -3587,19 +3590,23 @@ out:
int cifs_mount_get_tcon(struct cifs_mount_ctx *mnt_ctx)
{
struct TCP_Server_Info *server;
+ struct cifs_tcon *tcon = NULL;
struct cifs_sb_info *cifs_sb;
struct smb3_fs_context *ctx;
- struct cifs_tcon *tcon = NULL;
+ unsigned int sbflags;
int rc = 0;
- if (WARN_ON_ONCE(!mnt_ctx || !mnt_ctx->server || !mnt_ctx->ses || !mnt_ctx->fs_ctx ||
- !mnt_ctx->cifs_sb)) {
- rc = -EINVAL;
- goto out;
+ if (WARN_ON_ONCE(!mnt_ctx))
+ return -EINVAL;
+ if (WARN_ON_ONCE(!mnt_ctx->server || !mnt_ctx->ses ||
+ !mnt_ctx->fs_ctx || !mnt_ctx->cifs_sb)) {
+ mnt_ctx->tcon = NULL;
+ return -EINVAL;
}
server = mnt_ctx->server;
ctx = mnt_ctx->fs_ctx;
cifs_sb = mnt_ctx->cifs_sb;
+ sbflags = cifs_sb_flags(cifs_sb);
/* search for existing tcon to this server share */
tcon = cifs_get_tcon(mnt_ctx->ses, ctx);
@@ -3614,9 +3621,9 @@ int cifs_mount_get_tcon(struct cifs_mount_ctx *mnt_ctx)
* path (i.e., do not remap / and \ and do not map any special characters)
*/
if (tcon->posix_extensions) {
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS;
- cifs_sb->mnt_cifs_flags &= ~(CIFS_MOUNT_MAP_SFM_CHR |
- CIFS_MOUNT_MAP_SPECIAL_CHR);
+ sbflags |= CIFS_MOUNT_POSIX_PATHS;
+ sbflags &= ~(CIFS_MOUNT_MAP_SFM_CHR |
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
}
#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
@@ -3643,12 +3650,11 @@ int cifs_mount_get_tcon(struct cifs_mount_ctx *mnt_ctx)
/* do not care if a following call succeed - informational */
if (!tcon->pipe && server->ops->qfs_tcon) {
server->ops->qfs_tcon(mnt_ctx->xid, tcon, cifs_sb);
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RO_CACHE) {
+ if (sbflags & CIFS_MOUNT_RO_CACHE) {
if (tcon->fsDevInfo.DeviceCharacteristics &
cpu_to_le32(FILE_READ_ONLY_DEVICE))
cifs_dbg(VFS, "mounted to read only share\n");
- else if ((cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_RW_CACHE) == 0)
+ else if (!(sbflags & CIFS_MOUNT_RW_CACHE))
cifs_dbg(VFS, "read only mount of RW share\n");
/* no need to log a RW mount of a typical RW share */
}
@@ -3660,11 +3666,12 @@ int cifs_mount_get_tcon(struct cifs_mount_ctx *mnt_ctx)
* Inside cifs_fscache_get_super_cookie it checks
* that we do not get super cookie twice.
*/
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_FSCACHE)
+ if (sbflags & CIFS_MOUNT_FSCACHE)
cifs_fscache_get_super_cookie(tcon);
out:
mnt_ctx->tcon = tcon;
+ atomic_set(&cifs_sb->mnt_cifs_flags, sbflags);
return rc;
}
@@ -3783,7 +3790,8 @@ int cifs_is_path_remote(struct cifs_mount_ctx *mnt_ctx)
cifs_sb, full_path, tcon->Flags & SMB_SHARE_IS_IN_DFS);
if (rc != 0) {
cifs_server_dbg(VFS, "cannot query dirs between root and final path, enabling CIFS_MOUNT_USE_PREFIX_PATH\n");
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
+ atomic_or(CIFS_MOUNT_USE_PREFIX_PATH,
+ &cifs_sb->mnt_cifs_flags);
rc = 0;
}
}
@@ -3863,7 +3871,7 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
* Force the use of prefix path to support failover on DFS paths that resolve to targets
* that have different prefix paths.
*/
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
+ atomic_or(CIFS_MOUNT_USE_PREFIX_PATH, &cifs_sb->mnt_cifs_flags);
kfree(cifs_sb->prepath);
cifs_sb->prepath = ctx->prepath;
ctx->prepath = NULL;
@@ -4357,7 +4365,7 @@ cifs_sb_tlink(struct cifs_sb_info *cifs_sb)
kuid_t fsuid = current_fsuid();
int err;
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
+ if (!(cifs_sb_flags(cifs_sb) & CIFS_MOUNT_MULTIUSER))
return cifs_get_tlink(cifs_sb_master_tlink(cifs_sb));
spin_lock(&cifs_sb->tlink_tree_lock);
diff --git a/fs/smb/client/dfs_cache.c b/fs/smb/client/dfs_cache.c
index 983132735d72..83f8cf2f8d2b 100644
--- a/fs/smb/client/dfs_cache.c
+++ b/fs/smb/client/dfs_cache.c
@@ -1333,7 +1333,7 @@ int dfs_cache_remount_fs(struct cifs_sb_info *cifs_sb)
* Force the use of prefix path to support failover on DFS paths that resolve to targets
* that have different prefix paths.
*/
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
+ atomic_or(CIFS_MOUNT_USE_PREFIX_PATH, &cifs_sb->mnt_cifs_flags);
refresh_tcon_referral(tcon, true);
return 0;
diff --git a/fs/smb/client/dir.c b/fs/smb/client/dir.c
index cb10088197d2..953f1fee8cb8 100644
--- a/fs/smb/client/dir.c
+++ b/fs/smb/client/dir.c
@@ -82,10 +82,11 @@ char *__build_path_from_dentry_optional_prefix(struct dentry *direntry, void *pa
const char *tree, int tree_len,
bool prefix)
{
- int dfsplen;
- int pplen = 0;
- struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(direntry);
+ unsigned int sbflags = cifs_sb_flags(cifs_sb);
char dirsep = CIFS_DIR_SEP(cifs_sb);
+ int pplen = 0;
+ int dfsplen;
char *s;
if (unlikely(!page))
@@ -96,7 +97,7 @@ char *__build_path_from_dentry_optional_prefix(struct dentry *direntry, void *pa
else
dfsplen = 0;
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH)
+ if (sbflags & CIFS_MOUNT_USE_PREFIX_PATH)
pplen = cifs_sb->prepath ? strlen(cifs_sb->prepath) + 1 : 0;
s = dentry_path_raw(direntry, page, PATH_MAX);
@@ -123,7 +124,7 @@ char *__build_path_from_dentry_optional_prefix(struct dentry *direntry, void *pa
if (dfsplen) {
s -= dfsplen;
memcpy(s, tree, dfsplen);
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
+ if (sbflags & CIFS_MOUNT_POSIX_PATHS) {
int i;
for (i = 0; i < dfsplen; i++) {
if (s[i] == '\\')
@@ -152,7 +153,7 @@ char *build_path_from_dentry_optional_prefix(struct dentry *direntry, void *page
static int
check_name(struct dentry *direntry, struct cifs_tcon *tcon)
{
- struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(direntry);
int i;
if (unlikely(tcon->fsAttrInfo.MaxPathNameComponentLength &&
@@ -160,7 +161,7 @@ check_name(struct dentry *direntry, struct cifs_tcon *tcon)
le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength)))
return -ENAMETOOLONG;
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)) {
+ if (!(cifs_sb_flags(cifs_sb) & CIFS_MOUNT_POSIX_PATHS)) {
for (i = 0; i < direntry->d_name.len; i++) {
if (direntry->d_name.name[i] == '\\') {
cifs_dbg(FYI, "Invalid file name\n");
@@ -181,11 +182,12 @@ static int cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned
int rc = -ENOENT;
int create_options = CREATE_NOT_DIR;
int desired_access;
- struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode);
struct cifs_tcon *tcon = tlink_tcon(tlink);
const char *full_path;
void *page = alloc_dentry_path();
struct inode *newinode = NULL;
+ unsigned int sbflags;
int disposition;
struct TCP_Server_Info *server = tcon->ses->server;
struct cifs_open_parms oparms;
@@ -365,6 +367,7 @@ retry_open:
* If Open reported that we actually created a file then we now have to
* set the mode if possible.
*/
+ sbflags = cifs_sb_flags(cifs_sb);
if ((tcon->unix_ext) && (*oplock & CIFS_CREATE_ACTION)) {
struct cifs_unix_set_info_args args = {
.mode = mode,
@@ -374,7 +377,7 @@ retry_open:
.device = 0,
};
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
+ if (sbflags & CIFS_MOUNT_SET_UID) {
args.uid = current_fsuid();
if (inode->i_mode & S_ISGID)
args.gid = inode->i_gid;
@@ -411,9 +414,9 @@ cifs_create_get_file_info:
if (server->ops->set_lease_key)
server->ops->set_lease_key(newinode, fid);
if ((*oplock & CIFS_CREATE_ACTION) && S_ISREG(newinode->i_mode)) {
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
+ if (sbflags & CIFS_MOUNT_DYNPERM)
newinode->i_mode = mode;
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
+ if (sbflags & CIFS_MOUNT_SET_UID) {
newinode->i_uid = current_fsuid();
if (inode->i_mode & S_ISGID)
newinode->i_gid = inode->i_gid;
@@ -458,18 +461,20 @@ int
cifs_atomic_open(struct inode *inode, struct dentry *direntry,
struct file *file, unsigned int oflags, umode_t mode)
{
- int rc;
- unsigned int xid;
- struct tcon_link *tlink;
- struct cifs_tcon *tcon;
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode);
+ struct cifs_open_info_data buf = {};
struct TCP_Server_Info *server;
- struct cifs_fid fid = {};
+ struct cifsFileInfo *file_info;
struct cifs_pending_open open;
+ struct cifs_fid fid = {};
+ struct tcon_link *tlink;
+ struct cifs_tcon *tcon;
+ unsigned int sbflags;
+ unsigned int xid;
__u32 oplock;
- struct cifsFileInfo *file_info;
- struct cifs_open_info_data buf = {};
+ int rc;
- if (unlikely(cifs_forced_shutdown(CIFS_SB(inode->i_sb))))
+ if (unlikely(cifs_forced_shutdown(cifs_sb)))
return smb_EIO(smb_eio_trace_forced_shutdown);
/*
@@ -499,7 +504,7 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry,
cifs_dbg(FYI, "parent inode = 0x%p name is: %pd and dentry = 0x%p\n",
inode, direntry, direntry);
- tlink = cifs_sb_tlink(CIFS_SB(inode->i_sb));
+ tlink = cifs_sb_tlink(cifs_sb);
if (IS_ERR(tlink)) {
rc = PTR_ERR(tlink);
goto out_free_xid;
@@ -536,13 +541,13 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry,
goto out;
}
- if (file->f_flags & O_DIRECT &&
- CIFS_SB(inode->i_sb)->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO) {
- if (CIFS_SB(inode->i_sb)->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+ sbflags = cifs_sb_flags(cifs_sb);
+ if ((file->f_flags & O_DIRECT) && (sbflags & CIFS_MOUNT_STRICT_IO)) {
+ if (sbflags & CIFS_MOUNT_NO_BRL)
file->f_op = &cifs_file_direct_nobrl_ops;
else
file->f_op = &cifs_file_direct_ops;
- }
+ }
file_info = cifs_new_fileinfo(&fid, file, tlink, oplock, buf.symlink_target);
if (file_info == NULL) {
diff --git a/fs/smb/client/file.c b/fs/smb/client/file.c
index 18f31d4eb98d..f3ddcdf406c8 100644
--- a/fs/smb/client/file.c
+++ b/fs/smb/client/file.c
@@ -270,7 +270,7 @@ static void cifs_begin_writeback(struct netfs_io_request *wreq)
static int cifs_init_request(struct netfs_io_request *rreq, struct file *file)
{
struct cifs_io_request *req = container_of(rreq, struct cifs_io_request, rreq);
- struct cifs_sb_info *cifs_sb = CIFS_SB(rreq->inode->i_sb);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(rreq->inode);
struct cifsFileInfo *open_file = NULL;
rreq->rsize = cifs_sb->ctx->rsize;
@@ -281,7 +281,7 @@ static int cifs_init_request(struct netfs_io_request *rreq, struct file *file)
open_file = file->private_data;
rreq->netfs_priv = file->private_data;
req->cfile = cifsFileInfo_get(open_file);
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
+ if (cifs_sb_flags(cifs_sb) & CIFS_MOUNT_RWPIDFORWARD)
req->pid = req->cfile->pid;
} else if (rreq->origin != NETFS_WRITEBACK) {
WARN_ON_ONCE(1);
@@ -906,7 +906,7 @@ void _cifsFileInfo_put(struct cifsFileInfo *cifs_file,
* close because it may cause a error when we open this file
* again and get at least level II oplock.
*/
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO)
+ if (cifs_sb_flags(cifs_sb) & CIFS_MOUNT_STRICT_IO)
set_bit(CIFS_INO_INVALID_MAPPING, &cifsi->flags);
cifs_set_oplock_level(cifsi, 0);
}
@@ -955,11 +955,11 @@ void _cifsFileInfo_put(struct cifsFileInfo *cifs_file,
int cifs_file_flush(const unsigned int xid, struct inode *inode,
struct cifsFileInfo *cfile)
{
- struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode);
struct cifs_tcon *tcon;
int rc;
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)
+ if (cifs_sb_flags(cifs_sb) & CIFS_MOUNT_NOSSYNC)
return 0;
if (cfile && (OPEN_FMODE(cfile->f_flags) & FMODE_WRITE)) {
@@ -1015,24 +1015,24 @@ static int cifs_do_truncate(const unsigned int xid, struct dentry *dentry)
int cifs_open(struct inode *inode, struct file *file)
{
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode);
+ struct cifs_open_info_data data = {};
+ struct cifsFileInfo *cfile = NULL;
+ struct TCP_Server_Info *server;
+ struct cifs_pending_open open;
+ bool posix_open_ok = false;
+ struct cifs_fid fid = {};
+ struct tcon_link *tlink;
+ struct cifs_tcon *tcon;
+ const char *full_path;
+ unsigned int sbflags;
int rc = -EACCES;
unsigned int xid;
__u32 oplock;
- struct cifs_sb_info *cifs_sb;
- struct TCP_Server_Info *server;
- struct cifs_tcon *tcon;
- struct tcon_link *tlink;
- struct cifsFileInfo *cfile = NULL;
void *page;
- const char *full_path;
- bool posix_open_ok = false;
- struct cifs_fid fid = {};
- struct cifs_pending_open open;
- struct cifs_open_info_data data = {};
xid = get_xid();
- cifs_sb = CIFS_SB(inode->i_sb);
if (unlikely(cifs_forced_shutdown(cifs_sb))) {
free_xid(xid);
return smb_EIO(smb_eio_trace_forced_shutdown);
@@ -1056,9 +1056,9 @@ int cifs_open(struct inode *inode, struct file *file)
cifs_dbg(FYI, "inode = 0x%p file flags are 0x%x for %s\n",
inode, file->f_flags, full_path);
- if (file->f_flags & O_DIRECT &&
- cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO) {
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+ sbflags = cifs_sb_flags(cifs_sb);
+ if ((file->f_flags & O_DIRECT) && (sbflags & CIFS_MOUNT_STRICT_IO)) {
+ if (sbflags & CIFS_MOUNT_NO_BRL)
file->f_op = &cifs_file_direct_nobrl_ops;
else
file->f_op = &cifs_file_direct_ops;
@@ -1209,7 +1209,7 @@ cifs_relock_file(struct cifsFileInfo *cfile)
struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
int rc = 0;
#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
- struct cifs_sb_info *cifs_sb = CIFS_SB(cfile->dentry->d_sb);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(cinode);
#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
down_read_nested(&cinode->lock_sem, SINGLE_DEPTH_NESTING);
@@ -1222,7 +1222,7 @@ cifs_relock_file(struct cifsFileInfo *cfile)
#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
if (cap_unix(tcon->ses) &&
(CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
- ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
+ ((cifs_sb_flags(cifs_sb) & CIFS_MOUNT_NOPOSIXBRL) == 0))
rc = cifs_push_posix_locks(cfile);
else
#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
@@ -2011,7 +2011,7 @@ cifs_push_locks(struct cifsFileInfo *cfile)
struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
int rc = 0;
#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
- struct cifs_sb_info *cifs_sb = CIFS_SB(cfile->dentry->d_sb);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(cinode);
#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
/* we are going to update can_cache_brlcks here - need a write access */
@@ -2024,7 +2024,7 @@ cifs_push_locks(struct cifsFileInfo *cfile)
#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
if (cap_unix(tcon->ses) &&
(CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
- ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
+ ((cifs_sb_flags(cifs_sb) & CIFS_MOUNT_NOPOSIXBRL) == 0))
rc = cifs_push_posix_locks(cfile);
else
#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
@@ -2428,11 +2428,11 @@ int cifs_flock(struct file *file, int cmd, struct file_lock *fl)
cifs_read_flock(fl, &type, &lock, &unlock, &wait_flag,
tcon->ses->server);
- cifs_sb = CIFS_FILE_SB(file);
+ cifs_sb = CIFS_SB(file);
if (cap_unix(tcon->ses) &&
(CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
- ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
+ ((cifs_sb_flags(cifs_sb) & CIFS_MOUNT_NOPOSIXBRL) == 0))
posix_lck = true;
if (!lock && !unlock) {
@@ -2455,14 +2455,14 @@ int cifs_flock(struct file *file, int cmd, struct file_lock *fl)
int cifs_lock(struct file *file, int cmd, struct file_lock *flock)
{
- int rc, xid;
+ struct cifs_sb_info *cifs_sb = CIFS_SB(file);
+ struct cifsFileInfo *cfile;
int lock = 0, unlock = 0;
bool wait_flag = false;
bool posix_lck = false;
- struct cifs_sb_info *cifs_sb;
struct cifs_tcon *tcon;
- struct cifsFileInfo *cfile;
__u32 type;
+ int rc, xid;
rc = -EACCES;
xid = get_xid();
@@ -2477,12 +2477,11 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *flock)
cifs_read_flock(flock, &type, &lock, &unlock, &wait_flag,
tcon->ses->server);
- cifs_sb = CIFS_FILE_SB(file);
set_bit(CIFS_INO_CLOSE_ON_LOCK, &CIFS_I(d_inode(cfile->dentry))->flags);
if (cap_unix(tcon->ses) &&
(CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
- ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
+ ((cifs_sb_flags(cifs_sb) & CIFS_MOUNT_NOPOSIXBRL) == 0))
posix_lck = true;
/*
* BB add code here to normalize offset and length to account for
@@ -2532,11 +2531,11 @@ void cifs_write_subrequest_terminated(struct cifs_io_subrequest *wdata, ssize_t
struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
bool fsuid_only)
{
+ struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode);
struct cifsFileInfo *open_file = NULL;
- struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->netfs.inode.i_sb);
/* only filter by fsuid on multiuser mounts */
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
+ if (!(cifs_sb_flags(cifs_sb) & CIFS_MOUNT_MULTIUSER))
fsuid_only = false;
spin_lock(&cifs_inode->open_file_lock);
@@ -2589,10 +2588,10 @@ cifs_get_writable_file(struct cifsInodeInfo *cifs_inode, int flags,
return rc;
}
- cifs_sb = CIFS_SB(cifs_inode->netfs.inode.i_sb);
+ cifs_sb = CIFS_SB(cifs_inode);
/* only filter by fsuid on multiuser mounts */
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
+ if (!(cifs_sb_flags(cifs_sb) & CIFS_MOUNT_MULTIUSER))
fsuid_only = false;
spin_lock(&cifs_inode->open_file_lock);
@@ -2787,7 +2786,7 @@ int cifs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
struct TCP_Server_Info *server;
struct cifsFileInfo *smbfile = file->private_data;
struct inode *inode = file_inode(file);
- struct cifs_sb_info *cifs_sb = CIFS_FILE_SB(file);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(file);
rc = file_write_and_wait_range(file, start, end);
if (rc) {
@@ -2801,7 +2800,7 @@ int cifs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
file, datasync);
tcon = tlink_tcon(smbfile->tlink);
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) {
+ if (!(cifs_sb_flags(cifs_sb) & CIFS_MOUNT_NOSSYNC)) {
server = tcon->ses->server;
if (server->ops->flush == NULL) {
rc = -ENOSYS;
@@ -2853,7 +2852,7 @@ cifs_writev(struct kiocb *iocb, struct iov_iter *from)
struct inode *inode = file->f_mapping->host;
struct cifsInodeInfo *cinode = CIFS_I(inode);
struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server;
- struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode);
ssize_t rc;
rc = netfs_start_io_write(inode);
@@ -2870,7 +2869,7 @@ cifs_writev(struct kiocb *iocb, struct iov_iter *from)
if (rc <= 0)
goto out;
- if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) &&
+ if ((cifs_sb_flags(cifs_sb) & CIFS_MOUNT_NOPOSIXBRL) &&
(cifs_find_lock_conflict(cfile, iocb->ki_pos, iov_iter_count(from),
server->vals->exclusive_lock_type, 0,
NULL, CIFS_WRITE_OP))) {
@@ -2893,7 +2892,7 @@ cifs_strict_writev(struct kiocb *iocb, struct iov_iter *from)
{
struct inode *inode = file_inode(iocb->ki_filp);
struct cifsInodeInfo *cinode = CIFS_I(inode);
- struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode);
struct cifsFileInfo *cfile = (struct cifsFileInfo *)
iocb->ki_filp->private_data;
struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
@@ -2906,7 +2905,7 @@ cifs_strict_writev(struct kiocb *iocb, struct iov_iter *from)
if (CIFS_CACHE_WRITE(cinode)) {
if (cap_unix(tcon->ses) &&
(CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
- ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0)) {
+ ((cifs_sb_flags(cifs_sb) & CIFS_MOUNT_NOPOSIXBRL) == 0)) {
written = netfs_file_write_iter(iocb, from);
goto out;
}
@@ -2994,7 +2993,7 @@ cifs_strict_readv(struct kiocb *iocb, struct iov_iter *to)
{
struct inode *inode = file_inode(iocb->ki_filp);
struct cifsInodeInfo *cinode = CIFS_I(inode);
- struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode);
struct cifsFileInfo *cfile = (struct cifsFileInfo *)
iocb->ki_filp->private_data;
struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
@@ -3011,7 +3010,7 @@ cifs_strict_readv(struct kiocb *iocb, struct iov_iter *to)
if (!CIFS_CACHE_READ(cinode))
return netfs_unbuffered_read_iter(iocb, to);
- if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0) {
+ if ((cifs_sb_flags(cifs_sb) & CIFS_MOUNT_NOPOSIXBRL) == 0) {
if (iocb->ki_flags & IOCB_DIRECT)
return netfs_unbuffered_read_iter(iocb, to);
return netfs_buffered_read_iter(iocb, to);
@@ -3130,10 +3129,9 @@ bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file,
if (is_inode_writable(cifsInode) ||
((cifsInode->oplock & CIFS_CACHE_RW_FLG) != 0 && from_readdir)) {
/* This inode is open for write at least once */
- struct cifs_sb_info *cifs_sb;
+ struct cifs_sb_info *cifs_sb = CIFS_SB(cifsInode);
- cifs_sb = CIFS_SB(cifsInode->netfs.inode.i_sb);
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
+ if (cifs_sb_flags(cifs_sb) & CIFS_MOUNT_DIRECT_IO) {
/* since no page cache to corrupt on directio
we can change size safely */
return true;
@@ -3181,7 +3179,7 @@ void cifs_oplock_break(struct work_struct *work)
server = tcon->ses->server;
scoped_guard(spinlock, &cinode->open_file_lock) {
- unsigned int sbflags = cifs_sb->mnt_cifs_flags;
+ unsigned int sbflags = cifs_sb_flags(cifs_sb);
server->ops->downgrade_oplock(server, cinode, cfile->oplock_level,
cfile->oplock_epoch, &purge_cache);
diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c
index 09fe749e97ee..54090739535f 100644
--- a/fs/smb/client/fs_context.c
+++ b/fs/smb/client/fs_context.c
@@ -2062,161 +2062,160 @@ smb3_cleanup_fs_context(struct smb3_fs_context *ctx)
kfree(ctx);
}
-void smb3_update_mnt_flags(struct cifs_sb_info *cifs_sb)
+unsigned int smb3_update_mnt_flags(struct cifs_sb_info *cifs_sb)
{
+ unsigned int sbflags = cifs_sb_flags(cifs_sb);
struct smb3_fs_context *ctx = cifs_sb->ctx;
if (ctx->nodfs)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_DFS;
+ sbflags |= CIFS_MOUNT_NO_DFS;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_NO_DFS;
+ sbflags &= ~CIFS_MOUNT_NO_DFS;
if (ctx->noperm)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
+ sbflags |= CIFS_MOUNT_NO_PERM;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_NO_PERM;
+ sbflags &= ~CIFS_MOUNT_NO_PERM;
if (ctx->setuids)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
+ sbflags |= CIFS_MOUNT_SET_UID;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SET_UID;
+ sbflags &= ~CIFS_MOUNT_SET_UID;
if (ctx->setuidfromacl)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UID_FROM_ACL;
+ sbflags |= CIFS_MOUNT_UID_FROM_ACL;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_UID_FROM_ACL;
+ sbflags &= ~CIFS_MOUNT_UID_FROM_ACL;
if (ctx->server_ino)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
+ sbflags |= CIFS_MOUNT_SERVER_INUM;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM;
+ sbflags &= ~CIFS_MOUNT_SERVER_INUM;
if (ctx->remap)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SFM_CHR;
+ sbflags |= CIFS_MOUNT_MAP_SFM_CHR;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_MAP_SFM_CHR;
+ sbflags &= ~CIFS_MOUNT_MAP_SFM_CHR;
if (ctx->sfu_remap)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
+ sbflags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_MAP_SPECIAL_CHR;
+ sbflags &= ~CIFS_MOUNT_MAP_SPECIAL_CHR;
if (ctx->no_xattr)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
+ sbflags |= CIFS_MOUNT_NO_XATTR;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_NO_XATTR;
+ sbflags &= ~CIFS_MOUNT_NO_XATTR;
if (ctx->sfu_emul)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
+ sbflags |= CIFS_MOUNT_UNX_EMUL;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_UNX_EMUL;
+ sbflags &= ~CIFS_MOUNT_UNX_EMUL;
if (ctx->nobrl)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
+ sbflags |= CIFS_MOUNT_NO_BRL;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_NO_BRL;
+ sbflags &= ~CIFS_MOUNT_NO_BRL;
if (ctx->nohandlecache)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_HANDLE_CACHE;
+ sbflags |= CIFS_MOUNT_NO_HANDLE_CACHE;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_NO_HANDLE_CACHE;
+ sbflags &= ~CIFS_MOUNT_NO_HANDLE_CACHE;
if (ctx->nostrictsync)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOSSYNC;
+ sbflags |= CIFS_MOUNT_NOSSYNC;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_NOSSYNC;
+ sbflags &= ~CIFS_MOUNT_NOSSYNC;
if (ctx->mand_lock)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOPOSIXBRL;
+ sbflags |= CIFS_MOUNT_NOPOSIXBRL;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_NOPOSIXBRL;
+ sbflags &= ~CIFS_MOUNT_NOPOSIXBRL;
if (ctx->rwpidforward)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_RWPIDFORWARD;
+ sbflags |= CIFS_MOUNT_RWPIDFORWARD;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_RWPIDFORWARD;
+ sbflags &= ~CIFS_MOUNT_RWPIDFORWARD;
if (ctx->mode_ace)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MODE_FROM_SID;
+ sbflags |= CIFS_MOUNT_MODE_FROM_SID;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_MODE_FROM_SID;
+ sbflags &= ~CIFS_MOUNT_MODE_FROM_SID;
if (ctx->cifs_acl)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
+ sbflags |= CIFS_MOUNT_CIFS_ACL;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_CIFS_ACL;
+ sbflags &= ~CIFS_MOUNT_CIFS_ACL;
if (ctx->backupuid_specified)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_BACKUPUID;
+ sbflags |= CIFS_MOUNT_CIFS_BACKUPUID;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_CIFS_BACKUPUID;
+ sbflags &= ~CIFS_MOUNT_CIFS_BACKUPUID;
if (ctx->backupgid_specified)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_BACKUPGID;
+ sbflags |= CIFS_MOUNT_CIFS_BACKUPGID;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_CIFS_BACKUPGID;
+ sbflags &= ~CIFS_MOUNT_CIFS_BACKUPGID;
if (ctx->override_uid)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
+ sbflags |= CIFS_MOUNT_OVERR_UID;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_OVERR_UID;
+ sbflags &= ~CIFS_MOUNT_OVERR_UID;
if (ctx->override_gid)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
+ sbflags |= CIFS_MOUNT_OVERR_GID;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_OVERR_GID;
+ sbflags &= ~CIFS_MOUNT_OVERR_GID;
if (ctx->dynperm)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM;
+ sbflags |= CIFS_MOUNT_DYNPERM;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_DYNPERM;
+ sbflags &= ~CIFS_MOUNT_DYNPERM;
if (ctx->fsc)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_FSCACHE;
+ sbflags |= CIFS_MOUNT_FSCACHE;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_FSCACHE;
+ sbflags &= ~CIFS_MOUNT_FSCACHE;
if (ctx->multiuser)
- cifs_sb->mnt_cifs_flags |= (CIFS_MOUNT_MULTIUSER |
- CIFS_MOUNT_NO_PERM);
+ sbflags |= CIFS_MOUNT_MULTIUSER | CIFS_MOUNT_NO_PERM;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_MULTIUSER;
+ sbflags &= ~CIFS_MOUNT_MULTIUSER;
if (ctx->strict_io)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_STRICT_IO;
+ sbflags |= CIFS_MOUNT_STRICT_IO;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_STRICT_IO;
+ sbflags &= ~CIFS_MOUNT_STRICT_IO;
if (ctx->direct_io)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
+ sbflags |= CIFS_MOUNT_DIRECT_IO;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_DIRECT_IO;
+ sbflags &= ~CIFS_MOUNT_DIRECT_IO;
if (ctx->mfsymlinks)
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MF_SYMLINKS;
+ sbflags |= CIFS_MOUNT_MF_SYMLINKS;
else
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_MF_SYMLINKS;
- if (ctx->mfsymlinks) {
- if (ctx->sfu_emul) {
- /*
- * Our SFU ("Services for Unix") emulation allows now
- * creating new and reading existing SFU symlinks.
- * Older Linux kernel versions were not able to neither
- * read existing nor create new SFU symlinks. But
- * creating and reading SFU style mknod and FIFOs was
- * supported for long time. When "mfsymlinks" and
- * "sfu" are both enabled at the same time, it allows
- * reading both types of symlinks, but will only create
- * them with mfsymlinks format. This allows better
- * Apple compatibility, compatibility with older Linux
- * kernel clients (probably better for Samba too)
- * while still recognizing old Windows style symlinks.
- */
- cifs_dbg(VFS, "mount options mfsymlinks and sfu both enabled\n");
- }
- }
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SHUTDOWN;
+ sbflags &= ~CIFS_MOUNT_MF_SYMLINKS;
- return;
+ if (ctx->mfsymlinks && ctx->sfu_emul) {
+ /*
+ * Our SFU ("Services for Unix") emulation allows now
+ * creating new and reading existing SFU symlinks.
+ * Older Linux kernel versions were not able to neither
+ * read existing nor create new SFU symlinks. But
+ * creating and reading SFU style mknod and FIFOs was
+ * supported for long time. When "mfsymlinks" and
+ * "sfu" are both enabled at the same time, it allows
+ * reading both types of symlinks, but will only create
+ * them with mfsymlinks format. This allows better
+ * Apple compatibility, compatibility with older Linux
+ * kernel clients (probably better for Samba too)
+ * while still recognizing old Windows style symlinks.
+ */
+ cifs_dbg(VFS, "mount options mfsymlinks and sfu both enabled\n");
+ }
+ sbflags &= ~CIFS_MOUNT_SHUTDOWN;
+ atomic_set(&cifs_sb->mnt_cifs_flags, sbflags);
+ return sbflags;
}
diff --git a/fs/smb/client/fs_context.h b/fs/smb/client/fs_context.h
index 49b2a6f09ca2..0b64fcb5d302 100644
--- a/fs/smb/client/fs_context.h
+++ b/fs/smb/client/fs_context.h
@@ -374,7 +374,7 @@ int smb3_fs_context_dup(struct smb3_fs_context *new_ctx,
struct smb3_fs_context *ctx);
int smb3_sync_session_ctx_passwords(struct cifs_sb_info *cifs_sb,
struct cifs_ses *ses);
-void smb3_update_mnt_flags(struct cifs_sb_info *cifs_sb);
+unsigned int smb3_update_mnt_flags(struct cifs_sb_info *cifs_sb);
/*
* max deferred close timeout (jiffies) - 2^30
diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c
index d4d3cfeb6c90..3e844c55ab8a 100644
--- a/fs/smb/client/inode.c
+++ b/fs/smb/client/inode.c
@@ -40,32 +40,33 @@ static void cifs_set_netfs_context(struct inode *inode)
static void cifs_set_ops(struct inode *inode)
{
- struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode);
+ struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
struct netfs_inode *ictx = netfs_inode(inode);
+ unsigned int sbflags = cifs_sb_flags(cifs_sb);
switch (inode->i_mode & S_IFMT) {
case S_IFREG:
inode->i_op = &cifs_file_inode_ops;
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
+ if (sbflags & CIFS_MOUNT_DIRECT_IO) {
set_bit(NETFS_ICTX_UNBUFFERED, &ictx->flags);
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+ if (sbflags & CIFS_MOUNT_NO_BRL)
inode->i_fop = &cifs_file_direct_nobrl_ops;
else
inode->i_fop = &cifs_file_direct_ops;
- } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO) {
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+ } else if (sbflags & CIFS_MOUNT_STRICT_IO) {
+ if (sbflags & CIFS_MOUNT_NO_BRL)
inode->i_fop = &cifs_file_strict_nobrl_ops;
else
inode->i_fop = &cifs_file_strict_ops;
- } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+ } else if (sbflags & CIFS_MOUNT_NO_BRL)
inode->i_fop = &cifs_file_nobrl_ops;
else { /* not direct, send byte range locks */
inode->i_fop = &cifs_file_ops;
}
/* check if server can support readahead */
- if (cifs_sb_master_tcon(cifs_sb)->ses->server->max_read <
- PAGE_SIZE + MAX_CIFS_HDR_SIZE)
+ if (tcon->ses->server->max_read < PAGE_SIZE + MAX_CIFS_HDR_SIZE)
inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
else
inode->i_data.a_ops = &cifs_addr_ops;
@@ -194,8 +195,8 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr,
inode->i_gid = fattr->cf_gid;
/* if dynperm is set, don't clobber existing mode */
- if (inode_state_read(inode) & I_NEW ||
- !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM))
+ if ((inode_state_read(inode) & I_NEW) ||
+ !(cifs_sb_flags(cifs_sb) & CIFS_MOUNT_DYNPERM))
inode->i_mode = fattr->cf_mode;
cifs_i->cifsAttrs = fattr->cf_cifsattrs;
@@ -248,10 +249,8 @@ cifs_fill_uniqueid(struct super_block *sb, struct cifs_fattr *fattr)
{
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
- return;
-
- fattr->cf_uniqueid = iunique(sb, ROOT_I);
+ if (!(cifs_sb_flags(cifs_sb) & CIFS_MOUNT_SERVER_INUM))
+ fattr->cf_uniqueid = iunique(sb, ROOT_I);
}
/* Fill a cifs_fattr struct with info from FILE_UNIX_BASIC_INFO. */
@@ -259,6 +258,8 @@ void
cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, FILE_UNIX_BASIC_INFO *info,
struct cifs_sb_info *cifs_sb)
{
+ unsigned int sbflags;
+
memset(fattr, 0, sizeof(*fattr));
fattr->cf_uniqueid = le64_to_cpu(info->UniqueId);
fattr->cf_bytes = le64_to_cpu(info->NumOfBytes);
@@ -317,8 +318,9 @@ cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, FILE_UNIX_BASIC_INFO *info,
break;
}
+ sbflags = cifs_sb_flags(cifs_sb);
fattr->cf_uid = cifs_sb->ctx->linux_uid;
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)) {
+ if (!(sbflags & CIFS_MOUNT_OVERR_UID)) {
u64 id = le64_to_cpu(info->Uid);
if (id < ((uid_t)-1)) {
kuid_t uid = make_kuid(&init_user_ns, id);
@@ -328,7 +330,7 @@ cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, FILE_UNIX_BASIC_INFO *info,
}
fattr->cf_gid = cifs_sb->ctx->linux_gid;
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)) {
+ if (!(sbflags & CIFS_MOUNT_OVERR_GID)) {
u64 id = le64_to_cpu(info->Gid);
if (id < ((gid_t)-1)) {
kgid_t gid = make_kgid(&init_user_ns, id);
@@ -382,7 +384,7 @@ static int update_inode_info(struct super_block *sb,
*
* If file type or uniqueid is different, return error.
*/
- if (unlikely((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) &&
+ if (unlikely((cifs_sb_flags(cifs_sb) & CIFS_MOUNT_SERVER_INUM) &&
CIFS_I(*inode)->uniqueid != fattr->cf_uniqueid)) {
CIFS_I(*inode)->time = 0; /* force reval */
return -ESTALE;
@@ -468,7 +470,7 @@ static int cifs_get_unix_fattr(const unsigned char *full_path,
cifs_fill_uniqueid(sb, fattr);
/* check for Minshall+French symlinks */
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
+ if (cifs_sb_flags(cifs_sb) & CIFS_MOUNT_MF_SYMLINKS) {
tmprc = check_mf_symlink(xid, tcon, cifs_sb, fattr, full_path);
cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc);
}
@@ -1081,7 +1083,7 @@ cifs_backup_query_path_info(int xid,
else if ((tcon->ses->capabilities &
tcon->ses->server->vals->cap_nt_find) == 0)
info.info_level = SMB_FIND_FILE_INFO_STANDARD;
- else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
+ else if (cifs_sb_flags(cifs_sb) & CIFS_MOUNT_SERVER_INUM)
info.info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO;
else /* no srvino useful for fallback to some netapp */
info.info_level = SMB_FIND_FILE_DIRECTORY_INFO;
@@ -1109,7 +1111,7 @@ static void cifs_set_fattr_ino(int xid, struct cifs_tcon *tcon, struct super_blo
struct TCP_Server_Info *server = tcon->ses->server;
int rc;
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) {
+ if (!(cifs_sb_flags(cifs_sb) & CIFS_MOUNT_SERVER_INUM)) {
if (*inode)
fattr->cf_uniqueid = CIFS_I(*inode)->uniqueid;
else
@@ -1263,14 +1265,15 @@ static int cifs_get_fattr(struct cifs_open_info_data *data,
struct inode **inode,
const char *full_path)
{
+ struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
struct cifs_open_info_data tmp_data = {};
- struct cifs_tcon *tcon;
+ void *smb1_backup_rsp_buf = NULL;
struct TCP_Server_Info *server;
+ struct cifs_tcon *tcon;
struct tcon_link *tlink;
- struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
- void *smb1_backup_rsp_buf = NULL;
- int rc = 0;
+ unsigned int sbflags;
int tmprc = 0;
+ int rc = 0;
tlink = cifs_sb_tlink(cifs_sb);
if (IS_ERR(tlink))
@@ -1370,16 +1373,17 @@ static int cifs_get_fattr(struct cifs_open_info_data *data,
#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
handle_mnt_opt:
#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
+ sbflags = cifs_sb_flags(cifs_sb);
/* query for SFU type info if supported and needed */
if ((fattr->cf_cifsattrs & ATTR_SYSTEM) &&
- (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) {
+ (sbflags & CIFS_MOUNT_UNX_EMUL)) {
tmprc = cifs_sfu_type(fattr, full_path, cifs_sb, xid);
if (tmprc)
cifs_dbg(FYI, "cifs_sfu_type failed: %d\n", tmprc);
}
/* fill in 0777 bits from ACL */
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID) {
+ if (sbflags & CIFS_MOUNT_MODE_FROM_SID) {
rc = cifs_acl_to_fattr(cifs_sb, fattr, *inode,
true, full_path, fid);
if (rc == -EREMOTE)
@@ -1389,7 +1393,7 @@ handle_mnt_opt:
__func__, rc);
goto out;
}
- } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
+ } else if (sbflags & CIFS_MOUNT_CIFS_ACL) {
rc = cifs_acl_to_fattr(cifs_sb, fattr, *inode,
false, full_path, fid);
if (rc == -EREMOTE)
@@ -1399,7 +1403,7 @@ handle_mnt_opt:
__func__, rc);
goto out;
}
- } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)
+ } else if (sbflags & CIFS_MOUNT_UNX_EMUL)
/* fill in remaining high mode bits e.g. SUID, VTX */
cifs_sfu_mode(fattr, full_path, cifs_sb, xid);
else if (!(tcon->posix_extensions))
@@ -1409,7 +1413,7 @@ handle_mnt_opt:
/* check for Minshall+French symlinks */
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
+ if (sbflags & CIFS_MOUNT_MF_SYMLINKS) {
tmprc = check_mf_symlink(xid, tcon, cifs_sb, fattr, full_path);
cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc);
}
@@ -1509,7 +1513,7 @@ static int smb311_posix_get_fattr(struct cifs_open_info_data *data,
* 3. Tweak fattr based on mount options
*/
/* check for Minshall+French symlinks */
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
+ if (cifs_sb_flags(cifs_sb) & CIFS_MOUNT_MF_SYMLINKS) {
tmprc = check_mf_symlink(xid, tcon, cifs_sb, fattr, full_path);
cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc);
}
@@ -1660,7 +1664,7 @@ struct inode *cifs_root_iget(struct super_block *sb)
int len;
int rc;
- if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH)
+ if ((cifs_sb_flags(cifs_sb) & CIFS_MOUNT_USE_PREFIX_PATH)
&& cifs_sb->prepath) {
len = strlen(cifs_sb->prepath);
path = kzalloc(len + 2 /* leading sep + null */, GFP_KERNEL);
@@ -2098,8 +2102,9 @@ cifs_mkdir_qinfo(struct inode *parent, struct dentry *dentry, umode_t mode,
const char *full_path, struct cifs_sb_info *cifs_sb,
struct cifs_tcon *tcon, const unsigned int xid)
{
- int rc = 0;
struct inode *inode = NULL;
+ unsigned int sbflags;
+ int rc = 0;
if (tcon->posix_extensions) {
rc = smb311_posix_get_inode_info(&inode, full_path,
@@ -2139,6 +2144,7 @@ cifs_mkdir_qinfo(struct inode *parent, struct dentry *dentry, umode_t mode,
if (parent->i_mode & S_ISGID)
mode |= S_ISGID;
+ sbflags = cifs_sb_flags(cifs_sb);
#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
if (tcon->unix_ext) {
struct cifs_unix_set_info_args args = {
@@ -2148,7 +2154,7 @@ cifs_mkdir_qinfo(struct inode *parent, struct dentry *dentry, umode_t mode,
.mtime = NO_CHANGE_64,
.device = 0,
};
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
+ if (sbflags & CIFS_MOUNT_SET_UID) {
args.uid = current_fsuid();
if (parent->i_mode & S_ISGID)
args.gid = parent->i_gid;
@@ -2166,14 +2172,14 @@ cifs_mkdir_qinfo(struct inode *parent, struct dentry *dentry, umode_t mode,
{
#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
struct TCP_Server_Info *server = tcon->ses->server;
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
+ if (!(sbflags & CIFS_MOUNT_CIFS_ACL) &&
(mode & S_IWUGO) == 0 && server->ops->mkdir_setinfo)
server->ops->mkdir_setinfo(inode, full_path, cifs_sb,
tcon, xid);
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
+ if (sbflags & CIFS_MOUNT_DYNPERM)
inode->i_mode = (mode | S_IFDIR);
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
+ if (sbflags & CIFS_MOUNT_SET_UID) {
inode->i_uid = current_fsuid();
if (inode->i_mode & S_ISGID)
inode->i_gid = parent->i_gid;
@@ -2686,7 +2692,7 @@ cifs_dentry_needs_reval(struct dentry *dentry)
{
struct inode *inode = d_inode(dentry);
struct cifsInodeInfo *cifs_i = CIFS_I(inode);
- struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode);
struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
struct cached_fid *cfid = NULL;
@@ -2727,7 +2733,7 @@ cifs_dentry_needs_reval(struct dentry *dentry)
}
/* hardlinked files w/ noserverino get "special" treatment */
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) &&
+ if (!(cifs_sb_flags(cifs_sb) & CIFS_MOUNT_SERVER_INUM) &&
S_ISREG(inode->i_mode) && inode->i_nlink != 1)
return true;
@@ -2752,10 +2758,10 @@ cifs_wait_bit_killable(struct wait_bit_key *key, int mode)
int
cifs_revalidate_mapping(struct inode *inode)
{
- int rc;
struct cifsInodeInfo *cifs_inode = CIFS_I(inode);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode);
unsigned long *flags = &cifs_inode->flags;
- struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+ int rc;
/* swapfiles are not supposed to be shared */
if (IS_SWAPFILE(inode))
@@ -2768,7 +2774,7 @@ cifs_revalidate_mapping(struct inode *inode)
if (test_and_clear_bit(CIFS_INO_INVALID_MAPPING, flags)) {
/* for cache=singleclient, do not invalidate */
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RW_CACHE)
+ if (cifs_sb_flags(cifs_sb) & CIFS_MOUNT_RW_CACHE)
goto skip_invalidate;
cifs_inode->netfs.zero_point = cifs_inode->netfs.remote_i_size;
@@ -2892,10 +2898,11 @@ int cifs_revalidate_dentry(struct dentry *dentry)
int cifs_getattr(struct mnt_idmap *idmap, const struct path *path,
struct kstat *stat, u32 request_mask, unsigned int flags)
{
- struct dentry *dentry = path->dentry;
- struct cifs_sb_info *cifs_sb = CIFS_SB(dentry->d_sb);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(path->dentry);
struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
+ struct dentry *dentry = path->dentry;
struct inode *inode = d_inode(dentry);
+ unsigned int sbflags;
int rc;
if (unlikely(cifs_forced_shutdown(CIFS_SB(inode->i_sb))))
@@ -2952,12 +2959,13 @@ int cifs_getattr(struct mnt_idmap *idmap, const struct path *path,
* enabled, and the admin hasn't overridden them, set the ownership
* to the fsuid/fsgid of the current process.
*/
- if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER) &&
- !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
+ sbflags = cifs_sb_flags(cifs_sb);
+ if ((sbflags & CIFS_MOUNT_MULTIUSER) &&
+ !(sbflags & CIFS_MOUNT_CIFS_ACL) &&
!tcon->unix_ext) {
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID))
+ if (!(sbflags & CIFS_MOUNT_OVERR_UID))
stat->uid = current_fsuid();
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID))
+ if (!(sbflags & CIFS_MOUNT_OVERR_GID))
stat->gid = current_fsgid();
}
return 0;
@@ -3102,7 +3110,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
void *page = alloc_dentry_path();
struct inode *inode = d_inode(direntry);
struct cifsInodeInfo *cifsInode = CIFS_I(inode);
- struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode);
struct tcon_link *tlink;
struct cifs_tcon *pTcon;
struct cifs_unix_set_info_args *args = NULL;
@@ -3113,7 +3121,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
xid = get_xid();
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
+ if (cifs_sb_flags(cifs_sb) & CIFS_MOUNT_NO_PERM)
attrs->ia_valid |= ATTR_FORCE;
rc = setattr_prepare(&nop_mnt_idmap, direntry, attrs);
@@ -3266,26 +3274,26 @@ out:
static int
cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
{
- unsigned int xid;
- kuid_t uid = INVALID_UID;
- kgid_t gid = INVALID_GID;
struct inode *inode = d_inode(direntry);
- struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
struct cifsInodeInfo *cifsInode = CIFS_I(inode);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode);
+ unsigned int sbflags = cifs_sb_flags(cifs_sb);
struct cifsFileInfo *cfile = NULL;
- const char *full_path;
void *page = alloc_dentry_path();
- int rc = -EACCES;
- __u32 dosattr = 0;
__u64 mode = NO_CHANGE_64;
- bool posix = cifs_sb_master_tcon(cifs_sb)->posix_extensions;
+ kuid_t uid = INVALID_UID;
+ kgid_t gid = INVALID_GID;
+ const char *full_path;
+ __u32 dosattr = 0;
+ int rc = -EACCES;
+ unsigned int xid;
xid = get_xid();
cifs_dbg(FYI, "setattr on file %pd attrs->ia_valid 0x%x\n",
direntry, attrs->ia_valid);
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
+ if (sbflags & CIFS_MOUNT_NO_PERM)
attrs->ia_valid |= ATTR_FORCE;
rc = setattr_prepare(&nop_mnt_idmap, direntry, attrs);
@@ -3346,8 +3354,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
if (attrs->ia_valid & ATTR_GID)
gid = attrs->ia_gid;
- if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) ||
- (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID)) {
+ if (sbflags & (CIFS_MOUNT_CIFS_ACL | CIFS_MOUNT_MODE_FROM_SID)) {
if (uid_valid(uid) || gid_valid(gid)) {
mode = NO_CHANGE_64;
rc = id_mode_to_cifs_acl(inode, full_path, &mode,
@@ -3358,9 +3365,9 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
goto cifs_setattr_exit;
}
}
- } else
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID))
+ } else if (!(sbflags & CIFS_MOUNT_SET_UID)) {
attrs->ia_valid &= ~(ATTR_UID | ATTR_GID);
+ }
/* skip mode change if it's just for clearing setuid/setgid */
if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID))
@@ -3369,9 +3376,8 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
if (attrs->ia_valid & ATTR_MODE) {
mode = attrs->ia_mode;
rc = 0;
- if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) ||
- (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID) ||
- posix) {
+ if ((sbflags & (CIFS_MOUNT_CIFS_ACL | CIFS_MOUNT_MODE_FROM_SID)) ||
+ cifs_sb_master_tcon(cifs_sb)->posix_extensions) {
rc = id_mode_to_cifs_acl(inode, full_path, &mode,
INVALID_UID, INVALID_GID);
if (rc) {
@@ -3393,7 +3399,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
dosattr = cifsInode->cifsAttrs | ATTR_READONLY;
/* fix up mode if we're not using dynperm */
- if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0)
+ if ((sbflags & CIFS_MOUNT_DYNPERM) == 0)
attrs->ia_mode = inode->i_mode & ~S_IWUGO;
} else if ((mode & S_IWUGO) &&
(cifsInode->cifsAttrs & ATTR_READONLY)) {
@@ -3404,7 +3410,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
dosattr |= ATTR_NORMAL;
/* reset local inode permissions to normal */
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) {
+ if (!(sbflags & CIFS_MOUNT_DYNPERM)) {
attrs->ia_mode &= ~(S_IALLUGO);
if (S_ISDIR(inode->i_mode))
attrs->ia_mode |=
@@ -3413,7 +3419,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
attrs->ia_mode |=
cifs_sb->ctx->file_mode;
}
- } else if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) {
+ } else if (!(sbflags & CIFS_MOUNT_DYNPERM)) {
/* ignore mode change - ATTR_READONLY hasn't changed */
attrs->ia_valid &= ~ATTR_MODE;
}
diff --git a/fs/smb/client/ioctl.c b/fs/smb/client/ioctl.c
index 8dc2651e237f..9afab3237e54 100644
--- a/fs/smb/client/ioctl.c
+++ b/fs/smb/client/ioctl.c
@@ -216,7 +216,7 @@ static int cifs_shutdown(struct super_block *sb, unsigned long arg)
*/
case CIFS_GOING_FLAGS_LOGFLUSH:
case CIFS_GOING_FLAGS_NOLOGFLUSH:
- sbi->mnt_cifs_flags |= CIFS_MOUNT_SHUTDOWN;
+ atomic_or(CIFS_MOUNT_SHUTDOWN, &sbi->mnt_cifs_flags);
goto shutdown_good;
default:
rc = -EINVAL;
diff --git a/fs/smb/client/link.c b/fs/smb/client/link.c
index a2f7bfa8ad1e..434e8fe74080 100644
--- a/fs/smb/client/link.c
+++ b/fs/smb/client/link.c
@@ -544,14 +544,15 @@ int
cifs_symlink(struct mnt_idmap *idmap, struct inode *inode,
struct dentry *direntry, const char *symname)
{
- int rc = -EOPNOTSUPP;
- unsigned int xid;
- struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode);
+ struct inode *newinode = NULL;
struct tcon_link *tlink;
struct cifs_tcon *pTcon;
const char *full_path;
+ int rc = -EOPNOTSUPP;
+ unsigned int sbflags;
+ unsigned int xid;
void *page;
- struct inode *newinode = NULL;
if (unlikely(cifs_forced_shutdown(cifs_sb)))
return smb_EIO(smb_eio_trace_forced_shutdown);
@@ -580,6 +581,7 @@ cifs_symlink(struct mnt_idmap *idmap, struct inode *inode,
cifs_dbg(FYI, "symname is %s\n", symname);
/* BB what if DFS and this volume is on different share? BB */
+ sbflags = cifs_sb_flags(cifs_sb);
rc = -EOPNOTSUPP;
switch (cifs_symlink_type(cifs_sb)) {
case CIFS_SYMLINK_TYPE_UNIX:
@@ -594,14 +596,14 @@ cifs_symlink(struct mnt_idmap *idmap, struct inode *inode,
break;
case CIFS_SYMLINK_TYPE_MFSYMLINKS:
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
+ if (sbflags & CIFS_MOUNT_MF_SYMLINKS) {
rc = create_mf_symlink(xid, pTcon, cifs_sb,
full_path, symname);
}
break;
case CIFS_SYMLINK_TYPE_SFU:
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
+ if (sbflags & CIFS_MOUNT_UNX_EMUL) {
rc = __cifs_sfu_make_node(xid, inode, direntry, pTcon,
full_path, S_IFLNK,
0, symname);
diff --git a/fs/smb/client/misc.c b/fs/smb/client/misc.c
index 22cde46309fe..bc24c92b8b95 100644
--- a/fs/smb/client/misc.c
+++ b/fs/smb/client/misc.c
@@ -275,13 +275,15 @@ dump_smb(void *buf, int smb_buf_length)
void
cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb)
{
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
+ unsigned int sbflags = cifs_sb_flags(cifs_sb);
+
+ if (sbflags & CIFS_MOUNT_SERVER_INUM) {
struct cifs_tcon *tcon = NULL;
if (cifs_sb->master_tlink)
tcon = cifs_sb_master_tcon(cifs_sb);
- cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM;
+ atomic_andnot(CIFS_MOUNT_SERVER_INUM, &cifs_sb->mnt_cifs_flags);
cifs_sb->mnt_cifs_serverino_autodisabled = true;
cifs_dbg(VFS, "Autodisabling the use of server inode numbers on %s\n",
tcon ? tcon->tree_name : "new server");
@@ -382,11 +384,13 @@ void cifs_done_oplock_break(struct cifsInodeInfo *cinode)
bool
backup_cred(struct cifs_sb_info *cifs_sb)
{
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_BACKUPUID) {
+ unsigned int sbflags = cifs_sb_flags(cifs_sb);
+
+ if (sbflags & CIFS_MOUNT_CIFS_BACKUPUID) {
if (uid_eq(cifs_sb->ctx->backupuid, current_fsuid()))
return true;
}
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_BACKUPGID) {
+ if (sbflags & CIFS_MOUNT_CIFS_BACKUPGID) {
if (in_group_p(cifs_sb->ctx->backupgid))
return true;
}
@@ -955,7 +959,7 @@ int cifs_update_super_prepath(struct cifs_sb_info *cifs_sb, char *prefix)
convert_delimiter(cifs_sb->prepath, CIFS_DIR_SEP(cifs_sb));
}
- cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
+ atomic_or(CIFS_MOUNT_USE_PREFIX_PATH, &cifs_sb->mnt_cifs_flags);
return 0;
}
@@ -984,7 +988,7 @@ int cifs_inval_name_dfs_link_error(const unsigned int xid,
* look up or tcon is not DFS.
*/
if (strlen(full_path) < 2 || !cifs_sb ||
- (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS) ||
+ (cifs_sb_flags(cifs_sb) & CIFS_MOUNT_NO_DFS) ||
!is_tcon_dfs(tcon))
return 0;
diff --git a/fs/smb/client/readdir.c b/fs/smb/client/readdir.c
index 8615a8747b7f..be22bbc4a65a 100644
--- a/fs/smb/client/readdir.c
+++ b/fs/smb/client/readdir.c
@@ -121,7 +121,7 @@ retry:
* want to clobber the existing one with the one that
* the readdir code created.
*/
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM))
+ if (!(cifs_sb_flags(cifs_sb) & CIFS_MOUNT_SERVER_INUM))
fattr->cf_uniqueid = CIFS_I(inode)->uniqueid;
/*
@@ -177,6 +177,7 @@ cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb)
struct cifs_open_info_data data = {
.reparse = { .tag = fattr->cf_cifstag, },
};
+ unsigned int sbflags;
fattr->cf_uid = cifs_sb->ctx->linux_uid;
fattr->cf_gid = cifs_sb->ctx->linux_gid;
@@ -215,12 +216,12 @@ out_reparse:
* may look wrong since the inodes may not have timed out by the time
* "ls" does a stat() call on them.
*/
- if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) ||
- (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID))
+ sbflags = cifs_sb_flags(cifs_sb);
+ if (sbflags & (CIFS_MOUNT_CIFS_ACL | CIFS_MOUNT_MODE_FROM_SID))
fattr->cf_flags |= CIFS_FATTR_NEED_REVAL;
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL &&
- fattr->cf_cifsattrs & ATTR_SYSTEM) {
+ if ((sbflags & CIFS_MOUNT_UNX_EMUL) &&
+ (fattr->cf_cifsattrs & ATTR_SYSTEM)) {
if (fattr->cf_eof == 0) {
fattr->cf_mode &= ~S_IFMT;
fattr->cf_mode |= S_IFIFO;
@@ -345,13 +346,14 @@ static int
_initiate_cifs_search(const unsigned int xid, struct file *file,
const char *full_path)
{
- __u16 search_flags;
- int rc = 0;
- struct cifsFileInfo *cifsFile;
- struct cifs_sb_info *cifs_sb = CIFS_FILE_SB(file);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(file);
struct tcon_link *tlink = NULL;
- struct cifs_tcon *tcon;
struct TCP_Server_Info *server;
+ struct cifsFileInfo *cifsFile;
+ struct cifs_tcon *tcon;
+ unsigned int sbflags;
+ __u16 search_flags;
+ int rc = 0;
if (file->private_data == NULL) {
tlink = cifs_sb_tlink(cifs_sb);
@@ -385,6 +387,7 @@ _initiate_cifs_search(const unsigned int xid, struct file *file,
cifs_dbg(FYI, "Full path: %s start at: %lld\n", full_path, file->f_pos);
ffirst_retry:
+ sbflags = cifs_sb_flags(cifs_sb);
/* test for Unix extensions */
/* but now check for them on the share/mount not on the SMB session */
/* if (cap_unix(tcon->ses) { */
@@ -395,7 +398,7 @@ ffirst_retry:
else if ((tcon->ses->capabilities &
tcon->ses->server->vals->cap_nt_find) == 0) {
cifsFile->srch_inf.info_level = SMB_FIND_FILE_INFO_STANDARD;
- } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
+ } else if (sbflags & CIFS_MOUNT_SERVER_INUM) {
cifsFile->srch_inf.info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO;
} else /* not srvinos - BB fixme add check for backlevel? */ {
cifsFile->srch_inf.info_level = SMB_FIND_FILE_FULL_DIRECTORY_INFO;
@@ -411,8 +414,7 @@ ffirst_retry:
if (rc == 0) {
cifsFile->invalidHandle = false;
- } else if ((rc == -EOPNOTSUPP) &&
- (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) {
+ } else if (rc == -EOPNOTSUPP && (sbflags & CIFS_MOUNT_SERVER_INUM)) {
cifs_autodisable_serverino(cifs_sb);
goto ffirst_retry;
}
@@ -690,7 +692,7 @@ find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon, loff_t pos,
loff_t first_entry_in_buffer;
loff_t index_to_find = pos;
struct cifsFileInfo *cfile = file->private_data;
- struct cifs_sb_info *cifs_sb = CIFS_FILE_SB(file);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(file);
struct TCP_Server_Info *server = tcon->ses->server;
/* check if index in the buffer */
@@ -955,6 +957,7 @@ static int cifs_filldir(char *find_entry, struct file *file,
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
struct cifs_dirent de = { NULL, };
struct cifs_fattr fattr;
+ unsigned int sbflags;
struct qstr name;
int rc = 0;
@@ -1019,15 +1022,15 @@ static int cifs_filldir(char *find_entry, struct file *file,
break;
}
- if (de.ino && (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) {
+ sbflags = cifs_sb_flags(cifs_sb);
+ if (de.ino && (sbflags & CIFS_MOUNT_SERVER_INUM)) {
fattr.cf_uniqueid = de.ino;
} else {
fattr.cf_uniqueid = iunique(sb, ROOT_I);
cifs_autodisable_serverino(cifs_sb);
}
- if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) &&
- couldbe_mf_symlink(&fattr))
+ if ((sbflags & CIFS_MOUNT_MF_SYMLINKS) && couldbe_mf_symlink(&fattr))
/*
* trying to get the type and mode can be slow,
* so just call those regular files for now, and mark
@@ -1058,7 +1061,7 @@ int cifs_readdir(struct file *file, struct dir_context *ctx)
const char *full_path;
void *page = alloc_dentry_path();
struct cached_fid *cfid = NULL;
- struct cifs_sb_info *cifs_sb = CIFS_FILE_SB(file);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(file);
xid = get_xid();
diff --git a/fs/smb/client/reparse.c b/fs/smb/client/reparse.c
index ce9b923498b5..cd1e1eaee67a 100644
--- a/fs/smb/client/reparse.c
+++ b/fs/smb/client/reparse.c
@@ -55,17 +55,18 @@ static int create_native_symlink(const unsigned int xid, struct inode *inode,
const char *full_path, const char *symname)
{
struct reparse_symlink_data_buffer *buf = NULL;
- struct cifs_open_info_data data = {};
- struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode);
const char *symroot = cifs_sb->ctx->symlinkroot;
+ struct cifs_open_info_data data = {};
+ char sep = CIFS_DIR_SEP(cifs_sb);
+ char *symlink_target = NULL;
+ u16 len, plen, poff, slen;
+ unsigned int sbflags;
+ __le16 *path = NULL;
struct inode *new;
+ char *sym = NULL;
struct kvec iov;
- __le16 *path = NULL;
bool directory;
- char *symlink_target = NULL;
- char *sym = NULL;
- char sep = CIFS_DIR_SEP(cifs_sb);
- u16 len, plen, poff, slen;
int rc = 0;
if (strlen(symname) > REPARSE_SYM_PATH_MAX)
@@ -83,8 +84,8 @@ static int create_native_symlink(const unsigned int xid, struct inode *inode,
.symlink_target = symlink_target,
};
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) &&
- symroot && symname[0] == '/') {
+ sbflags = cifs_sb_flags(cifs_sb);
+ if (!(sbflags & CIFS_MOUNT_POSIX_PATHS) && symroot && symname[0] == '/') {
/*
* This is a request to create an absolute symlink on the server
* which does not support POSIX paths, and expects symlink in
@@ -164,7 +165,7 @@ static int create_native_symlink(const unsigned int xid, struct inode *inode,
* mask these characters in NT object prefix by '_' and then change
* them back.
*/
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) && symname[0] == '/')
+ if (!(sbflags & CIFS_MOUNT_POSIX_PATHS) && symname[0] == '/')
sym[0] = sym[1] = sym[2] = sym[5] = '_';
path = cifs_convert_path_to_utf16(sym, cifs_sb);
@@ -173,7 +174,7 @@ static int create_native_symlink(const unsigned int xid, struct inode *inode,
goto out;
}
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) && symname[0] == '/') {
+ if (!(sbflags & CIFS_MOUNT_POSIX_PATHS) && symname[0] == '/') {
sym[0] = '\\';
sym[1] = sym[2] = '?';
sym[5] = ':';
@@ -197,7 +198,7 @@ static int create_native_symlink(const unsigned int xid, struct inode *inode,
slen = 2 * UniStrnlen((wchar_t *)path, REPARSE_SYM_PATH_MAX);
poff = 0;
plen = slen;
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) && symname[0] == '/') {
+ if (!(sbflags & CIFS_MOUNT_POSIX_PATHS) && symname[0] == '/') {
/*
* For absolute NT symlinks skip leading "\\??\\" in PrintName as
* PrintName is user visible location in DOS/Win32 format (not in NT format).
@@ -824,7 +825,7 @@ int smb2_parse_native_symlink(char **target, const char *buf, unsigned int len,
goto out;
}
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) &&
+ if (!(cifs_sb_flags(cifs_sb) & CIFS_MOUNT_POSIX_PATHS) &&
symroot && !relative) {
/*
* This is an absolute symlink from the server which does not
diff --git a/fs/smb/client/reparse.h b/fs/smb/client/reparse.h
index 570b0d25aeba..0164dc47bdfd 100644
--- a/fs/smb/client/reparse.h
+++ b/fs/smb/client/reparse.h
@@ -33,7 +33,7 @@ static inline kuid_t wsl_make_kuid(struct cifs_sb_info *cifs_sb,
{
u32 uid = le32_to_cpu(*(__le32 *)ptr);
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)
+ if (cifs_sb_flags(cifs_sb) & CIFS_MOUNT_OVERR_UID)
return cifs_sb->ctx->linux_uid;
return make_kuid(current_user_ns(), uid);
}
@@ -43,7 +43,7 @@ static inline kgid_t wsl_make_kgid(struct cifs_sb_info *cifs_sb,
{
u32 gid = le32_to_cpu(*(__le32 *)ptr);
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)
+ if (cifs_sb_flags(cifs_sb) & CIFS_MOUNT_OVERR_GID)
return cifs_sb->ctx->linux_gid;
return make_kgid(current_user_ns(), gid);
}
diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c
index aed49aaef8c4..9643eca0cb70 100644
--- a/fs/smb/client/smb1ops.c
+++ b/fs/smb/client/smb1ops.c
@@ -49,6 +49,7 @@ void reset_cifs_unix_caps(unsigned int xid, struct cifs_tcon *tcon,
if (!CIFSSMBQFSUnixInfo(xid, tcon)) {
__u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
+ unsigned int sbflags;
cifs_dbg(FYI, "unix caps which server supports %lld\n", cap);
/*
@@ -75,14 +76,16 @@ void reset_cifs_unix_caps(unsigned int xid, struct cifs_tcon *tcon,
if (cap & CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP)
cifs_dbg(VFS, "per-share encryption not supported yet\n");
+ if (cifs_sb)
+ sbflags = cifs_sb_flags(cifs_sb);
+
cap &= CIFS_UNIX_CAP_MASK;
if (ctx && ctx->no_psx_acl)
cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
else if (CIFS_UNIX_POSIX_ACL_CAP & cap) {
cifs_dbg(FYI, "negotiated posix acl support\n");
if (cifs_sb)
- cifs_sb->mnt_cifs_flags |=
- CIFS_MOUNT_POSIXACL;
+ sbflags |= CIFS_MOUNT_POSIXACL;
}
if (ctx && ctx->posix_paths == 0)
@@ -90,10 +93,12 @@ void reset_cifs_unix_caps(unsigned int xid, struct cifs_tcon *tcon,
else if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
cifs_dbg(FYI, "negotiate posix pathnames\n");
if (cifs_sb)
- cifs_sb->mnt_cifs_flags |=
- CIFS_MOUNT_POSIX_PATHS;
+ sbflags |= CIFS_MOUNT_POSIX_PATHS;
}
+ if (cifs_sb)
+ atomic_set(&cifs_sb->mnt_cifs_flags, sbflags);
+
cifs_dbg(FYI, "Negotiate caps 0x%x\n", (int)cap);
#ifdef CONFIG_CIFS_DEBUG2
if (cap & CIFS_UNIX_FCNTL_CAP)
@@ -1147,7 +1152,7 @@ static int cifs_oplock_response(struct cifs_tcon *tcon, __u64 persistent_fid,
__u64 volatile_fid, __u16 net_fid,
struct cifsInodeInfo *cinode, unsigned int oplock)
{
- unsigned int sbflags = CIFS_SB(cinode->netfs.inode.i_sb)->mnt_cifs_flags;
+ unsigned int sbflags = cifs_sb_flags(CIFS_SB(cinode));
__u8 op;
op = !!((oplock & CIFS_CACHE_READ_FLG) || (sbflags & CIFS_MOUNT_RO_CACHE));
@@ -1282,7 +1287,8 @@ cifs_make_node(unsigned int xid, struct inode *inode,
struct dentry *dentry, struct cifs_tcon *tcon,
const char *full_path, umode_t mode, dev_t dev)
{
- struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode);
+ unsigned int sbflags = cifs_sb_flags(cifs_sb);
struct inode *newinode = NULL;
int rc;
@@ -1298,7 +1304,7 @@ cifs_make_node(unsigned int xid, struct inode *inode,
.mtime = NO_CHANGE_64,
.device = dev,
};
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
+ if (sbflags & CIFS_MOUNT_SET_UID) {
args.uid = current_fsuid();
args.gid = current_fsgid();
} else {
@@ -1317,7 +1323,7 @@ cifs_make_node(unsigned int xid, struct inode *inode,
if (rc == 0)
d_instantiate(dentry, newinode);
return rc;
- } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
+ } else if (sbflags & CIFS_MOUNT_UNX_EMUL) {
/*
* Check if mounted with mount parm 'sfu' mount parm.
* SFU emulation should work with all servers
diff --git a/fs/smb/client/smb2file.c b/fs/smb/client/smb2file.c
index 1ab41de2b634..ed651c946251 100644
--- a/fs/smb/client/smb2file.c
+++ b/fs/smb/client/smb2file.c
@@ -72,7 +72,7 @@ int smb2_fix_symlink_target_type(char **target, bool directory, struct cifs_sb_i
* POSIX server does not distinguish between symlinks to file and
* symlink directory. So nothing is needed to fix on the client side.
*/
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
+ if (cifs_sb_flags(cifs_sb) & CIFS_MOUNT_POSIX_PATHS)
return 0;
if (!*target)
diff --git a/fs/smb/client/smb2misc.c b/fs/smb/client/smb2misc.c
index e19674d9b92b..973fce3c959c 100644
--- a/fs/smb/client/smb2misc.c
+++ b/fs/smb/client/smb2misc.c
@@ -455,17 +455,8 @@ calc_size_exit:
__le16 *
cifs_convert_path_to_utf16(const char *from, struct cifs_sb_info *cifs_sb)
{
- int len;
const char *start_of_path;
- __le16 *to;
- int map_type;
-
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SFM_CHR)
- map_type = SFM_MAP_UNI_RSVD;
- else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR)
- map_type = SFU_MAP_UNI_RSVD;
- else
- map_type = NO_MAP_UNI_RSVD;
+ int len;
/* Windows doesn't allow paths beginning with \ */
if (from[0] == '\\')
@@ -479,14 +470,13 @@ cifs_convert_path_to_utf16(const char *from, struct cifs_sb_info *cifs_sb)
} else
start_of_path = from;
- to = cifs_strndup_to_utf16(start_of_path, PATH_MAX, &len,
- cifs_sb->local_nls, map_type);
- return to;
+ return cifs_strndup_to_utf16(start_of_path, PATH_MAX, &len,
+ cifs_sb->local_nls, cifs_remap(cifs_sb));
}
__le32 smb2_get_lease_state(struct cifsInodeInfo *cinode, unsigned int oplock)
{
- unsigned int sbflags = CIFS_SB(cinode->netfs.inode.i_sb)->mnt_cifs_flags;
+ unsigned int sbflags = cifs_sb_flags(CIFS_SB(cinode));
__le32 lease = 0;
if ((oplock & CIFS_CACHE_WRITE_FLG) || (sbflags & CIFS_MOUNT_RW_CACHE))
diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
index fea9a35caa57..7f2d3459cbf9 100644
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -986,7 +986,7 @@ smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon,
rc = -EREMOTE;
}
if (rc == -EREMOTE && IS_ENABLED(CONFIG_CIFS_DFS_UPCALL) &&
- (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS))
+ (cifs_sb_flags(cifs_sb) & CIFS_MOUNT_NO_DFS))
rc = -EOPNOTSUPP;
goto out;
}
@@ -2691,7 +2691,7 @@ static int smb2_oplock_response(struct cifs_tcon *tcon, __u64 persistent_fid,
__u64 volatile_fid, __u16 net_fid,
struct cifsInodeInfo *cinode, unsigned int oplock)
{
- unsigned int sbflags = CIFS_SB(cinode->netfs.inode.i_sb)->mnt_cifs_flags;
+ unsigned int sbflags = cifs_sb_flags(CIFS_SB(cinode));
__u8 op;
if (tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_LEASING)
@@ -5332,7 +5332,7 @@ static int smb2_make_node(unsigned int xid, struct inode *inode,
struct dentry *dentry, struct cifs_tcon *tcon,
const char *full_path, umode_t mode, dev_t dev)
{
- struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+ unsigned int sbflags = cifs_sb_flags(CIFS_SB(inode));
int rc = -EOPNOTSUPP;
/*
@@ -5341,7 +5341,7 @@ static int smb2_make_node(unsigned int xid, struct inode *inode,
* supports block and char device, socket & fifo,
* and was used by default in earlier versions of Windows
*/
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
+ if (sbflags & CIFS_MOUNT_UNX_EMUL) {
rc = cifs_sfu_make_node(xid, inode, dentry, tcon,
full_path, mode, dev);
} else if (CIFS_REPARSE_SUPPORT(tcon)) {
diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
index ef655acf673d..04e361ed2356 100644
--- a/fs/smb/client/smb2pdu.c
+++ b/fs/smb/client/smb2pdu.c
@@ -1714,19 +1714,17 @@ SMB2_auth_kerberos(struct SMB2_sess_data *sess_data)
is_binding = (ses->ses_status == SES_GOOD);
spin_unlock(&ses->ses_lock);
- /* keep session key if binding */
- if (!is_binding) {
- kfree_sensitive(ses->auth_key.response);
- ses->auth_key.response = kmemdup(msg->data, msg->sesskey_len,
- GFP_KERNEL);
- if (!ses->auth_key.response) {
- cifs_dbg(VFS, "Kerberos can't allocate (%u bytes) memory\n",
- msg->sesskey_len);
- rc = -ENOMEM;
- goto out_put_spnego_key;
- }
- ses->auth_key.len = msg->sesskey_len;
+ kfree_sensitive(ses->auth_key.response);
+ ses->auth_key.response = kmemdup(msg->data,
+ msg->sesskey_len,
+ GFP_KERNEL);
+ if (!ses->auth_key.response) {
+ cifs_dbg(VFS, "%s: can't allocate (%u bytes) memory\n",
+ __func__, msg->sesskey_len);
+ rc = -ENOMEM;
+ goto out_put_spnego_key;
}
+ ses->auth_key.len = msg->sesskey_len;
sess_data->iov[1].iov_base = msg->data + msg->sesskey_len;
sess_data->iov[1].iov_len = msg->secblob_len;
@@ -3182,22 +3180,19 @@ SMB2_open_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server,
}
if ((oparms->disposition != FILE_OPEN) && (oparms->cifs_sb)) {
+ unsigned int sbflags = cifs_sb_flags(oparms->cifs_sb);
bool set_mode;
bool set_owner;
- if ((oparms->cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID) &&
- (oparms->mode != ACL_NO_MODE))
+ if ((sbflags & CIFS_MOUNT_MODE_FROM_SID) &&
+ oparms->mode != ACL_NO_MODE) {
set_mode = true;
- else {
+ } else {
set_mode = false;
oparms->mode = ACL_NO_MODE;
}
- if (oparms->cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UID_FROM_ACL)
- set_owner = true;
- else
- set_owner = false;
-
+ set_owner = sbflags & CIFS_MOUNT_UID_FROM_ACL;
if (set_owner | set_mode) {
cifs_dbg(FYI, "add sd with mode 0x%x\n", oparms->mode);
rc = add_sd_context(iov, &n_iov, oparms->mode, set_owner);
diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c
index 75697f6d2566..05f8099047e1 100644
--- a/fs/smb/client/transport.c
+++ b/fs/smb/client/transport.c
@@ -807,16 +807,21 @@ cifs_cancelled_callback(struct TCP_Server_Info *server, struct mid_q_entry *mid)
}
/*
- * Return a channel (master if none) of @ses that can be used to send
- * regular requests.
+ * cifs_pick_channel - pick an eligible channel for network operations
*
- * If we are currently binding a new channel (negprot/sess.setup),
- * return the new incomplete channel.
+ * @ses: session reference
+ *
+ * Select an eligible channel (not terminating and not marked as needing
+ * reconnect), preferring the least loaded one. If no eligible channel is
+ * found, fall back to the primary channel (index 0).
+ *
+ * Return: TCP_Server_Info pointer for the chosen channel, or NULL if @ses is
+ * NULL.
*/
struct TCP_Server_Info *cifs_pick_channel(struct cifs_ses *ses)
{
uint index = 0;
- unsigned int min_in_flight = UINT_MAX, max_in_flight = 0;
+ unsigned int min_in_flight = UINT_MAX;
struct TCP_Server_Info *server = NULL;
int i, start, cur;
@@ -846,14 +851,8 @@ struct TCP_Server_Info *cifs_pick_channel(struct cifs_ses *ses)
min_in_flight = server->in_flight;
index = cur;
}
- if (server->in_flight > max_in_flight)
- max_in_flight = server->in_flight;
}
- /* if all channels are equally loaded, fall back to round-robin */
- if (min_in_flight == max_in_flight)
- index = (uint)start % ses->chan_count;
-
server = ses->chans[index].server;
spin_unlock(&ses->chan_lock);
diff --git a/fs/smb/client/xattr.c b/fs/smb/client/xattr.c
index e1a7d9a10a53..23227f2f9428 100644
--- a/fs/smb/client/xattr.c
+++ b/fs/smb/client/xattr.c
@@ -149,7 +149,7 @@ static int cifs_xattr_set(const struct xattr_handler *handler,
break;
}
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
+ if (cifs_sb_flags(cifs_sb) & CIFS_MOUNT_NO_XATTR)
goto out;
if (pTcon->ses->server->ops->set_EA) {
@@ -309,7 +309,7 @@ static int cifs_xattr_get(const struct xattr_handler *handler,
break;
}
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
+ if (cifs_sb_flags(cifs_sb) & CIFS_MOUNT_NO_XATTR)
goto out;
if (pTcon->ses->server->ops->query_all_EAs)
@@ -398,7 +398,7 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size)
if (unlikely(cifs_forced_shutdown(cifs_sb)))
return smb_EIO(smb_eio_trace_forced_shutdown);
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
+ if (cifs_sb_flags(cifs_sb) & CIFS_MOUNT_NO_XATTR)
return -EOPNOTSUPP;
tlink = cifs_sb_tlink(cifs_sb);
diff --git a/fs/smb/server/Kconfig b/fs/smb/server/Kconfig
index 2775162c535c..12594879cb64 100644
--- a/fs/smb/server/Kconfig
+++ b/fs/smb/server/Kconfig
@@ -13,6 +13,7 @@ config SMB_SERVER
select CRYPTO_LIB_MD5
select CRYPTO_LIB_SHA256
select CRYPTO_LIB_SHA512
+ select CRYPTO_LIB_UTILS
select CRYPTO_CMAC
select CRYPTO_AEAD2
select CRYPTO_CCM
diff --git a/fs/smb/server/auth.c b/fs/smb/server/auth.c
index 580c4d303dc3..5fe8c667c6b1 100644
--- a/fs/smb/server/auth.c
+++ b/fs/smb/server/auth.c
@@ -15,6 +15,7 @@
#include <crypto/aead.h>
#include <crypto/md5.h>
#include <crypto/sha2.h>
+#include <crypto/utils.h>
#include <linux/random.h>
#include <linux/scatterlist.h>
@@ -165,7 +166,8 @@ int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess,
ntlmv2_rsp, CIFS_HMAC_MD5_HASH_SIZE,
sess->sess_key);
- if (memcmp(ntlmv2->ntlmv2_hash, ntlmv2_rsp, CIFS_HMAC_MD5_HASH_SIZE) != 0)
+ if (crypto_memneq(ntlmv2->ntlmv2_hash, ntlmv2_rsp,
+ CIFS_HMAC_MD5_HASH_SIZE))
return -EINVAL;
return 0;
}
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index 95901a78951c..743c629fe7ec 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -4,6 +4,7 @@
* Copyright (C) 2018 Samsung Electronics Co., Ltd.
*/
+#include <crypto/utils.h>
#include <linux/inetdevice.h>
#include <net/addrconf.h>
#include <linux/syscalls.h>
@@ -8880,7 +8881,7 @@ int smb2_check_sign_req(struct ksmbd_work *work)
ksmbd_sign_smb2_pdu(work->conn, work->sess->sess_key, iov, 1,
signature);
- if (memcmp(signature, signature_req, SMB2_SIGNATURE_SIZE)) {
+ if (crypto_memneq(signature, signature_req, SMB2_SIGNATURE_SIZE)) {
pr_err("bad smb2 signature\n");
return 0;
}
@@ -8968,7 +8969,7 @@ int smb3_check_sign_req(struct ksmbd_work *work)
if (ksmbd_sign_smb3_pdu(conn, signing_key, iov, 1, signature))
return 0;
- if (memcmp(signature, signature_req, SMB2_SIGNATURE_SIZE)) {
+ if (crypto_memneq(signature, signature_req, SMB2_SIGNATURE_SIZE)) {
pr_err("bad smb2 signature\n");
return 0;
}
diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c
index 7c53b78b818e..188572491d53 100644
--- a/fs/smb/server/transport_rdma.c
+++ b/fs/smb/server/transport_rdma.c
@@ -2540,9 +2540,9 @@ static int smb_direct_prepare(struct ksmbd_transport *t)
goto put;
req = (struct smbdirect_negotiate_req *)recvmsg->packet;
- sp->max_recv_size = min_t(int, sp->max_recv_size,
+ sp->max_recv_size = min_t(u32, sp->max_recv_size,
le32_to_cpu(req->preferred_send_size));
- sp->max_send_size = min_t(int, sp->max_send_size,
+ sp->max_send_size = min_t(u32, sp->max_send_size,
le32_to_cpu(req->max_receive_size));
sp->max_fragmented_send_size =
le32_to_cpu(req->max_fragmented_size);
diff --git a/fs/squashfs/cache.c b/fs/squashfs/cache.c
index 8e958db5f786..67abd4dff222 100644
--- a/fs/squashfs/cache.c
+++ b/fs/squashfs/cache.c
@@ -344,6 +344,9 @@ int squashfs_read_metadata(struct super_block *sb, void *buffer,
if (unlikely(length < 0))
return -EIO;
+ if (unlikely(*offset < 0 || *offset >= SQUASHFS_METADATA_SIZE))
+ return -EIO;
+
while (length) {
entry = squashfs_cache_get(sb, msblk->block_cache, *block, 0);
if (entry->error) {
diff --git a/fs/xfs/libxfs/xfs_ag.c b/fs/xfs/libxfs/xfs_ag.c
index 9c6765cc2d44..bd8fbb40b49e 100644
--- a/fs/xfs/libxfs/xfs_ag.c
+++ b/fs/xfs/libxfs/xfs_ag.c
@@ -872,6 +872,34 @@ resv_err:
return err2;
}
+void
+xfs_growfs_compute_deltas(
+ struct xfs_mount *mp,
+ xfs_rfsblock_t nb,
+ int64_t *deltap,
+ xfs_agnumber_t *nagcountp)
+{
+ xfs_rfsblock_t nb_div, nb_mod;
+ int64_t delta;
+ xfs_agnumber_t nagcount;
+
+ nb_div = nb;
+ nb_mod = do_div(nb_div, mp->m_sb.sb_agblocks);
+ if (nb_mod && nb_mod >= XFS_MIN_AG_BLOCKS)
+ nb_div++;
+ else if (nb_mod)
+ nb = nb_div * mp->m_sb.sb_agblocks;
+
+ if (nb_div > XFS_MAX_AGNUMBER + 1) {
+ nb_div = XFS_MAX_AGNUMBER + 1;
+ nb = nb_div * mp->m_sb.sb_agblocks;
+ }
+ nagcount = nb_div;
+ delta = nb - mp->m_sb.sb_dblocks;
+ *deltap = delta;
+ *nagcountp = nagcount;
+}
+
/*
* Extent the AG indicated by the @id by the length passed in
*/
diff --git a/fs/xfs/libxfs/xfs_ag.h b/fs/xfs/libxfs/xfs_ag.h
index 1f24cfa27321..3cd4790768ff 100644
--- a/fs/xfs/libxfs/xfs_ag.h
+++ b/fs/xfs/libxfs/xfs_ag.h
@@ -331,6 +331,9 @@ struct aghdr_init_data {
int xfs_ag_init_headers(struct xfs_mount *mp, struct aghdr_init_data *id);
int xfs_ag_shrink_space(struct xfs_perag *pag, struct xfs_trans **tpp,
xfs_extlen_t delta);
+void
+xfs_growfs_compute_deltas(struct xfs_mount *mp, xfs_rfsblock_t nb,
+ int64_t *deltap, xfs_agnumber_t *nagcountp);
int xfs_ag_extend_space(struct xfs_perag *pag, struct xfs_trans *tp,
xfs_extlen_t len);
int xfs_ag_get_geometry(struct xfs_perag *pag, struct xfs_ag_geometry *ageo);
diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c
index a017016e9075..3794e5412eba 100644
--- a/fs/xfs/libxfs/xfs_inode_buf.c
+++ b/fs/xfs/libxfs/xfs_inode_buf.c
@@ -268,6 +268,10 @@ xfs_inode_from_disk(
}
if (xfs_is_reflink_inode(ip))
xfs_ifork_init_cow(ip);
+ if (xfs_is_metadir_inode(ip)) {
+ XFS_STATS_DEC(ip->i_mount, xs_inodes_active);
+ XFS_STATS_INC(ip->i_mount, xs_inodes_meta);
+ }
return 0;
out_destroy_data_fork:
diff --git a/fs/xfs/libxfs/xfs_metafile.c b/fs/xfs/libxfs/xfs_metafile.c
index cf239f862212..71f004e9dc64 100644
--- a/fs/xfs/libxfs/xfs_metafile.c
+++ b/fs/xfs/libxfs/xfs_metafile.c
@@ -61,6 +61,9 @@ xfs_metafile_set_iflag(
ip->i_diflags2 |= XFS_DIFLAG2_METADATA;
ip->i_metatype = metafile_type;
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
+
+ XFS_STATS_DEC(ip->i_mount, xs_inodes_active);
+ XFS_STATS_INC(ip->i_mount, xs_inodes_meta);
}
/* Clear the metadata directory inode flag. */
@@ -74,6 +77,8 @@ xfs_metafile_clear_iflag(
ip->i_diflags2 &= ~XFS_DIFLAG2_METADATA;
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
+ XFS_STATS_INC(ip->i_mount, xs_inodes_active);
+ XFS_STATS_DEC(ip->i_mount, xs_inodes_meta);
}
/*
diff --git a/fs/xfs/libxfs/xfs_ondisk.h b/fs/xfs/libxfs/xfs_ondisk.h
index 2e9715cc1641..23cde1248f01 100644
--- a/fs/xfs/libxfs/xfs_ondisk.h
+++ b/fs/xfs/libxfs/xfs_ondisk.h
@@ -73,7 +73,7 @@ xfs_check_ondisk_structs(void)
XFS_CHECK_STRUCT_SIZE(struct xfs_dir3_free_hdr, 64);
XFS_CHECK_STRUCT_SIZE(struct xfs_dir3_leaf, 64);
XFS_CHECK_STRUCT_SIZE(struct xfs_dir3_leaf_hdr, 64);
- XFS_CHECK_STRUCT_SIZE(struct xfs_attr_leaf_entry, 8);
+ XFS_CHECK_STRUCT_SIZE(struct xfs_attr_leaf_entry, 8);
XFS_CHECK_STRUCT_SIZE(struct xfs_attr_leaf_hdr, 32);
XFS_CHECK_STRUCT_SIZE(struct xfs_attr_leaf_map, 4);
XFS_CHECK_STRUCT_SIZE(struct xfs_attr_leaf_name_local, 4);
@@ -116,7 +116,7 @@ xfs_check_ondisk_structs(void)
XFS_CHECK_STRUCT_SIZE(struct xfs_da_intnode, 16);
XFS_CHECK_STRUCT_SIZE(struct xfs_da_node_entry, 8);
XFS_CHECK_STRUCT_SIZE(struct xfs_da_node_hdr, 16);
- XFS_CHECK_STRUCT_SIZE(struct xfs_dir2_data_free, 4);
+ XFS_CHECK_STRUCT_SIZE(struct xfs_dir2_data_free, 4);
XFS_CHECK_STRUCT_SIZE(struct xfs_dir2_data_hdr, 16);
XFS_CHECK_OFFSET(struct xfs_dir2_data_unused, freetag, 0);
XFS_CHECK_OFFSET(struct xfs_dir2_data_unused, length, 2);
@@ -136,16 +136,7 @@ xfs_check_ondisk_structs(void)
/* ondisk dir/attr structures from xfs/122 */
XFS_CHECK_STRUCT_SIZE(struct xfs_attr_sf_entry, 3);
XFS_CHECK_STRUCT_SIZE(struct xfs_dir2_data_free, 4);
- XFS_CHECK_STRUCT_SIZE(struct xfs_dir2_data_hdr, 16);
XFS_CHECK_STRUCT_SIZE(struct xfs_dir2_data_unused, 6);
- XFS_CHECK_STRUCT_SIZE(struct xfs_dir2_free, 16);
- XFS_CHECK_STRUCT_SIZE(struct xfs_dir2_free_hdr, 16);
- XFS_CHECK_STRUCT_SIZE(struct xfs_dir2_leaf, 16);
- XFS_CHECK_STRUCT_SIZE(struct xfs_dir2_leaf_entry, 8);
- XFS_CHECK_STRUCT_SIZE(struct xfs_dir2_leaf_hdr, 16);
- XFS_CHECK_STRUCT_SIZE(struct xfs_dir2_leaf_tail, 4);
- XFS_CHECK_STRUCT_SIZE(struct xfs_dir2_sf_entry, 3);
- XFS_CHECK_STRUCT_SIZE(struct xfs_dir2_sf_hdr, 10);
/* log structures */
XFS_CHECK_STRUCT_SIZE(struct xfs_buf_log_format, 88);
@@ -217,11 +208,6 @@ xfs_check_ondisk_structs(void)
XFS_CHECK_OFFSET(struct xfs_dir3_free, hdr.hdr.magic, 0);
XFS_CHECK_OFFSET(struct xfs_attr3_leafblock, hdr.info.hdr, 0);
- XFS_CHECK_STRUCT_SIZE(struct xfs_bulkstat, 192);
- XFS_CHECK_STRUCT_SIZE(struct xfs_inumbers, 24);
- XFS_CHECK_STRUCT_SIZE(struct xfs_bulkstat_req, 64);
- XFS_CHECK_STRUCT_SIZE(struct xfs_inumbers_req, 64);
-
/*
* Make sure the incore inode timestamp range corresponds to hand
* converted values based on the ondisk format specification.
@@ -301,6 +287,40 @@ xfs_check_ondisk_structs(void)
XFS_CHECK_SB_OFFSET(sb_pad, 281);
XFS_CHECK_SB_OFFSET(sb_rtstart, 288);
XFS_CHECK_SB_OFFSET(sb_rtreserved, 296);
+
+ /*
+ * ioctl UABI
+ *
+ * Due to different padding/alignment requirements across
+ * different architectures, some structures are ommited from
+ * the size checks. In addition, structures with architecture
+ * dependent size fields are also ommited (e.g. __kernel_long_t).
+ */
+ XFS_CHECK_STRUCT_SIZE(struct xfs_bulkstat, 192);
+ XFS_CHECK_STRUCT_SIZE(struct xfs_inumbers, 24);
+ XFS_CHECK_STRUCT_SIZE(struct xfs_bulkstat_req, 64);
+ XFS_CHECK_STRUCT_SIZE(struct xfs_inumbers_req, 64);
+ XFS_CHECK_STRUCT_SIZE(struct dioattr, 12);
+ XFS_CHECK_STRUCT_SIZE(struct getbmap, 32);
+ XFS_CHECK_STRUCT_SIZE(struct getbmapx, 48);
+ XFS_CHECK_STRUCT_SIZE(struct xfs_attrlist_cursor, 16);
+ XFS_CHECK_STRUCT_SIZE(struct xfs_attrlist, 8);
+ XFS_CHECK_STRUCT_SIZE(struct xfs_attrlist, 8);
+ XFS_CHECK_STRUCT_SIZE(struct xfs_attrlist_ent, 4);
+ XFS_CHECK_STRUCT_SIZE(struct xfs_ag_geometry, 128);
+ XFS_CHECK_STRUCT_SIZE(struct xfs_rtgroup_geometry, 128);
+ XFS_CHECK_STRUCT_SIZE(struct xfs_error_injection, 8);
+ XFS_CHECK_STRUCT_SIZE(struct xfs_fsop_geom, 256);
+ XFS_CHECK_STRUCT_SIZE(struct xfs_fsop_geom_v4, 112);
+ XFS_CHECK_STRUCT_SIZE(struct xfs_fsop_counts, 32);
+ XFS_CHECK_STRUCT_SIZE(struct xfs_fsop_resblks, 16);
+ XFS_CHECK_STRUCT_SIZE(struct xfs_growfs_log, 8);
+ XFS_CHECK_STRUCT_SIZE(struct xfs_bulk_ireq, 64);
+ XFS_CHECK_STRUCT_SIZE(struct xfs_fs_eofblocks, 128);
+ XFS_CHECK_STRUCT_SIZE(struct xfs_fsid, 8);
+ XFS_CHECK_STRUCT_SIZE(struct xfs_scrub_metadata, 64);
+ XFS_CHECK_STRUCT_SIZE(struct xfs_scrub_vec, 16);
+ XFS_CHECK_STRUCT_SIZE(struct xfs_scrub_vec_head, 40);
}
#endif /* __XFS_ONDISK_H */
diff --git a/fs/xfs/libxfs/xfs_sb.c b/fs/xfs/libxfs/xfs_sb.c
index 38d16fe1f6d8..47322adb7690 100644
--- a/fs/xfs/libxfs/xfs_sb.c
+++ b/fs/xfs/libxfs/xfs_sb.c
@@ -1347,6 +1347,9 @@ xfs_log_sb(
* feature was introduced. This counter can go negative due to the way
* we handle nearly-lockless reservations, so we must use the _positive
* variant here to avoid writing out nonsense frextents.
+ *
+ * RT groups are only supported on v5 file systems, which always
+ * have lazy SB counters.
*/
if (xfs_has_rtgroups(mp) && !xfs_has_zoned(mp)) {
mp->m_sb.sb_frextents =
diff --git a/fs/xfs/scrub/dir_repair.c b/fs/xfs/scrub/dir_repair.c
index 9dc55c918c78..23b80c54aa60 100644
--- a/fs/xfs/scrub/dir_repair.c
+++ b/fs/xfs/scrub/dir_repair.c
@@ -177,7 +177,7 @@ xrep_dir_teardown(
rd->dir_names = NULL;
if (rd->dir_entries)
xfarray_destroy(rd->dir_entries);
- rd->dir_names = NULL;
+ rd->dir_entries = NULL;
}
/* Set up for a directory repair. */
diff --git a/fs/xfs/scrub/orphanage.c b/fs/xfs/scrub/orphanage.c
index 52a108f6d5f4..33c6db6b4498 100644
--- a/fs/xfs/scrub/orphanage.c
+++ b/fs/xfs/scrub/orphanage.c
@@ -442,6 +442,11 @@ xrep_adoption_check_dcache(
return 0;
d_child = try_lookup_noperm(&qname, d_orphanage);
+ if (IS_ERR(d_child)) {
+ dput(d_orphanage);
+ return PTR_ERR(d_child);
+ }
+
if (d_child) {
trace_xrep_adoption_check_child(sc->mp, d_child);
@@ -479,7 +484,7 @@ xrep_adoption_zap_dcache(
return;
d_child = try_lookup_noperm(&qname, d_orphanage);
- while (d_child != NULL) {
+ while (!IS_ERR_OR_NULL(d_child)) {
trace_xrep_adoption_invalidate_child(sc->mp, d_child);
ASSERT(d_is_negative(d_child));
diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c
index 17255c41786b..8d64d904d73c 100644
--- a/fs/xfs/xfs_fsops.c
+++ b/fs/xfs/xfs_fsops.c
@@ -95,18 +95,17 @@ xfs_growfs_data_private(
struct xfs_growfs_data *in) /* growfs data input struct */
{
xfs_agnumber_t oagcount = mp->m_sb.sb_agcount;
+ xfs_rfsblock_t nb = in->newblocks;
struct xfs_buf *bp;
int error;
xfs_agnumber_t nagcount;
xfs_agnumber_t nagimax = 0;
- xfs_rfsblock_t nb, nb_div, nb_mod;
int64_t delta;
bool lastag_extended = false;
struct xfs_trans *tp;
struct aghdr_init_data id = {};
struct xfs_perag *last_pag;
- nb = in->newblocks;
error = xfs_sb_validate_fsb_count(&mp->m_sb, nb);
if (error)
return error;
@@ -125,20 +124,8 @@ xfs_growfs_data_private(
mp->m_sb.sb_rextsize);
if (error)
return error;
+ xfs_growfs_compute_deltas(mp, nb, &delta, &nagcount);
- nb_div = nb;
- nb_mod = do_div(nb_div, mp->m_sb.sb_agblocks);
- if (nb_mod && nb_mod >= XFS_MIN_AG_BLOCKS)
- nb_div++;
- else if (nb_mod)
- nb = nb_div * mp->m_sb.sb_agblocks;
-
- if (nb_div > XFS_MAX_AGNUMBER + 1) {
- nb_div = XFS_MAX_AGNUMBER + 1;
- nb = nb_div * mp->m_sb.sb_agblocks;
- }
- nagcount = nb_div;
- delta = nb - mp->m_sb.sb_dblocks;
/*
* Reject filesystems with a single AG because they are not
* supported, and reject a shrink operation that would cause a
diff --git a/fs/xfs/xfs_health.c b/fs/xfs/xfs_health.c
index 169123772cb3..239b843e83d4 100644
--- a/fs/xfs/xfs_health.c
+++ b/fs/xfs/xfs_health.c
@@ -314,6 +314,22 @@ xfs_rgno_mark_sick(
xfs_rtgroup_put(rtg);
}
+static inline void xfs_inode_report_fserror(struct xfs_inode *ip)
+{
+ /*
+ * Do not report inodes being constructed or freed, or metadata inodes,
+ * to fsnotify.
+ */
+ if (xfs_iflags_test(ip, XFS_INEW | XFS_IRECLAIM) ||
+ xfs_is_internal_inode(ip)) {
+ fserror_report_metadata(ip->i_mount->m_super, -EFSCORRUPTED,
+ GFP_NOFS);
+ return;
+ }
+
+ fserror_report_file_metadata(VFS_I(ip), -EFSCORRUPTED, GFP_NOFS);
+}
+
/* Mark the unhealthy parts of an inode. */
void
xfs_inode_mark_sick(
@@ -339,7 +355,7 @@ xfs_inode_mark_sick(
inode_state_clear(VFS_I(ip), I_DONTCACHE);
spin_unlock(&VFS_I(ip)->i_lock);
- fserror_report_file_metadata(VFS_I(ip), -EFSCORRUPTED, GFP_NOFS);
+ xfs_inode_report_fserror(ip);
if (mask)
xfs_healthmon_report_inode(ip, XFS_HEALTHMON_SICK, old_mask,
mask);
@@ -371,7 +387,7 @@ xfs_inode_mark_corrupt(
inode_state_clear(VFS_I(ip), I_DONTCACHE);
spin_unlock(&VFS_I(ip)->i_lock);
- fserror_report_file_metadata(VFS_I(ip), -EFSCORRUPTED, GFP_NOFS);
+ xfs_inode_report_fserror(ip);
if (mask)
xfs_healthmon_report_inode(ip, XFS_HEALTHMON_CORRUPT, old_mask,
mask);
diff --git a/fs/xfs/xfs_healthmon.c b/fs/xfs/xfs_healthmon.c
index e37c18cec372..4a06d6632f65 100644
--- a/fs/xfs/xfs_healthmon.c
+++ b/fs/xfs/xfs_healthmon.c
@@ -69,7 +69,7 @@ xfs_healthmon_get(
struct xfs_healthmon *hm;
rcu_read_lock();
- hm = mp->m_healthmon;
+ hm = rcu_dereference(mp->m_healthmon);
if (hm && !refcount_inc_not_zero(&hm->ref))
hm = NULL;
rcu_read_unlock();
@@ -110,13 +110,13 @@ xfs_healthmon_attach(
struct xfs_healthmon *hm)
{
spin_lock(&xfs_healthmon_lock);
- if (mp->m_healthmon != NULL) {
+ if (rcu_access_pointer(mp->m_healthmon) != NULL) {
spin_unlock(&xfs_healthmon_lock);
return -EEXIST;
}
refcount_inc(&hm->ref);
- mp->m_healthmon = hm;
+ rcu_assign_pointer(mp->m_healthmon, hm);
hm->mount_cookie = (uintptr_t)mp->m_super;
spin_unlock(&xfs_healthmon_lock);
@@ -128,13 +128,16 @@ STATIC void
xfs_healthmon_detach(
struct xfs_healthmon *hm)
{
+ struct xfs_mount *mp;
+
spin_lock(&xfs_healthmon_lock);
if (hm->mount_cookie == DETACHED_MOUNT_COOKIE) {
spin_unlock(&xfs_healthmon_lock);
return;
}
- XFS_M((struct super_block *)hm->mount_cookie)->m_healthmon = NULL;
+ mp = XFS_M((struct super_block *)hm->mount_cookie);
+ rcu_assign_pointer(mp->m_healthmon, NULL);
hm->mount_cookie = DETACHED_MOUNT_COOKIE;
spin_unlock(&xfs_healthmon_lock);
diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c
index dbaab4ae709f..a7a09e7eec81 100644
--- a/fs/xfs/xfs_icache.c
+++ b/fs/xfs/xfs_icache.c
@@ -106,7 +106,7 @@ xfs_inode_alloc(
mapping_set_folio_min_order(VFS_I(ip)->i_mapping,
M_IGEO(mp)->min_folio_order);
- XFS_STATS_INC(mp, vn_active);
+ XFS_STATS_INC(mp, xs_inodes_active);
ASSERT(atomic_read(&ip->i_pincount) == 0);
ASSERT(ip->i_ino == 0);
@@ -172,7 +172,10 @@ __xfs_inode_free(
/* asserts to verify all state is correct here */
ASSERT(atomic_read(&ip->i_pincount) == 0);
ASSERT(!ip->i_itemp || list_empty(&ip->i_itemp->ili_item.li_bio_list));
- XFS_STATS_DEC(ip->i_mount, vn_active);
+ if (xfs_is_metadir_inode(ip))
+ XFS_STATS_DEC(ip->i_mount, xs_inodes_meta);
+ else
+ XFS_STATS_DEC(ip->i_mount, xs_inodes_active);
call_rcu(&VFS_I(ip)->i_rcu, xfs_inode_free_callback);
}
@@ -636,6 +639,14 @@ xfs_iget_cache_miss(
if (!ip)
return -ENOMEM;
+ /*
+ * Set XFS_INEW as early as possible so that the health code won't pass
+ * the inode to the fserror code if the ondisk inode cannot be loaded.
+ * We're going to free the xfs_inode immediately if that happens, which
+ * would lead to UAF problems.
+ */
+ xfs_iflags_set(ip, XFS_INEW);
+
error = xfs_imap(pag, tp, ip->i_ino, &ip->i_imap, flags);
if (error)
goto out_destroy;
@@ -713,7 +724,6 @@ xfs_iget_cache_miss(
ip->i_udquot = NULL;
ip->i_gdquot = NULL;
ip->i_pdquot = NULL;
- xfs_iflags_set(ip, XFS_INEW);
/* insert the new inode */
spin_lock(&pag->pag_ici_lock);
@@ -2234,7 +2244,7 @@ xfs_inode_mark_reclaimable(
struct xfs_mount *mp = ip->i_mount;
bool need_inactive;
- XFS_STATS_INC(mp, vn_reclaim);
+ XFS_STATS_INC(mp, xs_inode_mark_reclaimable);
/*
* We should never get here with any of the reclaim flags already set.
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
index 61c71128d171..ddd4028be8d6 100644
--- a/fs/xfs/xfs_mount.h
+++ b/fs/xfs/xfs_mount.h
@@ -345,7 +345,7 @@ typedef struct xfs_mount {
struct xfs_hooks m_dir_update_hooks;
/* Private data referring to a health monitor object. */
- struct xfs_healthmon *m_healthmon;
+ struct xfs_healthmon __rcu *m_healthmon;
} xfs_mount_t;
#define M_IGEO(mp) (&(mp)->m_ino_geo)
diff --git a/fs/xfs/xfs_notify_failure.c b/fs/xfs/xfs_notify_failure.c
index 6be19fa1ebe2..64c8afb935c2 100644
--- a/fs/xfs/xfs_notify_failure.c
+++ b/fs/xfs/xfs_notify_failure.c
@@ -304,7 +304,7 @@ xfs_dax_notify_dev_failure(
error = xfs_alloc_read_agf(pag, tp, 0, &agf_bp);
if (error) {
- xfs_perag_put(pag);
+ xfs_perag_rele(pag);
break;
}
@@ -340,7 +340,7 @@ xfs_dax_notify_dev_failure(
if (rtg)
xfs_rtgroup_unlock(rtg, XFS_RTGLOCK_RMAP);
if (error) {
- xfs_group_put(xg);
+ xfs_group_rele(xg);
break;
}
}
diff --git a/fs/xfs/xfs_platform.h b/fs/xfs/xfs_platform.h
index 1e59bf94d1f2..59a33c60e0ca 100644
--- a/fs/xfs/xfs_platform.h
+++ b/fs/xfs/xfs_platform.h
@@ -235,6 +235,10 @@ int xfs_rw_bdev(struct block_device *bdev, sector_t sector, unsigned int count,
#ifdef XFS_WARN
+/*
+ * Please note that this ASSERT doesn't kill the kernel. It will if the kernel
+ * has panic_on_warn set.
+ */
#define ASSERT(expr) \
(likely(expr) ? (void)0 : asswarn(NULL, #expr, __FILE__, __LINE__))
@@ -245,6 +249,11 @@ int xfs_rw_bdev(struct block_device *bdev, sector_t sector, unsigned int count,
#endif /* XFS_WARN */
#endif /* DEBUG */
+/*
+ * Use this to catch metadata corruptions that are not caught by block or
+ * structure verifiers. The reason is that the verifiers check corruptions only
+ * within the scope of the object being verified.
+ */
#define XFS_IS_CORRUPT(mp, expr) \
(unlikely(expr) ? xfs_corruption_error(#expr, XFS_ERRLEVEL_LOW, (mp), \
NULL, 0, __FILE__, __LINE__, \
diff --git a/fs/xfs/xfs_rtalloc.c b/fs/xfs/xfs_rtalloc.c
index 90a94a5b6f7e..153f3c378f9f 100644
--- a/fs/xfs/xfs_rtalloc.c
+++ b/fs/xfs/xfs_rtalloc.c
@@ -112,6 +112,10 @@ xfs_rtcopy_summary(
error = xfs_rtget_summary(oargs, log, bbno, &sum);
if (error)
goto out;
+ if (XFS_IS_CORRUPT(oargs->mp, sum < 0)) {
+ error = -EFSCORRUPTED;
+ goto out;
+ }
if (sum == 0)
continue;
error = xfs_rtmodify_summary(oargs, log, bbno, -sum);
@@ -120,7 +124,6 @@ xfs_rtcopy_summary(
error = xfs_rtmodify_summary(nargs, log, bbno, sum);
if (error)
goto out;
- ASSERT(sum > 0);
}
}
error = 0;
@@ -1047,6 +1050,15 @@ xfs_growfs_rt_bmblock(
*/
xfs_trans_resv_calc(mp, &mp->m_resv);
+ /*
+ * Sync sb counters now to reflect the updated values. Lazy counters are
+ * not always updated and in order to avoid inconsistencies between
+ * frextents and rtextents, it is better to sync the counters.
+ */
+
+ if (xfs_has_lazysbcount(mp))
+ xfs_log_sb(args.tp);
+
error = xfs_trans_commit(args.tp);
if (error)
goto out_free;
@@ -1079,17 +1091,27 @@ xfs_last_rtgroup_extents(
}
/*
- * Calculate the last rbmblock currently used.
+ * This will return the bitmap block number (indexed at 0) that will be
+ * extended/modified. There are 2 cases here:
+ * 1. The size of the rtg is such that it is a multiple of
+ * xfs_rtbitmap_rtx_per_rbmblock() i.e, an integral number of bitmap blocks
+ * are completely filled up. In this case, we should return
+ * 1 + (the last used bitmap block number).
+ * 2. The size of the rtg is not an multiple of xfs_rtbitmap_rtx_per_rbmblock().
+ * Here we will return the block number of last used block number. In this
+ * case, we will modify the last used bitmap block to extend the size of the
+ * rtgroup.
*
* This also deals with the case where there were no rtextents before.
*/
static xfs_fileoff_t
-xfs_last_rt_bmblock(
+xfs_last_rt_bmblock_to_extend(
struct xfs_rtgroup *rtg)
{
struct xfs_mount *mp = rtg_mount(rtg);
xfs_rgnumber_t rgno = rtg_rgno(rtg);
xfs_fileoff_t bmbno = 0;
+ unsigned int mod = 0;
ASSERT(!mp->m_sb.sb_rgcount || rgno >= mp->m_sb.sb_rgcount - 1);
@@ -1097,9 +1119,16 @@ xfs_last_rt_bmblock(
xfs_rtxnum_t nrext = xfs_last_rtgroup_extents(mp);
/* Also fill up the previous block if not entirely full. */
- bmbno = xfs_rtbitmap_blockcount_len(mp, nrext);
- if (xfs_rtx_to_rbmword(mp, nrext) != 0)
- bmbno--;
+ /* We are doing a -1 to convert it to a 0 based index */
+ bmbno = xfs_rtbitmap_blockcount_len(mp, nrext) - 1;
+ div_u64_rem(nrext, xfs_rtbitmap_rtx_per_rbmblock(mp), &mod);
+ /*
+ * mod = 0 means that all the current blocks are full. So
+ * return the next block number to be used for the rtgroup
+ * growth.
+ */
+ if (mod == 0)
+ bmbno++;
}
return bmbno;
@@ -1204,7 +1233,8 @@ xfs_growfs_rtg(
goto out_rele;
}
- for (bmbno = xfs_last_rt_bmblock(rtg); bmbno < bmblocks; bmbno++) {
+ for (bmbno = xfs_last_rt_bmblock_to_extend(rtg); bmbno < bmblocks;
+ bmbno++) {
error = xfs_growfs_rt_bmblock(rtg, nrblocks, rextsize, bmbno);
if (error)
goto out_error;
diff --git a/fs/xfs/xfs_stats.c b/fs/xfs/xfs_stats.c
index 017db0361cd8..c13d600732c9 100644
--- a/fs/xfs/xfs_stats.c
+++ b/fs/xfs/xfs_stats.c
@@ -42,7 +42,7 @@ int xfs_stats_format(struct xfsstats __percpu *stats, char *buf)
{ "xstrat", xfsstats_offset(xs_write_calls) },
{ "rw", xfsstats_offset(xs_attr_get) },
{ "attr", xfsstats_offset(xs_iflush_count)},
- { "icluster", xfsstats_offset(vn_active) },
+ { "icluster", xfsstats_offset(xs_inodes_active) },
{ "vnodes", xfsstats_offset(xb_get) },
{ "buf", xfsstats_offset(xs_abtb_2) },
{ "abtb2", xfsstats_offset(xs_abtc_2) },
@@ -59,7 +59,8 @@ int xfs_stats_format(struct xfsstats __percpu *stats, char *buf)
{ "rtrefcntbt", xfsstats_offset(xs_qm_dqreclaims)},
/* we print both series of quota information together */
{ "qm", xfsstats_offset(xs_gc_read_calls)},
- { "zoned", xfsstats_offset(__pad1)},
+ { "zoned", xfsstats_offset(xs_inodes_meta)},
+ { "metafile", xfsstats_offset(xs_xstrat_bytes)},
};
/* Loop over all stats groups */
@@ -99,16 +100,20 @@ int xfs_stats_format(struct xfsstats __percpu *stats, char *buf)
void xfs_stats_clearall(struct xfsstats __percpu *stats)
{
+ uint32_t xs_inodes_active, xs_inodes_meta;
int c;
- uint32_t vn_active;
xfs_notice(NULL, "Clearing xfsstats");
for_each_possible_cpu(c) {
preempt_disable();
- /* save vn_active, it's a universal truth! */
- vn_active = per_cpu_ptr(stats, c)->s.vn_active;
+ /*
+ * Save the active / meta inode counters, as they are stateful.
+ */
+ xs_inodes_active = per_cpu_ptr(stats, c)->s.xs_inodes_active;
+ xs_inodes_meta = per_cpu_ptr(stats, c)->s.xs_inodes_meta;
memset(per_cpu_ptr(stats, c), 0, sizeof(*stats));
- per_cpu_ptr(stats, c)->s.vn_active = vn_active;
+ per_cpu_ptr(stats, c)->s.xs_inodes_active = xs_inodes_active;
+ per_cpu_ptr(stats, c)->s.xs_inodes_meta = xs_inodes_meta;
preempt_enable();
}
}
diff --git a/fs/xfs/xfs_stats.h b/fs/xfs/xfs_stats.h
index 153d2381d0a8..57c32b86c358 100644
--- a/fs/xfs/xfs_stats.h
+++ b/fs/xfs/xfs_stats.h
@@ -100,14 +100,14 @@ struct __xfsstats {
uint32_t xs_iflush_count;
uint32_t xs_icluster_flushcnt;
uint32_t xs_icluster_flushinode;
- uint32_t vn_active; /* # vnodes not on free lists */
- uint32_t vn_alloc; /* # times vn_alloc called */
- uint32_t vn_get; /* # times vn_get called */
- uint32_t vn_hold; /* # times vn_hold called */
- uint32_t vn_rele; /* # times vn_rele called */
- uint32_t vn_reclaim; /* # times vn_reclaim called */
- uint32_t vn_remove; /* # times vn_remove called */
- uint32_t vn_free; /* # times vn_free called */
+ uint32_t xs_inodes_active;
+ uint32_t __unused_vn_alloc;
+ uint32_t __unused_vn_get;
+ uint32_t __unused_vn_hold;
+ uint32_t xs_inode_destroy;
+ uint32_t xs_inode_destroy2; /* same as xs_inode_destroy */
+ uint32_t xs_inode_mark_reclaimable;
+ uint32_t __unused_vn_free;
uint32_t xb_get;
uint32_t xb_create;
uint32_t xb_get_locked;
@@ -142,7 +142,8 @@ struct __xfsstats {
uint32_t xs_gc_read_calls;
uint32_t xs_gc_write_calls;
uint32_t xs_gc_zone_reset_calls;
- uint32_t __pad1;
+/* Metafile counters */
+ uint32_t xs_inodes_meta;
/* Extra precision counters */
uint64_t xs_xstrat_bytes;
uint64_t xs_write_bytes;
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
index abc45f860a73..f8de44443e81 100644
--- a/fs/xfs/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -712,8 +712,8 @@ xfs_fs_destroy_inode(
trace_xfs_destroy_inode(ip);
ASSERT(!rwsem_is_locked(&inode->i_rwsem));
- XFS_STATS_INC(ip->i_mount, vn_rele);
- XFS_STATS_INC(ip->i_mount, vn_remove);
+ XFS_STATS_INC(ip->i_mount, xs_inode_destroy);
+ XFS_STATS_INC(ip->i_mount, xs_inode_destroy2);
xfs_inode_mark_reclaimable(ip);
}
diff --git a/fs/xfs/xfs_verify_media.c b/fs/xfs/xfs_verify_media.c
index 069cd371619d..8bbd4ec567f8 100644
--- a/fs/xfs/xfs_verify_media.c
+++ b/fs/xfs/xfs_verify_media.c
@@ -122,7 +122,7 @@ xfs_verify_report_losses(
error = xfs_alloc_read_agf(pag, tp, 0, &agf_bp);
if (error) {
- xfs_perag_put(pag);
+ xfs_perag_rele(pag);
break;
}
@@ -158,7 +158,7 @@ xfs_verify_report_losses(
if (rtg)
xfs_rtgroup_unlock(rtg, XFS_RTGLOCK_RMAP);
if (error) {
- xfs_group_put(xg);
+ xfs_group_rele(xg);
break;
}
}
diff --git a/fs/xfs/xfs_zone_alloc.c b/fs/xfs/xfs_zone_alloc.c
index 67e0c8f5800f..e3d19b6dc64a 100644
--- a/fs/xfs/xfs_zone_alloc.c
+++ b/fs/xfs/xfs_zone_alloc.c
@@ -78,7 +78,7 @@ xfs_zone_account_reclaimable(
struct xfs_rtgroup *rtg,
uint32_t freed)
{
- struct xfs_group *xg = &rtg->rtg_group;
+ struct xfs_group *xg = rtg_group(rtg);
struct xfs_mount *mp = rtg_mount(rtg);
struct xfs_zone_info *zi = mp->m_zone_info;
uint32_t used = rtg_rmap(rtg)->i_used_blocks;
@@ -759,7 +759,7 @@ xfs_zone_alloc_blocks(
trace_xfs_zone_alloc_blocks(oz, allocated, count_fsb);
- *sector = xfs_gbno_to_daddr(&rtg->rtg_group, 0);
+ *sector = xfs_gbno_to_daddr(rtg_group(rtg), 0);
*is_seq = bdev_zone_is_seq(mp->m_rtdev_targp->bt_bdev, *sector);
if (!*is_seq)
*sector += XFS_FSB_TO_BB(mp, allocated);
@@ -1080,7 +1080,7 @@ xfs_init_zone(
if (write_pointer == 0) {
/* zone is empty */
atomic_inc(&zi->zi_nr_free_zones);
- xfs_group_set_mark(&rtg->rtg_group, XFS_RTG_FREE);
+ xfs_group_set_mark(rtg_group(rtg), XFS_RTG_FREE);
iz->available += rtg_blocks(rtg);
} else if (write_pointer < rtg_blocks(rtg)) {
/* zone is open */
diff --git a/fs/xfs/xfs_zone_gc.c b/fs/xfs/xfs_zone_gc.c
index 48c6cf584447..7efeecd2d85f 100644
--- a/fs/xfs/xfs_zone_gc.c
+++ b/fs/xfs/xfs_zone_gc.c
@@ -627,7 +627,7 @@ xfs_zone_gc_alloc_blocks(
if (!*count_fsb)
return NULL;
- *daddr = xfs_gbno_to_daddr(&oz->oz_rtg->rtg_group, 0);
+ *daddr = xfs_gbno_to_daddr(rtg_group(oz->oz_rtg), 0);
*is_seq = bdev_zone_is_seq(mp->m_rtdev_targp->bt_bdev, *daddr);
if (!*is_seq)
*daddr += XFS_FSB_TO_BB(mp, oz->oz_allocated);
@@ -702,7 +702,7 @@ xfs_zone_gc_start_chunk(
chunk->data = data;
chunk->oz = oz;
chunk->victim_rtg = iter->victim_rtg;
- atomic_inc(&chunk->victim_rtg->rtg_group.xg_active_ref);
+ atomic_inc(&rtg_group(chunk->victim_rtg)->xg_active_ref);
atomic_inc(&chunk->victim_rtg->rtg_gccount);
bio->bi_iter.bi_sector = xfs_rtb_to_daddr(mp, chunk->old_startblock);
@@ -788,7 +788,7 @@ xfs_zone_gc_split_write(
atomic_inc(&chunk->oz->oz_ref);
split_chunk->victim_rtg = chunk->victim_rtg;
- atomic_inc(&chunk->victim_rtg->rtg_group.xg_active_ref);
+ atomic_inc(&rtg_group(chunk->victim_rtg)->xg_active_ref);
atomic_inc(&chunk->victim_rtg->rtg_gccount);
chunk->offset += split_len;
@@ -888,7 +888,7 @@ xfs_zone_gc_finish_reset(
goto out;
}
- xfs_group_set_mark(&rtg->rtg_group, XFS_RTG_FREE);
+ xfs_group_set_mark(rtg_group(rtg), XFS_RTG_FREE);
atomic_inc(&zi->zi_nr_free_zones);
xfs_zoned_add_available(mp, rtg_blocks(rtg));
@@ -917,7 +917,7 @@ xfs_submit_zone_reset_bio(
XFS_STATS_INC(mp, xs_gc_zone_reset_calls);
- bio->bi_iter.bi_sector = xfs_gbno_to_daddr(&rtg->rtg_group, 0);
+ bio->bi_iter.bi_sector = xfs_gbno_to_daddr(rtg_group(rtg), 0);
if (!bdev_zone_is_seq(bio->bi_bdev, bio->bi_iter.bi_sector)) {
/*
* Also use the bio to drive the state machine when neither