mirror of
https://github.com/torvalds/linux.git
synced 2024-11-23 04:31:50 +00:00
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>
This commit is contained in:
parent
ad3829cf1d
commit
31742c5a33
@ -207,6 +207,19 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static long cifs_fallocate(struct file *file, int mode, loff_t off, loff_t len)
|
||||||
|
{
|
||||||
|
struct super_block *sb = file->f_path.dentry->d_sb;
|
||||||
|
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
|
||||||
|
struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
|
||||||
|
struct TCP_Server_Info *server = tcon->ses->server;
|
||||||
|
|
||||||
|
if (server->ops->fallocate)
|
||||||
|
return server->ops->fallocate(file, tcon, mode, off, len);
|
||||||
|
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
static int cifs_permission(struct inode *inode, int mask)
|
static int cifs_permission(struct inode *inode, int mask)
|
||||||
{
|
{
|
||||||
struct cifs_sb_info *cifs_sb;
|
struct cifs_sb_info *cifs_sb;
|
||||||
@ -909,6 +922,7 @@ const struct file_operations cifs_file_ops = {
|
|||||||
.unlocked_ioctl = cifs_ioctl,
|
.unlocked_ioctl = cifs_ioctl,
|
||||||
#endif /* CONFIG_CIFS_POSIX */
|
#endif /* CONFIG_CIFS_POSIX */
|
||||||
.setlease = cifs_setlease,
|
.setlease = cifs_setlease,
|
||||||
|
.fallocate = cifs_fallocate,
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct file_operations cifs_file_strict_ops = {
|
const struct file_operations cifs_file_strict_ops = {
|
||||||
@ -928,6 +942,7 @@ const struct file_operations cifs_file_strict_ops = {
|
|||||||
.unlocked_ioctl = cifs_ioctl,
|
.unlocked_ioctl = cifs_ioctl,
|
||||||
#endif /* CONFIG_CIFS_POSIX */
|
#endif /* CONFIG_CIFS_POSIX */
|
||||||
.setlease = cifs_setlease,
|
.setlease = cifs_setlease,
|
||||||
|
.fallocate = cifs_fallocate,
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct file_operations cifs_file_direct_ops = {
|
const struct file_operations cifs_file_direct_ops = {
|
||||||
@ -948,6 +963,7 @@ const struct file_operations cifs_file_direct_ops = {
|
|||||||
#endif /* CONFIG_CIFS_POSIX */
|
#endif /* CONFIG_CIFS_POSIX */
|
||||||
.llseek = cifs_llseek,
|
.llseek = cifs_llseek,
|
||||||
.setlease = cifs_setlease,
|
.setlease = cifs_setlease,
|
||||||
|
.fallocate = cifs_fallocate,
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct file_operations cifs_file_nobrl_ops = {
|
const struct file_operations cifs_file_nobrl_ops = {
|
||||||
@ -966,6 +982,7 @@ const struct file_operations cifs_file_nobrl_ops = {
|
|||||||
.unlocked_ioctl = cifs_ioctl,
|
.unlocked_ioctl = cifs_ioctl,
|
||||||
#endif /* CONFIG_CIFS_POSIX */
|
#endif /* CONFIG_CIFS_POSIX */
|
||||||
.setlease = cifs_setlease,
|
.setlease = cifs_setlease,
|
||||||
|
.fallocate = cifs_fallocate,
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct file_operations cifs_file_strict_nobrl_ops = {
|
const struct file_operations cifs_file_strict_nobrl_ops = {
|
||||||
@ -984,6 +1001,7 @@ const struct file_operations cifs_file_strict_nobrl_ops = {
|
|||||||
.unlocked_ioctl = cifs_ioctl,
|
.unlocked_ioctl = cifs_ioctl,
|
||||||
#endif /* CONFIG_CIFS_POSIX */
|
#endif /* CONFIG_CIFS_POSIX */
|
||||||
.setlease = cifs_setlease,
|
.setlease = cifs_setlease,
|
||||||
|
.fallocate = cifs_fallocate,
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct file_operations cifs_file_direct_nobrl_ops = {
|
const struct file_operations cifs_file_direct_nobrl_ops = {
|
||||||
@ -1003,6 +1021,7 @@ const struct file_operations cifs_file_direct_nobrl_ops = {
|
|||||||
#endif /* CONFIG_CIFS_POSIX */
|
#endif /* CONFIG_CIFS_POSIX */
|
||||||
.llseek = cifs_llseek,
|
.llseek = cifs_llseek,
|
||||||
.setlease = cifs_setlease,
|
.setlease = cifs_setlease,
|
||||||
|
.fallocate = cifs_fallocate,
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct file_operations cifs_dir_ops = {
|
const struct file_operations cifs_dir_ops = {
|
||||||
|
@ -411,6 +411,8 @@ struct smb_version_operations {
|
|||||||
unsigned int *, unsigned int *);
|
unsigned int *, unsigned int *);
|
||||||
/* check if we need to issue closedir */
|
/* check if we need to issue closedir */
|
||||||
bool (*dir_needs_close)(struct cifsFileInfo *);
|
bool (*dir_needs_close)(struct cifsFileInfo *);
|
||||||
|
long (*fallocate)(struct file *, struct cifs_tcon *, int, loff_t,
|
||||||
|
loff_t);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct smb_version_values {
|
struct smb_version_values {
|
||||||
|
@ -1015,6 +1015,50 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon,
|
||||||
|
loff_t offset, loff_t len)
|
||||||
|
{
|
||||||
|
struct inode *inode;
|
||||||
|
struct cifsInodeInfo *cifsi;
|
||||||
|
struct cifsFileInfo *cfile = file->private_data;
|
||||||
|
struct file_zero_data_information fsctl_buf;
|
||||||
|
long rc;
|
||||||
|
unsigned int xid;
|
||||||
|
__u8 set_sparse = 1;
|
||||||
|
|
||||||
|
xid = get_xid();
|
||||||
|
|
||||||
|
inode = cfile->dentry->d_inode;
|
||||||
|
cifsi = CIFS_I(inode);
|
||||||
|
|
||||||
|
/* Need to make file sparse, if not already, before freeing range. */
|
||||||
|
/* Consider adding equivalent for compressed since it could also work */
|
||||||
|
if (!smb2_set_sparse(xid, tcon, cfile, inode, set_sparse))
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
cifs_dbg(FYI, "offset %lld len %lld", offset, len);
|
||||||
|
|
||||||
|
fsctl_buf.FileOffset = cpu_to_le64(offset);
|
||||||
|
fsctl_buf.BeyondFinalZero = cpu_to_le64(offset + len);
|
||||||
|
|
||||||
|
rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
|
||||||
|
cfile->fid.volatile_fid, FSCTL_SET_ZERO_DATA,
|
||||||
|
true /* is_fctl */, (char *)&fsctl_buf,
|
||||||
|
sizeof(struct file_zero_data_information), NULL, NULL);
|
||||||
|
free_xid(xid);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long smb3_fallocate(struct file *file, struct cifs_tcon *tcon, int mode,
|
||||||
|
loff_t off, loff_t len)
|
||||||
|
{
|
||||||
|
/* KEEP_SIZE already checked for by do_fallocate */
|
||||||
|
if (mode & FALLOC_FL_PUNCH_HOLE)
|
||||||
|
return smb3_punch_hole(file, tcon, off, len);
|
||||||
|
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
smb2_downgrade_oplock(struct TCP_Server_Info *server,
|
smb2_downgrade_oplock(struct TCP_Server_Info *server,
|
||||||
struct cifsInodeInfo *cinode, bool set_level2)
|
struct cifsInodeInfo *cinode, bool set_level2)
|
||||||
@ -1463,6 +1507,7 @@ struct smb_version_operations smb30_operations = {
|
|||||||
.validate_negotiate = smb3_validate_negotiate,
|
.validate_negotiate = smb3_validate_negotiate,
|
||||||
.wp_retry_size = smb2_wp_retry_size,
|
.wp_retry_size = smb2_wp_retry_size,
|
||||||
.dir_needs_close = smb2_dir_needs_close,
|
.dir_needs_close = smb2_dir_needs_close,
|
||||||
|
.fallocate = smb3_fallocate,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct smb_version_values smb20_values = {
|
struct smb_version_values smb20_values = {
|
||||||
|
@ -573,6 +573,12 @@ struct copychunk_ioctl {
|
|||||||
__u32 Reserved2;
|
__u32 Reserved2;
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
/* this goes in the ioctl buffer when doing FSCTL_SET_ZERO_DATA */
|
||||||
|
struct file_zero_data_information {
|
||||||
|
__le64 FileOffset;
|
||||||
|
__le64 BeyondFinalZero;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
struct copychunk_ioctl_rsp {
|
struct copychunk_ioctl_rsp {
|
||||||
__le32 ChunksWritten;
|
__le32 ChunksWritten;
|
||||||
__le32 ChunkBytesWritten;
|
__le32 ChunkBytesWritten;
|
||||||
|
@ -63,7 +63,7 @@
|
|||||||
#define FSCTL_SET_OBJECT_ID_EXTENDED 0x000900BC /* BB add struct */
|
#define FSCTL_SET_OBJECT_ID_EXTENDED 0x000900BC /* BB add struct */
|
||||||
#define FSCTL_CREATE_OR_GET_OBJECT_ID 0x000900C0 /* BB add struct */
|
#define FSCTL_CREATE_OR_GET_OBJECT_ID 0x000900C0 /* BB add struct */
|
||||||
#define FSCTL_SET_SPARSE 0x000900C4 /* BB add struct */
|
#define FSCTL_SET_SPARSE 0x000900C4 /* BB add struct */
|
||||||
#define FSCTL_SET_ZERO_DATA 0x000900C8 /* BB add struct */
|
#define FSCTL_SET_ZERO_DATA 0x000980C8
|
||||||
#define FSCTL_SET_ENCRYPTION 0x000900D7 /* BB add struct */
|
#define FSCTL_SET_ENCRYPTION 0x000900D7 /* BB add struct */
|
||||||
#define FSCTL_ENCRYPTION_FSCTL_IO 0x000900DB /* BB add struct */
|
#define FSCTL_ENCRYPTION_FSCTL_IO 0x000900DB /* BB add struct */
|
||||||
#define FSCTL_WRITE_RAW_ENCRYPTED 0x000900DF /* BB add struct */
|
#define FSCTL_WRITE_RAW_ENCRYPTED 0x000900DF /* BB add struct */
|
||||||
|
Loading…
Reference in New Issue
Block a user