diff options
| author | Steve French <smfrench@gmail.com> | 2014-08-17 09:38:47 -0400 |
|---|---|---|
| committer | Steve French <smfrench@gmail.com> | 2014-08-17 19:12:38 -0400 |
| commit | 31742c5a331766bc7df6b0d525df00c6cd20d5a6 (patch) | |
| tree | 8a8ca459f4bc29c8c6898d09765b3130e24862e3 | |
| parent | ad3829cf1db5cf6a5dfafd54f9291b44f5fb1da8 (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.c | 19 | ||||
| -rw-r--r-- | fs/cifs/cifsglob.h | 2 | ||||
| -rw-r--r-- | fs/cifs/smb2ops.c | 45 | ||||
| -rw-r--r-- | fs/cifs/smb2pdu.h | 6 | ||||
| -rw-r--r-- | fs/cifs/smbfsctl.h | 2 |
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 | ||
| 210 | static 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 | |||
| 210 | static int cifs_permission(struct inode *inode, int mask) | 223 | static 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 | ||
| 914 | const struct file_operations cifs_file_strict_ops = { | 928 | const 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 | ||
| 933 | const struct file_operations cifs_file_direct_ops = { | 948 | const 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 | ||
| 953 | const struct file_operations cifs_file_nobrl_ops = { | 969 | const 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 | ||
| 971 | const struct file_operations cifs_file_strict_nobrl_ops = { | 988 | const 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 | ||
| 989 | const struct file_operations cifs_file_direct_nobrl_ops = { | 1007 | const 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 | ||
| 1008 | const struct file_operations cifs_dir_ops = { | 1027 | const 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 | ||
| 416 | struct smb_version_values { | 418 | struct 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 | ||
| 1018 | static 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 | |||
| 1052 | static 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 | |||
| 1018 | static void | 1062 | static void |
| 1019 | smb2_downgrade_oplock(struct TCP_Server_Info *server, | 1063 | smb2_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 | ||
| 1468 | struct smb_version_values smb20_values = { | 1513 | struct 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 */ | ||
| 577 | struct file_zero_data_information { | ||
| 578 | __le64 FileOffset; | ||
| 579 | __le64 BeyondFinalZero; | ||
| 580 | } __packed; | ||
| 581 | |||
| 576 | struct copychunk_ioctl_rsp { | 582 | struct 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 */ |
