Skip to content

Commit

Permalink
Enable previous version support
Browse files Browse the repository at this point in the history
Add ioctl to query previous versions of file

Allows listing snapshots on files on SMB3 mounts.

Signed-off-by: Steve French <smfrench@gmail.com>
  • Loading branch information
smfrench committed Oct 14, 2016
1 parent 18dd8e1 commit 834170c
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 2 deletions.
8 changes: 8 additions & 0 deletions fs/cifs/cifs_ioctl.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,15 @@ struct smb_mnt_fs_info {
__u64 cifs_posix_caps;
} __packed;

struct smb_snapshot_array {
__u32 number_of_snapshots;
__u32 number_of_snapshots_returned;
__u32 snapshot_array_size;
/* snapshots[]; */
} __packed;

#define CIFS_IOCTL_MAGIC 0xCF
#define CIFS_IOC_COPYCHUNK_FILE _IOW(CIFS_IOCTL_MAGIC, 3, int)
#define CIFS_IOC_SET_INTEGRITY _IO(CIFS_IOCTL_MAGIC, 4)
#define CIFS_IOC_GET_MNT_INFO _IOR(CIFS_IOCTL_MAGIC, 5, struct smb_mnt_fs_info)
#define CIFS_ENUMERATE_SNAPSHOTS _IOR(CIFS_IOCTL_MAGIC, 6, struct smb_snapshot_array)
2 changes: 2 additions & 0 deletions fs/cifs/cifsglob.h
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,8 @@ struct smb_version_operations {
int (*calc_signature)(struct smb_rqst *, struct TCP_Server_Info *);
int (*set_integrity)(const unsigned int, struct cifs_tcon *tcon,
struct cifsFileInfo *src_file);
int (*enum_snapshots)(const unsigned int xid, struct cifs_tcon *tcon,
struct cifsFileInfo *src_file, void __user *);
int (*query_mf_symlink)(unsigned int, struct cifs_tcon *,
struct cifs_sb_info *, const unsigned char *,
char *, unsigned int *);
Expand Down
16 changes: 14 additions & 2 deletions fs/cifs/ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
xid = get_xid();

cifs_sb = CIFS_SB(inode->i_sb);

cifs_dbg(VFS, "cifs ioctl 0x%x\n", command);
switch (command) {
case FS_IOC_GETFLAGS:
if (pSMBFile == NULL)
Expand Down Expand Up @@ -267,11 +267,23 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
tcon = tlink_tcon(pSMBFile->tlink);
rc = smb_mnt_get_fsinfo(xid, tcon, (void __user *)arg);
break;
case CIFS_ENUMERATE_SNAPSHOTS:
if (arg == 0) {
rc = -EINVAL;
goto cifs_ioc_exit;
}
tcon = tlink_tcon(pSMBFile->tlink);
if (tcon->ses->server->ops->enum_snapshots)
rc = tcon->ses->server->ops->enum_snapshots(xid, tcon,
pSMBFile, (void __user *)arg);
else
rc = -EOPNOTSUPP;
break;
default:
cifs_dbg(FYI, "unsupported ioctl\n");
break;
}

cifs_ioc_exit:
free_xid(xid);
return rc;
}
48 changes: 48 additions & 0 deletions fs/cifs/smb2ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "cifs_unicode.h"
#include "smb2status.h"
#include "smb2glob.h"
#include "cifs_ioctl.h"

static int
change_conf(struct TCP_Server_Info *server)
Expand Down Expand Up @@ -894,6 +895,50 @@ smb3_set_integrity(const unsigned int xid, struct cifs_tcon *tcon,

}

static int
smb3_enum_snapshots(const unsigned int xid, struct cifs_tcon *tcon,
struct cifsFileInfo *cfile, void __user *ioc_buf)
{
char *retbuf = NULL;
unsigned int ret_data_len = 0;
int rc;
struct smb_snapshot_array snapshot_in;

rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
cfile->fid.volatile_fid,
FSCTL_SRV_ENUMERATE_SNAPSHOTS,
true /* is_fsctl */, NULL, 0 /* no input data */,
(char **)&retbuf,
&ret_data_len);
cifs_dbg(FYI, "enum snaphots ioctl returned %d and ret buflen is %d\n",
rc, ret_data_len);
if (rc)
return rc;

if (ret_data_len && (ioc_buf != NULL) && (retbuf != NULL)) {
/* Fixup buffer */
if (copy_from_user(&snapshot_in, ioc_buf,
sizeof(struct smb_snapshot_array))) {
rc = -EFAULT;
kfree(retbuf);
return rc;
}
if (snapshot_in.snapshot_array_size < sizeof(struct smb_snapshot_array)) {
rc = -ERANGE;
return rc;
}

if (ret_data_len > snapshot_in.snapshot_array_size)
ret_data_len = snapshot_in.snapshot_array_size;

if (copy_to_user(ioc_buf, retbuf, ret_data_len))
rc = -EFAULT;
}

kfree(retbuf);
return rc;
}

static int
smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
const char *path, struct cifs_sb_info *cifs_sb,
Expand Down Expand Up @@ -1659,6 +1704,7 @@ struct smb_version_operations smb21_operations = {
.clone_range = smb2_clone_range,
.wp_retry_size = smb2_wp_retry_size,
.dir_needs_close = smb2_dir_needs_close,
.enum_snapshots = smb3_enum_snapshots,
};

struct smb_version_operations smb30_operations = {
Expand Down Expand Up @@ -1745,6 +1791,7 @@ struct smb_version_operations smb30_operations = {
.wp_retry_size = smb2_wp_retry_size,
.dir_needs_close = smb2_dir_needs_close,
.fallocate = smb3_fallocate,
.enum_snapshots = smb3_enum_snapshots,
};

#ifdef CONFIG_CIFS_SMB311
Expand Down Expand Up @@ -1832,6 +1879,7 @@ struct smb_version_operations smb311_operations = {
.wp_retry_size = smb2_wp_retry_size,
.dir_needs_close = smb2_dir_needs_close,
.fallocate = smb3_fallocate,
.enum_snapshots = smb3_enum_snapshots,
};
#endif /* CIFS_SMB311 */

Expand Down

0 comments on commit 834170c

Please sign in to comment.