From: Huiwen He <huiwen.he@linux.dev>
To: smfrench@gmail.com, linkinjeon@kernel.org, pc@manguebit.org,
ronniesahlberg@gmail.com, sprasad@microsoft.com, tom@talpey.com,
bharathsm@microsoft.com, senozhatsky@chromium.org,
dhowells@redhat.com, chenxiaosong@kylinos.cn
Cc: linux-cifs@vger.kernel.org
Subject: [PATCH 1/2] smb/client: implement fileattr_set for compression flags
Date: Wed, 22 Jul 2026 16:53:32 +0800 [thread overview]
Message-ID: <20260722085333.86217-2-huiwen.he@linux.dev> (raw)
In-Reply-To: <20260722085333.86217-1-huiwen.he@linux.dev>
From: Huiwen He <hehuiwen@kylinos.cn>
CIFS handles FS_IOC_SETFLAGS in cifs_ioctl() because it does not
implement ->fileattr_set. This causes the request to fall back from the
generic fileattr path and bypass its permission and serialization checks.
Implement ->fileattr_set for regular files and directories and use the
existing compression helper for FS_COMPR_FL. Accept an unchanged
FS_CASEFOLD_FL reported by fileattr_get so chattr can update compression
on case-insensitive shares.
Tested chattr +c and -c on files and directories against Samba. Non-owner
and read-only mount requests were rejected by the VFS checks.
Signed-off-by: Huiwen He <hehuiwen@kylinos.cn>
Reviewed-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
---
fs/smb/client/cifsfs.c | 4 +-
fs/smb/client/cifsfs.h | 2 +
fs/smb/client/ioctl.c | 89 ++++++++++++++++++++++++++++++++++++------
3 files changed, 81 insertions(+), 14 deletions(-)
diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c
index 66b9104e7ca2..0a1135602697 100644
--- a/fs/smb/client/cifsfs.c
+++ b/fs/smb/client/cifsfs.c
@@ -1195,7 +1195,7 @@ int cifs_fileattr_get(struct dentry *dentry, struct file_kattr *fa)
u32 attrs;
/* Preserve FS_COMPR_FL previously reported by cifs_ioctl(). */
- if (CIFS_I(inode)->cifsAttrs & ATTR_COMPRESSED)
+ if (READ_ONCE(CIFS_I(inode)->cifsAttrs) & ATTR_COMPRESSED)
fa->flags |= FS_COMPR_FL;
/*
@@ -1256,6 +1256,7 @@ const struct inode_operations cifs_dir_inode_ops = {
.get_acl = cifs_get_acl,
.set_acl = cifs_set_acl,
.fileattr_get = cifs_fileattr_get,
+ .fileattr_set = cifs_fileattr_set,
};
const struct inode_operations cifs_file_inode_ops = {
@@ -1267,6 +1268,7 @@ const struct inode_operations cifs_file_inode_ops = {
.get_acl = cifs_get_acl,
.set_acl = cifs_set_acl,
.fileattr_get = cifs_fileattr_get,
+ .fileattr_set = cifs_fileattr_set,
};
const char *cifs_get_link(struct dentry *dentry, struct inode *inode,
diff --git a/fs/smb/client/cifsfs.h b/fs/smb/client/cifsfs.h
index 854e672a4e37..10dcf51378d3 100644
--- a/fs/smb/client/cifsfs.h
+++ b/fs/smb/client/cifsfs.h
@@ -91,6 +91,8 @@ extern const struct inode_operations cifs_namespace_inode_operations;
struct file_kattr;
int cifs_fileattr_get(struct dentry *dentry, struct file_kattr *fa);
+int cifs_fileattr_set(struct mnt_idmap *idmap, struct dentry *dentry,
+ struct file_kattr *fa);
/* Functions related to files and directories */
diff --git a/fs/smb/client/ioctl.c b/fs/smb/client/ioctl.c
index 9fa743be3652..8b2ca0c7c06c 100644
--- a/fs/smb/client/ioctl.c
+++ b/fs/smb/client/ioctl.c
@@ -10,6 +10,7 @@
#include <linux/fs.h>
#include <linux/file.h>
+#include <linux/fileattr.h>
#include <linux/mount.h>
#include <linux/mm.h>
#include <linux/pagemap.h>
@@ -67,11 +68,11 @@ static long cifs_ioctl_query_info(unsigned int xid, struct file *filep,
return rc;
}
-static int cifs_set_compression_by_path(unsigned int xid, struct file *filep,
+static int cifs_set_compression_by_path(unsigned int xid, struct dentry *dentry,
struct cifs_tcon *tcon,
__u16 compression_state)
{
- struct inode *inode = file_inode(filep);
+ struct inode *inode = d_inode(dentry);
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
struct TCP_Server_Info *server = tcon->ses->server;
struct cifs_open_parms oparms;
@@ -92,11 +93,11 @@ static int cifs_set_compression_by_path(unsigned int xid, struct file *filep,
cifs_sb->mnt_cifs_serverino_autodisabled)
return -EOPNOTSUPP;
- if (d_unhashed(filep->f_path.dentry))
+ if (d_unhashed(dentry))
return -ESTALE;
page = alloc_dentry_path();
- full_path = build_path_from_dentry(filep->f_path.dentry, page);
+ full_path = build_path_from_dentry(dentry, page);
if (IS_ERR(full_path)) {
free_dentry_path(page);
return PTR_ERR(full_path);
@@ -123,6 +124,10 @@ static int cifs_set_compression_by_path(unsigned int xid, struct file *filep,
goto close;
uniqueid = le64_to_cpu(data.fi.IndexNumber);
+ if (!uniqueid) {
+ rc = -EOPNOTSUPP;
+ goto close;
+ }
if (uniqueid != CIFS_I(inode)->uniqueid) {
rc = -ESTALE;
goto close;
@@ -141,14 +146,14 @@ static int cifs_set_compression_by_path(unsigned int xid, struct file *filep,
return rc;
}
-static int cifs_ioctl_set_compression(unsigned int xid, struct file *filep,
- struct cifs_tcon *tcon,
- struct cifsFileInfo *cfile,
- __u16 compression_state)
+static int cifs_set_compression(unsigned int xid, struct dentry *dentry,
+ struct cifs_tcon *tcon,
+ struct cifsFileInfo *cfile,
+ __u16 compression_state)
{
struct cifsFileInfo *wfile;
struct cifs_tcon *wtcon;
- struct inode *inode = file_inode(filep);
+ struct inode *inode = d_inode(dentry);
int rc;
if (!tcon->ses->server->ops->set_compression)
@@ -173,10 +178,68 @@ static int cifs_ioctl_set_compression(unsigned int xid, struct file *filep,
return rc;
}
- return cifs_set_compression_by_path(xid, filep, tcon,
+ return cifs_set_compression_by_path(xid, dentry, tcon,
compression_state);
}
+int cifs_fileattr_set(struct mnt_idmap *idmap, struct dentry *dentry,
+ struct file_kattr *fa)
+{
+ struct inode *inode = d_inode(dentry);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+ struct file_kattr current_fa = {};
+ struct tcon_link *tlink;
+ struct cifs_tcon *tcon;
+ __u16 compression_state;
+ bool enable_compression;
+ u32 allowed = FS_COMPR_FL;
+ unsigned int xid;
+ int rc;
+
+ if (!fa->flags_valid)
+ return -EOPNOTSUPP;
+
+ /*
+ * chattr writes back all flags returned by fileattr_get(). Accept
+ * FS_CASEFOLD_FL only when it reflects the share's casefold state.
+ */
+ if (fa->flags & FS_CASEFOLD_FL) {
+ rc = cifs_fileattr_get(dentry, ¤t_fa);
+ if (rc)
+ return rc;
+ if (current_fa.flags & FS_CASEFOLD_FL)
+ allowed |= FS_CASEFOLD_FL;
+ }
+ if (fa->flags & ~allowed)
+ return -EOPNOTSUPP;
+
+ enable_compression = fa->flags & FS_COMPR_FL;
+ compression_state = enable_compression ? COMPRESSION_FORMAT_DEFAULT :
+ COMPRESSION_FORMAT_NONE;
+
+ tlink = cifs_sb_tlink(cifs_sb);
+ if (IS_ERR(tlink))
+ return PTR_ERR(tlink);
+ tcon = tlink_tcon(tlink);
+
+ xid = get_xid();
+ rc = cifs_set_compression(xid, dentry, tcon, NULL, compression_state);
+ free_xid(xid);
+ cifs_put_tlink(tlink);
+
+ if (!rc) {
+ spin_lock(&inode->i_lock);
+ if (enable_compression)
+ CIFS_I(inode)->cifsAttrs |= FILE_ATTRIBUTE_COMPRESSED;
+ else
+ CIFS_I(inode)->cifsAttrs &= ~FILE_ATTRIBUTE_COMPRESSED;
+ spin_unlock(&inode->i_lock);
+ }
+
+ cifs_dbg(FYI, "set compress flag rc %d\n", rc);
+ return rc;
+}
+
static long cifs_ioctl_copychunk(unsigned int xid, struct file *dst_file,
unsigned long srcfd)
{
@@ -542,9 +605,9 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
COMPRESSION_FORMAT_DEFAULT :
COMPRESSION_FORMAT_NONE;
- rc = cifs_ioctl_set_compression(xid, filep, tcon,
- pSMBFile,
- compression_state);
+ rc = cifs_set_compression(xid, filep->f_path.dentry,
+ tcon, pSMBFile,
+ compression_state);
if (rc == 0) {
spin_lock(&inode->i_lock);
if (enable_compression)
--
2.43.0
next prev parent reply other threads:[~2026-07-22 8:54 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-22 8:53 [PATCH 0/2] smb/client: handle compression flags through fileattr Huiwen He
2026-07-22 8:53 ` Huiwen He [this message]
2026-07-22 8:53 ` [PATCH 2/2] smb/client: remove unused file flags ioctl handlers Huiwen He
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260722085333.86217-2-huiwen.he@linux.dev \
--to=huiwen.he@linux.dev \
--cc=bharathsm@microsoft.com \
--cc=chenxiaosong@kylinos.cn \
--cc=dhowells@redhat.com \
--cc=linkinjeon@kernel.org \
--cc=linux-cifs@vger.kernel.org \
--cc=pc@manguebit.org \
--cc=ronniesahlberg@gmail.com \
--cc=senozhatsky@chromium.org \
--cc=smfrench@gmail.com \
--cc=sprasad@microsoft.com \
--cc=tom@talpey.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox