mirror of
https://github.com/torvalds/linux.git
synced 2026-10-08 19:46:02 +02:00
ksmbd: support file compression attributes
Advertise file compression support and keep the compression state in the per-file DOS attributes when the backing filesystem cannot apply the compression flag directly. FSCTL_SET_COMPRESSION should still update the state returned by FSCTL_GET_COMPRESSION and file compression information in that case. When a new object is created under a compressed directory, inherit the compression attribute from the parent. If FILE_NO_COMPRESSION is specified, clear the compression state after creation and let it override inheritance for both files and directories. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
This commit is contained in:
parent
49f6a48586
commit
0fb327626a
|
|
@ -2960,6 +2960,34 @@ static void smb2_new_xattrs(struct ksmbd_tree_connect *tcon, const struct path *
|
|||
ksmbd_debug(SMB, "failed to store file attribute into xattr\n");
|
||||
}
|
||||
|
||||
static bool smb2_parent_compressed(struct ksmbd_tree_connect *tcon,
|
||||
const struct path *path)
|
||||
{
|
||||
struct dentry *parent = dget_parent(path->dentry);
|
||||
struct file_kattr fa = { .flags_valid = true };
|
||||
struct xattr_dos_attrib da;
|
||||
bool compressed = false;
|
||||
int rc;
|
||||
|
||||
rc = vfs_fileattr_get(parent, &fa);
|
||||
if (!rc && fa.flags & FS_COMPR_FL) {
|
||||
compressed = true;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!test_share_config_flag(tcon->share_conf,
|
||||
KSMBD_SHARE_FLAG_STORE_DOS_ATTRS))
|
||||
goto out;
|
||||
|
||||
rc = ksmbd_vfs_get_dos_attrib_xattr(mnt_idmap(path->mnt), parent, &da);
|
||||
if (rc > 0 && da.attr & FILE_ATTRIBUTE_COMPRESSED)
|
||||
compressed = true;
|
||||
|
||||
out:
|
||||
dput(parent);
|
||||
return compressed;
|
||||
}
|
||||
|
||||
static void smb2_update_xattrs(struct ksmbd_tree_connect *tcon,
|
||||
const struct path *path, struct ksmbd_file *fp)
|
||||
{
|
||||
|
|
@ -3520,8 +3548,6 @@ int smb2_open(struct ksmbd_work *work)
|
|||
if (req->CreateOptions & FILE_NON_DIRECTORY_FILE_LE) {
|
||||
rc = -EINVAL;
|
||||
goto err_out2;
|
||||
} else if (req->CreateOptions & FILE_NO_COMPRESSION_LE) {
|
||||
req->CreateOptions &= ~FILE_NO_COMPRESSION_LE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4128,6 +4154,22 @@ int smb2_open(struct ksmbd_work *work)
|
|||
|
||||
ksmbd_vfs_update_compressed_fattr(path.dentry, &fp->f_ci->m_fattr);
|
||||
|
||||
if (created) {
|
||||
if (fp->coption & FILE_NO_COMPRESSION_LE) {
|
||||
rc = ksmbd_vfs_set_compression_create(work, fp,
|
||||
COMPRESSION_FORMAT_NONE);
|
||||
if (rc)
|
||||
fp->f_ci->m_fattr &= ~FILE_ATTRIBUTE_COMPRESSED_LE;
|
||||
rc = 0;
|
||||
} else if (smb2_parent_compressed(tcon, &path)) {
|
||||
rc = ksmbd_vfs_set_compression_create(work, fp,
|
||||
COMPRESSION_FORMAT_LZNT1);
|
||||
if (rc)
|
||||
fp->f_ci->m_fattr |= FILE_ATTRIBUTE_COMPRESSED_LE;
|
||||
rc = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (created)
|
||||
smb2_new_xattrs(tcon, &path, fp);
|
||||
|
||||
|
|
@ -6271,6 +6313,7 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work,
|
|||
attrs = FILE_SUPPORTS_OBJECT_IDS |
|
||||
FILE_PERSISTENT_ACLS |
|
||||
FILE_UNICODE_ON_DISK |
|
||||
FILE_FILE_COMPRESSION |
|
||||
FILE_SUPPORTS_BLOCK_REFCOUNTING;
|
||||
|
||||
err = vfs_fileattr_get(path.dentry, &fa);
|
||||
|
|
|
|||
|
|
@ -2008,8 +2008,6 @@ void ksmbd_vfs_update_compressed_fattr(struct dentry *dentry, __le32 *fattr)
|
|||
struct file_kattr fa = { .flags_valid = true };
|
||||
|
||||
rc = vfs_fileattr_get(dentry, &fa);
|
||||
if (rc == -ENOIOCTLCMD)
|
||||
*fattr &= ~FILE_ATTRIBUTE_COMPRESSED_LE;
|
||||
if (rc)
|
||||
return;
|
||||
|
||||
|
|
@ -2025,15 +2023,19 @@ int ksmbd_vfs_get_compression(struct ksmbd_file *fp, u16 *fmt)
|
|||
int rc;
|
||||
|
||||
rc = vfs_fileattr_get(fp->filp->f_path.dentry, &fa);
|
||||
if (rc == -ENOIOCTLCMD) {
|
||||
*fmt = COMPRESSION_FORMAT_NONE;
|
||||
if (rc == -ENOIOCTLCMD || rc == -ENOTTY || rc == -EINVAL ||
|
||||
rc == -EOPNOTSUPP) {
|
||||
if (fp->f_ci->m_fattr & FILE_ATTRIBUTE_COMPRESSED_LE)
|
||||
*fmt = COMPRESSION_FORMAT_LZNT1;
|
||||
else
|
||||
*fmt = COMPRESSION_FORMAT_NONE;
|
||||
rc = 0;
|
||||
goto out;
|
||||
}
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
if (fa.flags & FS_COMPR_FL)
|
||||
if (fp->f_ci->m_fattr & FILE_ATTRIBUTE_COMPRESSED_LE)
|
||||
*fmt = COMPRESSION_FORMAT_LZNT1;
|
||||
else
|
||||
*fmt = COMPRESSION_FORMAT_NONE;
|
||||
|
|
@ -2042,7 +2044,9 @@ int ksmbd_vfs_get_compression(struct ksmbd_file *fp, u16 *fmt)
|
|||
return rc;
|
||||
}
|
||||
|
||||
int ksmbd_vfs_set_compression(struct ksmbd_work *work, struct ksmbd_file *fp, u16 fmt)
|
||||
static int __ksmbd_vfs_set_compression(struct ksmbd_work *work,
|
||||
struct ksmbd_file *fp, u16 fmt,
|
||||
bool check_access)
|
||||
{
|
||||
const struct cred *saved_cred = NULL;
|
||||
struct file_kattr fa;
|
||||
|
|
@ -2052,13 +2056,23 @@ int ksmbd_vfs_set_compression(struct ksmbd_work *work, struct ksmbd_file *fp, u1
|
|||
__le32 old_fattr;
|
||||
int rc;
|
||||
|
||||
if (!(fp->daccess & FILE_WRITE_DATA_LE)) {
|
||||
if (check_access && !(fp->daccess & FILE_WRITE_DATA_LE)) {
|
||||
rc = -EACCES;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (fmt != COMPRESSION_FORMAT_NONE &&
|
||||
fmt != COMPRESSION_FORMAT_DEFAULT &&
|
||||
fmt != COMPRESSION_FORMAT_LZNT1) {
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
saved_cred = override_creds(fp->filp->f_cred);
|
||||
rc = vfs_fileattr_get(dentry, &fa);
|
||||
if (rc == -ENOIOCTLCMD || rc == -ENOTTY || rc == -EINVAL ||
|
||||
rc == -EOPNOTSUPP)
|
||||
goto update_fattr;
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
|
|
@ -2068,9 +2082,6 @@ int ksmbd_vfs_set_compression(struct ksmbd_work *work, struct ksmbd_file *fp, u1
|
|||
} else if (fmt == COMPRESSION_FORMAT_DEFAULT ||
|
||||
fmt == COMPRESSION_FORMAT_LZNT1) {
|
||||
flags |= FS_COMPR_FL;
|
||||
} else {
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (flags != fa.flags) {
|
||||
|
|
@ -2081,10 +2092,14 @@ int ksmbd_vfs_set_compression(struct ksmbd_work *work, struct ksmbd_file *fp, u1
|
|||
|
||||
rc = vfs_fileattr_set(idmap, dentry, &fa);
|
||||
mnt_drop_write_file(fp->filp);
|
||||
if (rc == -ENOIOCTLCMD || rc == -ENOTTY || rc == -EINVAL ||
|
||||
rc == -EOPNOTSUPP)
|
||||
goto update_fattr;
|
||||
if (rc)
|
||||
goto out;
|
||||
}
|
||||
|
||||
update_fattr:
|
||||
old_fattr = fp->f_ci->m_fattr;
|
||||
if (fmt == COMPRESSION_FORMAT_NONE)
|
||||
fp->f_ci->m_fattr &= ~FILE_ATTRIBUTE_COMPRESSED_LE;
|
||||
|
|
@ -2094,15 +2109,19 @@ int ksmbd_vfs_set_compression(struct ksmbd_work *work, struct ksmbd_file *fp, u1
|
|||
if (fp->f_ci->m_fattr != old_fattr &&
|
||||
test_share_config_flag(work->tcon->share_conf,
|
||||
KSMBD_SHARE_FLAG_STORE_DOS_ATTRS)) {
|
||||
struct xattr_dos_attrib da;
|
||||
struct xattr_dos_attrib da = {0};
|
||||
|
||||
rc = ksmbd_vfs_get_dos_attrib_xattr(idmap, dentry, &da);
|
||||
if (rc <= 0) {
|
||||
rc = 0;
|
||||
goto out;
|
||||
da.version = 4;
|
||||
da.itime = fp->itime;
|
||||
da.create_time = fp->create_time;
|
||||
da.flags = XATTR_DOSINFO_CREATE_TIME |
|
||||
XATTR_DOSINFO_ITIME;
|
||||
}
|
||||
|
||||
da.attr = le32_to_cpu(fp->f_ci->m_fattr);
|
||||
da.flags |= XATTR_DOSINFO_ATTRIB;
|
||||
rc = ksmbd_vfs_set_dos_attrib_xattr(idmap,
|
||||
&fp->filp->f_path,
|
||||
&da, true);
|
||||
|
|
@ -2115,3 +2134,15 @@ int ksmbd_vfs_set_compression(struct ksmbd_work *work, struct ksmbd_file *fp, u1
|
|||
revert_creds(saved_cred);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int ksmbd_vfs_set_compression(struct ksmbd_work *work,
|
||||
struct ksmbd_file *fp, u16 fmt)
|
||||
{
|
||||
return __ksmbd_vfs_set_compression(work, fp, fmt, true);
|
||||
}
|
||||
|
||||
int ksmbd_vfs_set_compression_create(struct ksmbd_work *work,
|
||||
struct ksmbd_file *fp, u16 fmt)
|
||||
{
|
||||
return __ksmbd_vfs_set_compression(work, fp, fmt, false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -171,4 +171,6 @@ int ksmbd_vfs_inherit_posix_acl(struct mnt_idmap *idmap,
|
|||
void ksmbd_vfs_update_compressed_fattr(struct dentry *dentry, __le32 *fattr);
|
||||
int ksmbd_vfs_get_compression(struct ksmbd_file *fp, u16 *fmt);
|
||||
int ksmbd_vfs_set_compression(struct ksmbd_work *work, struct ksmbd_file *fp, u16 fmt);
|
||||
int ksmbd_vfs_set_compression_create(struct ksmbd_work *work,
|
||||
struct ksmbd_file *fp, u16 fmt);
|
||||
#endif /* __KSMBD_VFS_H__ */
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user