aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteve French <smfrench@gmail.com>2014-08-17 09:38:47 -0400
committerSteve French <smfrench@gmail.com>2014-08-17 19:12:38 -0400
commit31742c5a331766bc7df6b0d525df00c6cd20d5a6 (patch)
tree8a8ca459f4bc29c8c6898d09765b3130e24862e3
parentad3829cf1db5cf6a5dfafd54f9291b44f5fb1da8 (diff)
enable fallocate punch hole ("fallocate -p") for SMB3
Implement FALLOC_FL_PUNCH_HOLE (which does not change the file size fortunately so this matches the behavior of the equivalent SMB3 fsctl call) for SMB3 mounts. This allows "fallocate -p" to work. It requires that the server support setting files as sparse (which Windows allows). Signed-off-by: Steve French <smfrench@gmail.com>
-rw-r--r--fs/cifs/cifsfs.c19
-rw-r--r--fs/cifs/cifsglob.h2
-rw-r--r--fs/cifs/smb2ops.c45
-rw-r--r--fs/cifs/smb2pdu.h6
-rw-r--r--fs/cifs/smbfsctl.h2
5 files changed, 73 insertions, 1 deletions
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 0a4a4d7d407e..155347e190f9 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -207,6 +207,19 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf)
207 return 0; 207 return 0;
208} 208}
209 209
210static long cifs_fallocate(struct file *file, int mode, loff_t off, loff_t len)
211{
212 struct super_block *sb = file->f_path.dentry->d_sb;
213 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
214 struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
215 struct TCP_Server_Info *server = tcon->ses->server;
216
217 if (server->ops->fallocate)
218 return server->ops->fallocate(file, tcon, mode, off, len);
219
220 return -EOPNOTSUPP;
221}
222
210static int cifs_permission(struct inode *inode, int mask) 223static int cifs_permission(struct inode *inode, int mask)
211{ 224{
212 struct cifs_sb_info *cifs_sb; 225 struct cifs_sb_info *cifs_sb;
@@ -909,6 +922,7 @@ const struct file_operations cifs_file_ops = {
909 .unlocked_ioctl = cifs_ioctl, 922 .unlocked_ioctl = cifs_ioctl,
910#endif /* CONFIG_CIFS_POSIX */ 923#endif /* CONFIG_CIFS_POSIX */
911 .setlease = cifs_setlease, 924 .setlease = cifs_setlease,
925 .fallocate = cifs_fallocate,
912}; 926};
913 927
914const struct file_operations cifs_file_strict_ops = { 928const struct file_operations cifs_file_strict_ops = {
@@ -928,6 +942,7 @@ const struct file_operations cifs_file_strict_ops = {
928 .unlocked_ioctl = cifs_ioctl, 942 .unlocked_ioctl = cifs_ioctl,
929#endif /* CONFIG_CIFS_POSIX */ 943#endif /* CONFIG_CIFS_POSIX */
930 .setlease = cifs_setlease, 944 .setlease = cifs_setlease,
945 .fallocate = cifs_fallocate,
931}; 946};
932 947
933const struct file_operations cifs_file_direct_ops = { 948const struct file_operations cifs_file_direct_ops = {
@@ -948,6 +963,7 @@ const struct file_operations cifs_file_direct_ops = {
948#endif /* CONFIG_CIFS_POSIX */ 963#endif /* CONFIG_CIFS_POSIX */
949 .llseek = cifs_llseek, 964 .llseek = cifs_llseek,
950 .setlease = cifs_setlease, 965 .setlease = cifs_setlease,
966 .fallocate = cifs_fallocate,
951}; 967};
952 968
953const struct file_operations cifs_file_nobrl_ops = { 969const struct file_operations cifs_file_nobrl_ops = {
@@ -966,6 +982,7 @@ const struct file_operations cifs_file_nobrl_ops = {
966 .unlocked_ioctl = cifs_ioctl, 982 .unlocked_ioctl = cifs_ioctl,
967#endif /* CONFIG_CIFS_POSIX */ 983#endif /* CONFIG_CIFS_POSIX */
968 .setlease = cifs_setlease, 984 .setlease = cifs_setlease,
985 .fallocate = cifs_fallocate,
969}; 986};
970 987
971const struct file_operations cifs_file_strict_nobrl_ops = { 988const struct file_operations cifs_file_strict_nobrl_ops = {
@@ -984,6 +1001,7 @@ const struct file_operations cifs_file_strict_nobrl_ops = {
984 .unlocked_ioctl = cifs_ioctl, 1001 .unlocked_ioctl = cifs_ioctl,
985#endif /* CONFIG_CIFS_POSIX */ 1002#endif /* CONFIG_CIFS_POSIX */
986 .setlease = cifs_setlease, 1003 .setlease = cifs_setlease,
1004 .fallocate = cifs_fallocate,
987}; 1005};
988 1006
989const struct file_operations cifs_file_direct_nobrl_ops = { 1007const struct file_operations cifs_file_direct_nobrl_ops = {
@@ -1003,6 +1021,7 @@ const struct file_operations cifs_file_direct_nobrl_ops = {
1003#endif /* CONFIG_CIFS_POSIX */ 1021#endif /* CONFIG_CIFS_POSIX */
1004 .llseek = cifs_llseek, 1022 .llseek = cifs_llseek,
1005 .setlease = cifs_setlease, 1023 .setlease = cifs_setlease,
1024 .fallocate = cifs_fallocate,
1006}; 1025};
1007 1026
1008const struct file_operations cifs_dir_ops = { 1027const struct file_operations cifs_dir_ops = {
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index ce24c1fc2123..dfc731b02aa9 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -411,6 +411,8 @@ struct smb_version_operations {
411 unsigned int *, unsigned int *); 411 unsigned int *, unsigned int *);
412 /* check if we need to issue closedir */ 412 /* check if we need to issue closedir */
413 bool (*dir_needs_close)(struct cifsFileInfo *); 413 bool (*dir_needs_close)(struct cifsFileInfo *);
414 long (*fallocate)(struct file *, struct cifs_tcon *, int, loff_t,
415 loff_t);
414}; 416};
415 417
416struct smb_version_values { 418struct smb_version_values {
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 3fcd410cee31..101670c2c374 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -1015,6 +1015,50 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
1015 return rc; 1015 return rc;
1016} 1016}
1017 1017
1018static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon,
1019 loff_t offset, loff_t len)
1020{
1021 struct inode *inode;
1022 struct cifsInodeInfo *cifsi;
1023 struct cifsFileInfo *cfile = file->private_data;
1024 struct file_zero_data_information fsctl_buf;
1025 long rc;
1026 unsigned int xid;
1027 __u8 set_sparse = 1;
1028
1029 xid = get_xid();
1030
1031 inode = cfile->dentry->d_inode;
1032 cifsi = CIFS_I(inode);
1033
1034 /* Need to make file sparse, if not already, before freeing range. */
1035 /* Consider adding equivalent for compressed since it could also work */
1036 if (!smb2_set_sparse(xid, tcon, cfile, inode, set_sparse))
1037 return -EOPNOTSUPP;
1038
1039 cifs_dbg(FYI, "offset %lld len %lld", offset, len);
1040
1041 fsctl_buf.FileOffset = cpu_to_le64(offset);
1042 fsctl_buf.BeyondFinalZero = cpu_to_le64(offset + len);
1043
1044 rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
1045 cfile->fid.volatile_fid, FSCTL_SET_ZERO_DATA,
1046 true /* is_fctl */, (char *)&fsctl_buf,
1047 sizeof(struct file_zero_data_information), NULL, NULL);
1048 free_xid(xid);
1049 return rc;
1050}
1051
1052static long smb3_fallocate(struct file *file, struct cifs_tcon *tcon, int mode,
1053 loff_t off, loff_t len)
1054{
1055 /* KEEP_SIZE already checked for by do_fallocate */
1056 if (mode & FALLOC_FL_PUNCH_HOLE)
1057 return smb3_punch_hole(file, tcon, off, len);
1058
1059 return -EOPNOTSUPP;
1060}
1061
1018static void 1062static void
1019smb2_downgrade_oplock(struct TCP_Server_Info *server, 1063smb2_downgrade_oplock(struct TCP_Server_Info *server,
1020 struct cifsInodeInfo *cinode, bool set_level2) 1064 struct cifsInodeInfo *cinode, bool set_level2)
@@ -1463,6 +1507,7 @@ struct smb_version_operations smb30_operations = {
1463 .validate_negotiate = smb3_validate_negotiate, 1507 .validate_negotiate = smb3_validate_negotiate,
1464 .wp_retry_size = smb2_wp_retry_size, 1508 .wp_retry_size = smb2_wp_retry_size,
1465 .dir_needs_close = smb2_dir_needs_close, 1509 .dir_needs_close = smb2_dir_needs_close,
1510 .fallocate = smb3_fallocate,
1466}; 1511};
1467 1512
1468struct smb_version_values smb20_values = { 1513struct smb_version_values smb20_values = {
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index 69f3595d3952..fbe486c285a9 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -573,6 +573,12 @@ struct copychunk_ioctl {
573 __u32 Reserved2; 573 __u32 Reserved2;
574} __packed; 574} __packed;
575 575
576/* this goes in the ioctl buffer when doing FSCTL_SET_ZERO_DATA */
577struct file_zero_data_information {
578 __le64 FileOffset;
579 __le64 BeyondFinalZero;
580} __packed;
581
576struct copychunk_ioctl_rsp { 582struct copychunk_ioctl_rsp {
577 __le32 ChunksWritten; 583 __le32 ChunksWritten;
578 __le32 ChunkBytesWritten; 584 __le32 ChunkBytesWritten;
diff --git a/fs/cifs/smbfsctl.h b/fs/cifs/smbfsctl.h
index 0e538b5c9622..83efa59535be 100644
--- a/fs/cifs/smbfsctl.h
+++ b/fs/cifs/smbfsctl.h
@@ -63,7 +63,7 @@
63#define FSCTL_SET_OBJECT_ID_EXTENDED 0x000900BC /* BB add struct */ 63#define FSCTL_SET_OBJECT_ID_EXTENDED 0x000900BC /* BB add struct */
64#define FSCTL_CREATE_OR_GET_OBJECT_ID 0x000900C0 /* BB add struct */ 64#define FSCTL_CREATE_OR_GET_OBJECT_ID 0x000900C0 /* BB add struct */
65#define FSCTL_SET_SPARSE 0x000900C4 /* BB add struct */ 65#define FSCTL_SET_SPARSE 0x000900C4 /* BB add struct */
66#define FSCTL_SET_ZERO_DATA 0x000900C8 /* BB add struct */ 66#define FSCTL_SET_ZERO_DATA 0x000980C8
67#define FSCTL_SET_ENCRYPTION 0x000900D7 /* BB add struct */ 67#define FSCTL_SET_ENCRYPTION 0x000900D7 /* BB add struct */
68#define FSCTL_ENCRYPTION_FSCTL_IO 0x000900DB /* BB add struct */ 68#define FSCTL_ENCRYPTION_FSCTL_IO 0x000900DB /* BB add struct */
69#define FSCTL_WRITE_RAW_ENCRYPTED 0x000900DF /* BB add struct */ 69#define FSCTL_WRITE_RAW_ENCRYPTED 0x000900DF /* BB add struct */