summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteve French <smfrench@gmail.com>2013-10-14 16:31:32 -0400
committerSteve French <smfrench@gmail.com>2013-10-28 10:22:31 -0400
commit64a5cfa6db94c5abba2cafe77aca077dd1e3283b (patch)
tree4a17ded1db5b4e83ced56aa4d6d081d2a72211e4
parent7ff8d45c9dccf0744404d6fe44468ede7c1b9533 (diff)
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: Steve French <smfrench@gmail.com>
-rw-r--r--fs/cifs/cifsglob.h2
-rw-r--r--fs/cifs/ioctl.c55
-rw-r--r--fs/cifs/smb2ops.c11
-rw-r--r--fs/cifs/smb2pdu.c27
-rw-r--r--fs/cifs/smb2pdu.h9
-rw-r--r--fs/cifs/smb2proto.h2
6 files changed, 87 insertions, 19 deletions
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 52b6f6c26bfc..06e8947fc370 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -278,6 +278,8 @@ struct smb_version_operations {
278 /* set attributes */ 278 /* set attributes */
279 int (*set_file_info)(struct inode *, const char *, FILE_BASIC_INFO *, 279 int (*set_file_info)(struct inode *, const char *, FILE_BASIC_INFO *,
280 const unsigned int); 280 const unsigned int);
281 int (*set_compression)(const unsigned int, struct cifs_tcon *,
282 struct cifsFileInfo *);
281 /* check if we can send an echo or nor */ 283 /* check if we can send an echo or nor */
282 bool (*can_echo)(struct TCP_Server_Info *); 284 bool (*can_echo)(struct TCP_Server_Info *);
283 /* send echo request */ 285 /* send echo request */
diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c
index 3e0845585853..029867078aff 100644
--- a/fs/cifs/ioctl.c
+++ b/fs/cifs/ioctl.c
@@ -3,7 +3,7 @@
3 * 3 *
4 * vfs operations that deal with io control 4 * vfs operations that deal with io control
5 * 5 *
6 * Copyright (C) International Business Machines Corp., 2005,2007 6 * Copyright (C) International Business Machines Corp., 2005,2013
7 * Author(s): Steve French (sfrench@us.ibm.com) 7 * Author(s): Steve French (sfrench@us.ibm.com)
8 * 8 *
9 * This library is free software; you can redistribute it and/or modify 9 * 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 int rc = -ENOTTY; /* strange error - but the precedent */ 34 int rc = -ENOTTY; /* strange error - but the precedent */
35 unsigned int xid; 35 unsigned int xid;
36 struct cifs_sb_info *cifs_sb; 36 struct cifs_sb_info *cifs_sb;
37#ifdef CONFIG_CIFS_POSIX
38 struct cifsFileInfo *pSMBFile = filep->private_data; 37 struct cifsFileInfo *pSMBFile = filep->private_data;
39 struct cifs_tcon *tcon; 38 struct cifs_tcon *tcon;
40 __u64 ExtAttrBits = 0; 39 __u64 ExtAttrBits = 0;
41 __u64 ExtAttrMask = 0; 40 __u64 ExtAttrMask = 0;
42 __u64 caps; 41 __u64 caps;
43#endif /* CONFIG_CIFS_POSIX */
44 42
45 xid = get_xid(); 43 xid = get_xid();
46 44
@@ -49,12 +47,12 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
49 cifs_sb = CIFS_SB(inode->i_sb); 47 cifs_sb = CIFS_SB(inode->i_sb);
50 48
51 switch (command) { 49 switch (command) {
52#ifdef CONFIG_CIFS_POSIX
53 case FS_IOC_GETFLAGS: 50 case FS_IOC_GETFLAGS:
54 if (pSMBFile == NULL) 51 if (pSMBFile == NULL)
55 break; 52 break;
56 tcon = tlink_tcon(pSMBFile->tlink); 53 tcon = tlink_tcon(pSMBFile->tlink);
57 caps = le64_to_cpu(tcon->fsUnixInfo.Capability); 54 caps = le64_to_cpu(tcon->fsUnixInfo.Capability);
55#ifdef CONFIG_CIFS_POSIX
58 if (CIFS_UNIX_EXTATTR_CAP & caps) { 56 if (CIFS_UNIX_EXTATTR_CAP & caps) {
59 rc = CIFSGetExtAttr(xid, tcon, 57 rc = CIFSGetExtAttr(xid, tcon,
60 pSMBFile->fid.netfid, 58 pSMBFile->fid.netfid,
@@ -63,29 +61,50 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
63 rc = put_user(ExtAttrBits & 61 rc = put_user(ExtAttrBits &
64 FS_FL_USER_VISIBLE, 62 FS_FL_USER_VISIBLE,
65 (int __user *)arg); 63 (int __user *)arg);
64 if (rc != EOPNOTSUPP)
65 break;
66 }
67#endif /* CONFIG_CIFS_POSIX */
68 rc = 0;
69 if (CIFS_I(inode)->cifsAttrs & ATTR_COMPRESSED) {
70 /* add in the compressed bit */
71 ExtAttrBits = FS_COMPR_FL;
72 rc = put_user(ExtAttrBits & FS_FL_USER_VISIBLE,
73 (int __user *)arg);
66 } 74 }
67 break; 75 break;
68
69 case FS_IOC_SETFLAGS: 76 case FS_IOC_SETFLAGS:
70 if (pSMBFile == NULL) 77 if (pSMBFile == NULL)
71 break; 78 break;
72 tcon = tlink_tcon(pSMBFile->tlink); 79 tcon = tlink_tcon(pSMBFile->tlink);
73 caps = le64_to_cpu(tcon->fsUnixInfo.Capability); 80 caps = le64_to_cpu(tcon->fsUnixInfo.Capability);
74 if (CIFS_UNIX_EXTATTR_CAP & caps) { 81
75 if (get_user(ExtAttrBits, (int __user *)arg)) { 82 if (get_user(ExtAttrBits, (int __user *)arg)) {
76 rc = -EFAULT; 83 rc = -EFAULT;
77 break; 84 break;
78 } 85 }
79 /* 86
80 * rc = CIFSGetExtAttr(xid, tcon, 87 /*
81 * pSMBFile->fid.netfid, 88 * if (CIFS_UNIX_EXTATTR_CAP & caps)
82 * extAttrBits, 89 * rc = CIFSSetExtAttr(xid, tcon,
83 * &ExtAttrMask); 90 * pSMBFile->fid.netfid,
84 */ 91 * extAttrBits,
92 * &ExtAttrMask);
93 * if (rc != EOPNOTSUPP)
94 * break;
95 */
96
97 /* Currently only flag we can set is compressed flag */
98 if ((ExtAttrBits & FS_COMPR_FL) == 0)
99 break;
100
101 /* Try to set compress flag */
102 if (tcon->ses->server->ops->set_compression) {
103 rc = tcon->ses->server->ops->set_compression(
104 xid, tcon, pSMBFile);
105 cifs_dbg(FYI, "set compress flag rc %d\n", rc);
85 } 106 }
86 cifs_dbg(FYI, "set flags not implemented yet\n");
87 break; 107 break;
88#endif /* CONFIG_CIFS_POSIX */
89 default: 108 default:
90 cifs_dbg(FYI, "unsupported ioctl\n"); 109 cifs_dbg(FYI, "unsupported ioctl\n");
91 break; 110 break;
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 861b33214144..b96bacce955a 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -446,6 +446,14 @@ smb2_set_file_size(const unsigned int xid, struct cifs_tcon *tcon,
446} 446}
447 447
448static int 448static int
449smb2_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
450 struct cifsFileInfo *cfile)
451{
452 return SMB2_set_compression(xid, tcon, cfile->fid.persistent_fid,
453 cfile->fid.volatile_fid);
454}
455
456static int
449smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon, 457smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
450 const char *path, struct cifs_sb_info *cifs_sb, 458 const char *path, struct cifs_sb_info *cifs_sb,
451 struct cifs_fid *fid, __u16 search_flags, 459 struct cifs_fid *fid, __u16 search_flags,
@@ -874,6 +882,7 @@ struct smb_version_operations smb20_operations = {
874 .set_path_size = smb2_set_path_size, 882 .set_path_size = smb2_set_path_size,
875 .set_file_size = smb2_set_file_size, 883 .set_file_size = smb2_set_file_size,
876 .set_file_info = smb2_set_file_info, 884 .set_file_info = smb2_set_file_info,
885 .set_compression = smb2_set_compression,
877 .mkdir = smb2_mkdir, 886 .mkdir = smb2_mkdir,
878 .mkdir_setinfo = smb2_mkdir_setinfo, 887 .mkdir_setinfo = smb2_mkdir_setinfo,
879 .rmdir = smb2_rmdir, 888 .rmdir = smb2_rmdir,
@@ -945,6 +954,7 @@ struct smb_version_operations smb21_operations = {
945 .set_path_size = smb2_set_path_size, 954 .set_path_size = smb2_set_path_size,
946 .set_file_size = smb2_set_file_size, 955 .set_file_size = smb2_set_file_size,
947 .set_file_info = smb2_set_file_info, 956 .set_file_info = smb2_set_file_info,
957 .set_compression = smb2_set_compression,
948 .mkdir = smb2_mkdir, 958 .mkdir = smb2_mkdir,
949 .mkdir_setinfo = smb2_mkdir_setinfo, 959 .mkdir_setinfo = smb2_mkdir_setinfo,
950 .rmdir = smb2_rmdir, 960 .rmdir = smb2_rmdir,
@@ -1017,6 +1027,7 @@ struct smb_version_operations smb30_operations = {
1017 .set_path_size = smb2_set_path_size, 1027 .set_path_size = smb2_set_path_size,
1018 .set_file_size = smb2_set_file_size, 1028 .set_file_size = smb2_set_file_size,
1019 .set_file_info = smb2_set_file_info, 1029 .set_file_info = smb2_set_file_info,
1030 .set_compression = smb2_set_compression,
1020 .mkdir = smb2_mkdir, 1031 .mkdir = smb2_mkdir,
1021 .mkdir_setinfo = smb2_mkdir_setinfo, 1032 .mkdir_setinfo = smb2_mkdir_setinfo,
1022 .rmdir = smb2_rmdir, 1033 .rmdir = smb2_rmdir,
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 6e1868611233..bbafa12e83b2 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -1247,6 +1247,33 @@ ioctl_exit:
1247 return rc; 1247 return rc;
1248} 1248}
1249 1249
1250/*
1251 * Individual callers to ioctl worker function follow
1252 */
1253
1254int
1255SMB2_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
1256 u64 persistent_fid, u64 volatile_fid)
1257{
1258 int rc;
1259 char *res_key = NULL;
1260 struct compress_ioctl fsctl_input;
1261 char *ret_data = NULL;
1262
1263 fsctl_input.CompressionState =
1264 __constant_cpu_to_le16(COMPRESSION_FORMAT_DEFAULT);
1265
1266 rc = SMB2_ioctl(xid, tcon, persistent_fid, volatile_fid,
1267 FSCTL_SET_COMPRESSION, true /* is_fsctl */,
1268 (char *)&fsctl_input /* data input */,
1269 2 /* in data len */, &ret_data /* out data */, NULL);
1270
1271 cifs_dbg(FYI, "set compression rc %d\n", rc);
1272 kfree(res_key);
1273
1274 return rc;
1275}
1276
1250int 1277int
1251SMB2_close(const unsigned int xid, struct cifs_tcon *tcon, 1278SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
1252 u64 persistent_fid, u64 volatile_fid) 1279 u64 persistent_fid, u64 volatile_fid)
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index b83d0118a757..c7c3c8294d1a 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -569,6 +569,13 @@ struct network_interface_info_ioctl_rsp {
569 569
570#define NO_FILE_ID 0xFFFFFFFFFFFFFFFFULL /* general ioctls to srv not to file */ 570#define NO_FILE_ID 0xFFFFFFFFFFFFFFFFULL /* general ioctls to srv not to file */
571 571
572struct compress_ioctl {
573 __le16 CompressionState;
574} __packed;
575
576#define COMPRESSION_FORMAT_NONE 0x0000
577#define COMPRESSION_FORMAT_DEFAULT 0x0001
578#define COMPRESSION_FORMAT_LZNT1 0x0002
572struct smb2_ioctl_req { 579struct smb2_ioctl_req {
573 struct smb2_hdr hdr; 580 struct smb2_hdr hdr;
574 __le16 StructureSize; /* Must be 57 */ 581 __le16 StructureSize; /* Must be 57 */
@@ -584,7 +591,7 @@ struct smb2_ioctl_req {
584 __le32 MaxOutputResponse; 591 __le32 MaxOutputResponse;
585 __le32 Flags; 592 __le32 Flags;
586 __u32 Reserved2; 593 __u32 Reserved2;
587 char Buffer[0]; 594 __u8 Buffer[0];
588} __packed; 595} __packed;
589 596
590struct smb2_ioctl_rsp { 597struct smb2_ioctl_rsp {
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index e3fb4801ee96..3cf22e39420d 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -142,6 +142,8 @@ extern int SMB2_set_eof(const unsigned int xid, struct cifs_tcon *tcon,
142extern int SMB2_set_info(const unsigned int xid, struct cifs_tcon *tcon, 142extern int SMB2_set_info(const unsigned int xid, struct cifs_tcon *tcon,
143 u64 persistent_fid, u64 volatile_fid, 143 u64 persistent_fid, u64 volatile_fid,
144 FILE_BASIC_INFO *buf); 144 FILE_BASIC_INFO *buf);
145extern int SMB2_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
146 u64 persistent_fid, u64 volatile_fid);
145extern int SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon, 147extern int SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
146 const u64 persistent_fid, const u64 volatile_fid, 148 const u64 persistent_fid, const u64 volatile_fid,
147 const __u8 oplock_level); 149 const __u8 oplock_level);