Skip to content

Commit 31742c5

Browse files
committed
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>
1 parent ad3829c commit 31742c5

File tree

5 files changed

+73
-1
lines changed

5 files changed

+73
-1
lines changed

fs/cifs/cifsfs.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,19 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf)
207207
return 0;
208208
}
209209

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+
210223
static int cifs_permission(struct inode *inode, int mask)
211224
{
212225
struct cifs_sb_info *cifs_sb;
@@ -909,6 +922,7 @@ const struct file_operations cifs_file_ops = {
909922
.unlocked_ioctl = cifs_ioctl,
910923
#endif /* CONFIG_CIFS_POSIX */
911924
.setlease = cifs_setlease,
925+
.fallocate = cifs_fallocate,
912926
};
913927

914928
const struct file_operations cifs_file_strict_ops = {
@@ -928,6 +942,7 @@ const struct file_operations cifs_file_strict_ops = {
928942
.unlocked_ioctl = cifs_ioctl,
929943
#endif /* CONFIG_CIFS_POSIX */
930944
.setlease = cifs_setlease,
945+
.fallocate = cifs_fallocate,
931946
};
932947

933948
const struct file_operations cifs_file_direct_ops = {
@@ -948,6 +963,7 @@ const struct file_operations cifs_file_direct_ops = {
948963
#endif /* CONFIG_CIFS_POSIX */
949964
.llseek = cifs_llseek,
950965
.setlease = cifs_setlease,
966+
.fallocate = cifs_fallocate,
951967
};
952968

953969
const struct file_operations cifs_file_nobrl_ops = {
@@ -966,6 +982,7 @@ const struct file_operations cifs_file_nobrl_ops = {
966982
.unlocked_ioctl = cifs_ioctl,
967983
#endif /* CONFIG_CIFS_POSIX */
968984
.setlease = cifs_setlease,
985+
.fallocate = cifs_fallocate,
969986
};
970987

971988
const struct file_operations cifs_file_strict_nobrl_ops = {
@@ -984,6 +1001,7 @@ const struct file_operations cifs_file_strict_nobrl_ops = {
9841001
.unlocked_ioctl = cifs_ioctl,
9851002
#endif /* CONFIG_CIFS_POSIX */
9861003
.setlease = cifs_setlease,
1004+
.fallocate = cifs_fallocate,
9871005
};
9881006

9891007
const struct file_operations cifs_file_direct_nobrl_ops = {
@@ -1003,6 +1021,7 @@ const struct file_operations cifs_file_direct_nobrl_ops = {
10031021
#endif /* CONFIG_CIFS_POSIX */
10041022
.llseek = cifs_llseek,
10051023
.setlease = cifs_setlease,
1024+
.fallocate = cifs_fallocate,
10061025
};
10071026

10081027
const struct file_operations cifs_dir_ops = {

fs/cifs/cifsglob.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,8 @@ struct smb_version_operations {
411411
unsigned int *, unsigned int *);
412412
/* check if we need to issue closedir */
413413
bool (*dir_needs_close)(struct cifsFileInfo *);
414+
long (*fallocate)(struct file *, struct cifs_tcon *, int, loff_t,
415+
loff_t);
414416
};
415417

416418
struct smb_version_values {

fs/cifs/smb2ops.c

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1015,6 +1015,50 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
10151015
return rc;
10161016
}
10171017

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+
10181062
static void
10191063
smb2_downgrade_oplock(struct TCP_Server_Info *server,
10201064
struct cifsInodeInfo *cinode, bool set_level2)
@@ -1463,6 +1507,7 @@ struct smb_version_operations smb30_operations = {
14631507
.validate_negotiate = smb3_validate_negotiate,
14641508
.wp_retry_size = smb2_wp_retry_size,
14651509
.dir_needs_close = smb2_dir_needs_close,
1510+
.fallocate = smb3_fallocate,
14661511
};
14671512

14681513
struct smb_version_values smb20_values = {

fs/cifs/smb2pdu.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,12 @@ struct copychunk_ioctl {
573573
__u32 Reserved2;
574574
} __packed;
575575

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+
576582
struct copychunk_ioctl_rsp {
577583
__le32 ChunksWritten;
578584
__le32 ChunkBytesWritten;

fs/cifs/smbfsctl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@
6363
#define FSCTL_SET_OBJECT_ID_EXTENDED 0x000900BC /* BB add struct */
6464
#define FSCTL_CREATE_OR_GET_OBJECT_ID 0x000900C0 /* BB add struct */
6565
#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
6767
#define FSCTL_SET_ENCRYPTION 0x000900D7 /* BB add struct */
6868
#define FSCTL_ENCRYPTION_FSCTL_IO 0x000900DB /* BB add struct */
6969
#define FSCTL_WRITE_RAW_ENCRYPTED 0x000900DF /* BB add struct */

0 commit comments

Comments
 (0)