Commit 64a5cfa6 authored by Steve French's avatar Steve French

Allow setting per-file compression via SMB2/3

Allow cifs/smb2/smb3 to return whether or not a file is compressed
via lsattr, and allow SMB2/SMB3 to set the per-file compression
flag ("chattr +c filename" on an smb3 mount).

Windows users often set the compressed flag (it can be
done from the desktop and file manager).  David Disseldorp
has patches to Samba server to support this (at least on btrfs)
which are complementary to this
Signed-off-by: default avatarSteve French <smfrench@gmail.com>
parent 7ff8d45c
...@@ -278,6 +278,8 @@ struct smb_version_operations { ...@@ -278,6 +278,8 @@ struct smb_version_operations {
/* set attributes */ /* set attributes */
int (*set_file_info)(struct inode *, const char *, FILE_BASIC_INFO *, int (*set_file_info)(struct inode *, const char *, FILE_BASIC_INFO *,
const unsigned int); const unsigned int);
int (*set_compression)(const unsigned int, struct cifs_tcon *,
struct cifsFileInfo *);
/* check if we can send an echo or nor */ /* check if we can send an echo or nor */
bool (*can_echo)(struct TCP_Server_Info *); bool (*can_echo)(struct TCP_Server_Info *);
/* send echo request */ /* send echo request */
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* *
* vfs operations that deal with io control * vfs operations that deal with io control
* *
* Copyright (C) International Business Machines Corp., 2005,2007 * Copyright (C) International Business Machines Corp., 2005,2013
* Author(s): Steve French (sfrench@us.ibm.com) * Author(s): Steve French (sfrench@us.ibm.com)
* *
* This library is free software; you can redistribute it and/or modify * This library is free software; you can redistribute it and/or modify
...@@ -34,13 +34,11 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg) ...@@ -34,13 +34,11 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
int rc = -ENOTTY; /* strange error - but the precedent */ int rc = -ENOTTY; /* strange error - but the precedent */
unsigned int xid; unsigned int xid;
struct cifs_sb_info *cifs_sb; struct cifs_sb_info *cifs_sb;
#ifdef CONFIG_CIFS_POSIX
struct cifsFileInfo *pSMBFile = filep->private_data; struct cifsFileInfo *pSMBFile = filep->private_data;
struct cifs_tcon *tcon; struct cifs_tcon *tcon;
__u64 ExtAttrBits = 0; __u64 ExtAttrBits = 0;
__u64 ExtAttrMask = 0; __u64 ExtAttrMask = 0;
__u64 caps; __u64 caps;
#endif /* CONFIG_CIFS_POSIX */
xid = get_xid(); xid = get_xid();
...@@ -49,12 +47,12 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg) ...@@ -49,12 +47,12 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
cifs_sb = CIFS_SB(inode->i_sb); cifs_sb = CIFS_SB(inode->i_sb);
switch (command) { switch (command) {
#ifdef CONFIG_CIFS_POSIX
case FS_IOC_GETFLAGS: case FS_IOC_GETFLAGS:
if (pSMBFile == NULL) if (pSMBFile == NULL)
break; break;
tcon = tlink_tcon(pSMBFile->tlink); tcon = tlink_tcon(pSMBFile->tlink);
caps = le64_to_cpu(tcon->fsUnixInfo.Capability); caps = le64_to_cpu(tcon->fsUnixInfo.Capability);
#ifdef CONFIG_CIFS_POSIX
if (CIFS_UNIX_EXTATTR_CAP & caps) { if (CIFS_UNIX_EXTATTR_CAP & caps) {
rc = CIFSGetExtAttr(xid, tcon, rc = CIFSGetExtAttr(xid, tcon,
pSMBFile->fid.netfid, pSMBFile->fid.netfid,
...@@ -63,29 +61,50 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg) ...@@ -63,29 +61,50 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
rc = put_user(ExtAttrBits & rc = put_user(ExtAttrBits &
FS_FL_USER_VISIBLE, FS_FL_USER_VISIBLE,
(int __user *)arg); (int __user *)arg);
if (rc != EOPNOTSUPP)
break;
}
#endif /* CONFIG_CIFS_POSIX */
rc = 0;
if (CIFS_I(inode)->cifsAttrs & ATTR_COMPRESSED) {
/* add in the compressed bit */
ExtAttrBits = FS_COMPR_FL;
rc = put_user(ExtAttrBits & FS_FL_USER_VISIBLE,
(int __user *)arg);
} }
break; break;
case FS_IOC_SETFLAGS: case FS_IOC_SETFLAGS:
if (pSMBFile == NULL) if (pSMBFile == NULL)
break; break;
tcon = tlink_tcon(pSMBFile->tlink); tcon = tlink_tcon(pSMBFile->tlink);
caps = le64_to_cpu(tcon->fsUnixInfo.Capability); caps = le64_to_cpu(tcon->fsUnixInfo.Capability);
if (CIFS_UNIX_EXTATTR_CAP & caps) {
if (get_user(ExtAttrBits, (int __user *)arg)) { if (get_user(ExtAttrBits, (int __user *)arg)) {
rc = -EFAULT; rc = -EFAULT;
break; break;
} }
/*
* rc = CIFSGetExtAttr(xid, tcon, /*
* pSMBFile->fid.netfid, * if (CIFS_UNIX_EXTATTR_CAP & caps)
* extAttrBits, * rc = CIFSSetExtAttr(xid, tcon,
* &ExtAttrMask); * pSMBFile->fid.netfid,
*/ * extAttrBits,
* &ExtAttrMask);
* if (rc != EOPNOTSUPP)
* break;
*/
/* Currently only flag we can set is compressed flag */
if ((ExtAttrBits & FS_COMPR_FL) == 0)
break;
/* Try to set compress flag */
if (tcon->ses->server->ops->set_compression) {
rc = tcon->ses->server->ops->set_compression(
xid, tcon, pSMBFile);
cifs_dbg(FYI, "set compress flag rc %d\n", rc);
} }
cifs_dbg(FYI, "set flags not implemented yet\n");
break; break;
#endif /* CONFIG_CIFS_POSIX */
default: default:
cifs_dbg(FYI, "unsupported ioctl\n"); cifs_dbg(FYI, "unsupported ioctl\n");
break; break;
......
...@@ -445,6 +445,14 @@ smb2_set_file_size(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -445,6 +445,14 @@ smb2_set_file_size(const unsigned int xid, struct cifs_tcon *tcon,
cfile->fid.volatile_fid, cfile->pid, &eof); cfile->fid.volatile_fid, cfile->pid, &eof);
} }
static int
smb2_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
struct cifsFileInfo *cfile)
{
return SMB2_set_compression(xid, tcon, cfile->fid.persistent_fid,
cfile->fid.volatile_fid);
}
static int static int
smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon, smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
const char *path, struct cifs_sb_info *cifs_sb, const char *path, struct cifs_sb_info *cifs_sb,
...@@ -874,6 +882,7 @@ struct smb_version_operations smb20_operations = { ...@@ -874,6 +882,7 @@ struct smb_version_operations smb20_operations = {
.set_path_size = smb2_set_path_size, .set_path_size = smb2_set_path_size,
.set_file_size = smb2_set_file_size, .set_file_size = smb2_set_file_size,
.set_file_info = smb2_set_file_info, .set_file_info = smb2_set_file_info,
.set_compression = smb2_set_compression,
.mkdir = smb2_mkdir, .mkdir = smb2_mkdir,
.mkdir_setinfo = smb2_mkdir_setinfo, .mkdir_setinfo = smb2_mkdir_setinfo,
.rmdir = smb2_rmdir, .rmdir = smb2_rmdir,
...@@ -945,6 +954,7 @@ struct smb_version_operations smb21_operations = { ...@@ -945,6 +954,7 @@ struct smb_version_operations smb21_operations = {
.set_path_size = smb2_set_path_size, .set_path_size = smb2_set_path_size,
.set_file_size = smb2_set_file_size, .set_file_size = smb2_set_file_size,
.set_file_info = smb2_set_file_info, .set_file_info = smb2_set_file_info,
.set_compression = smb2_set_compression,
.mkdir = smb2_mkdir, .mkdir = smb2_mkdir,
.mkdir_setinfo = smb2_mkdir_setinfo, .mkdir_setinfo = smb2_mkdir_setinfo,
.rmdir = smb2_rmdir, .rmdir = smb2_rmdir,
...@@ -1017,6 +1027,7 @@ struct smb_version_operations smb30_operations = { ...@@ -1017,6 +1027,7 @@ struct smb_version_operations smb30_operations = {
.set_path_size = smb2_set_path_size, .set_path_size = smb2_set_path_size,
.set_file_size = smb2_set_file_size, .set_file_size = smb2_set_file_size,
.set_file_info = smb2_set_file_info, .set_file_info = smb2_set_file_info,
.set_compression = smb2_set_compression,
.mkdir = smb2_mkdir, .mkdir = smb2_mkdir,
.mkdir_setinfo = smb2_mkdir_setinfo, .mkdir_setinfo = smb2_mkdir_setinfo,
.rmdir = smb2_rmdir, .rmdir = smb2_rmdir,
......
...@@ -1247,6 +1247,33 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, ...@@ -1247,6 +1247,33 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
return rc; return rc;
} }
/*
* Individual callers to ioctl worker function follow
*/
int
SMB2_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_fid, u64 volatile_fid)
{
int rc;
char *res_key = NULL;
struct compress_ioctl fsctl_input;
char *ret_data = NULL;
fsctl_input.CompressionState =
__constant_cpu_to_le16(COMPRESSION_FORMAT_DEFAULT);
rc = SMB2_ioctl(xid, tcon, persistent_fid, volatile_fid,
FSCTL_SET_COMPRESSION, true /* is_fsctl */,
(char *)&fsctl_input /* data input */,
2 /* in data len */, &ret_data /* out data */, NULL);
cifs_dbg(FYI, "set compression rc %d\n", rc);
kfree(res_key);
return rc;
}
int int
SMB2_close(const unsigned int xid, struct cifs_tcon *tcon, SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_fid, u64 volatile_fid) u64 persistent_fid, u64 volatile_fid)
......
...@@ -569,6 +569,13 @@ struct network_interface_info_ioctl_rsp { ...@@ -569,6 +569,13 @@ struct network_interface_info_ioctl_rsp {
#define NO_FILE_ID 0xFFFFFFFFFFFFFFFFULL /* general ioctls to srv not to file */ #define NO_FILE_ID 0xFFFFFFFFFFFFFFFFULL /* general ioctls to srv not to file */
struct compress_ioctl {
__le16 CompressionState;
} __packed;
#define COMPRESSION_FORMAT_NONE 0x0000
#define COMPRESSION_FORMAT_DEFAULT 0x0001
#define COMPRESSION_FORMAT_LZNT1 0x0002
struct smb2_ioctl_req { struct smb2_ioctl_req {
struct smb2_hdr hdr; struct smb2_hdr hdr;
__le16 StructureSize; /* Must be 57 */ __le16 StructureSize; /* Must be 57 */
...@@ -584,7 +591,7 @@ struct smb2_ioctl_req { ...@@ -584,7 +591,7 @@ struct smb2_ioctl_req {
__le32 MaxOutputResponse; __le32 MaxOutputResponse;
__le32 Flags; __le32 Flags;
__u32 Reserved2; __u32 Reserved2;
char Buffer[0]; __u8 Buffer[0];
} __packed; } __packed;
struct smb2_ioctl_rsp { struct smb2_ioctl_rsp {
......
...@@ -142,6 +142,8 @@ extern int SMB2_set_eof(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -142,6 +142,8 @@ extern int SMB2_set_eof(const unsigned int xid, struct cifs_tcon *tcon,
extern int SMB2_set_info(const unsigned int xid, struct cifs_tcon *tcon, extern int SMB2_set_info(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_fid, u64 volatile_fid, u64 persistent_fid, u64 volatile_fid,
FILE_BASIC_INFO *buf); FILE_BASIC_INFO *buf);
extern int SMB2_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_fid, u64 volatile_fid);
extern int SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon, extern int SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
const u64 persistent_fid, const u64 volatile_fid, const u64 persistent_fid, const u64 volatile_fid,
const __u8 oplock_level); const __u8 oplock_level);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment