Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b8c32dbb authored by Pavel Shilovsky's avatar Pavel Shilovsky Committed by Steve French
Browse files

CIFS: Request SMB2.1 leases



if server supports them and we need oplocks.

Signed-off-by: default avatarPavel Shilovsky <piastryyy@gmail.com>
Signed-off-by: default avatarSteve French <sfrench@us.ibm.com>
parent 579f9053
Loading
Loading
Loading
Loading
+21 −7
Original line number Original line Diff line number Diff line
@@ -36,6 +36,7 @@
#include <linux/kthread.h>
#include <linux/kthread.h>
#include <linux/freezer.h>
#include <linux/freezer.h>
#include <linux/namei.h>
#include <linux/namei.h>
#include <linux/random.h>
#include <net/ipv6.h>
#include <net/ipv6.h>
#include "cifsfs.h"
#include "cifsfs.h"
#include "cifspdu.h"
#include "cifspdu.h"
@@ -88,6 +89,10 @@ extern mempool_t *cifs_mid_poolp;


struct workqueue_struct	*cifsiod_wq;
struct workqueue_struct	*cifsiod_wq;


#ifdef CONFIG_CIFS_SMB2
__u8 cifs_client_guid[SMB2_CLIENT_GUID_SIZE];
#endif

static int
static int
cifs_read_super(struct super_block *sb)
cifs_read_super(struct super_block *sb)
{
{
@@ -218,9 +223,10 @@ cifs_alloc_inode(struct super_block *sb)
		return NULL;
		return NULL;
	cifs_inode->cifsAttrs = 0x20;	/* default */
	cifs_inode->cifsAttrs = 0x20;	/* default */
	cifs_inode->time = 0;
	cifs_inode->time = 0;
	/* Until the file is open and we have gotten oplock
	/*
	info back from the server, can not assume caching of
	 * Until the file is open and we have gotten oplock info back from the
	file data or metadata */
	 * server, can not assume caching of file data or metadata.
	 */
	cifs_set_oplock_level(cifs_inode, 0);
	cifs_set_oplock_level(cifs_inode, 0);
	cifs_inode->delete_pending = false;
	cifs_inode->delete_pending = false;
	cifs_inode->invalid_mapping = false;
	cifs_inode->invalid_mapping = false;
@@ -228,9 +234,13 @@ cifs_alloc_inode(struct super_block *sb)
	cifs_inode->server_eof = 0;
	cifs_inode->server_eof = 0;
	cifs_inode->uniqueid = 0;
	cifs_inode->uniqueid = 0;
	cifs_inode->createtime = 0;
	cifs_inode->createtime = 0;

#ifdef CONFIG_CIFS_SMB2
	/* Can not set i_flags here - they get immediately overwritten
	get_random_bytes(cifs_inode->lease_key, SMB2_LEASE_KEY_SIZE);
	   to zero by the VFS */
#endif
	/*
	 * Can not set i_flags here - they get immediately overwritten to zero
	 * by the VFS.
	 */
	/* cifs_inode->vfs_inode.i_flags = S_NOATIME | S_NOCMTIME; */
	/* cifs_inode->vfs_inode.i_flags = S_NOATIME | S_NOCMTIME; */
	INIT_LIST_HEAD(&cifs_inode->openFileList);
	INIT_LIST_HEAD(&cifs_inode->openFileList);
	INIT_LIST_HEAD(&cifs_inode->llist);
	INIT_LIST_HEAD(&cifs_inode->llist);
@@ -1107,6 +1117,10 @@ init_cifs(void)
	spin_lock_init(&cifs_file_list_lock);
	spin_lock_init(&cifs_file_list_lock);
	spin_lock_init(&GlobalMid_Lock);
	spin_lock_init(&GlobalMid_Lock);


#ifdef CONFIG_CIFS_SMB2
	get_random_bytes(cifs_client_guid, SMB2_CLIENT_GUID_SIZE);
#endif

	if (cifs_max_pending < 2) {
	if (cifs_max_pending < 2) {
		cifs_max_pending = 2;
		cifs_max_pending = 2;
		cFYI(1, "cifs_max_pending set to min of 2");
		cFYI(1, "cifs_max_pending set to min of 2");
+10 −0
Original line number Original line Diff line number Diff line
@@ -361,6 +361,12 @@ struct smb_version_operations {
				 const unsigned int);
				 const unsigned int);
	/* push brlocks from the cache to the server */
	/* push brlocks from the cache to the server */
	int (*push_mand_locks)(struct cifsFileInfo *);
	int (*push_mand_locks)(struct cifsFileInfo *);
	/* get lease key of the inode */
	void (*get_lease_key)(struct inode *, struct cifs_fid *fid);
	/* set lease key of the inode */
	void (*set_lease_key)(struct inode *, struct cifs_fid *fid);
	/* generate new lease key */
	void (*new_lease_key)(struct cifs_fid *fid);
};
};


struct smb_version_values {
struct smb_version_values {
@@ -895,6 +901,7 @@ struct cifs_fid {
#ifdef CONFIG_CIFS_SMB2
#ifdef CONFIG_CIFS_SMB2
	__u64 persistent_fid;	/* persist file id for smb2 */
	__u64 persistent_fid;	/* persist file id for smb2 */
	__u64 volatile_fid;	/* volatile file id for smb2 */
	__u64 volatile_fid;	/* volatile file id for smb2 */
	__u8 lease_key[SMB2_LEASE_KEY_SIZE];	/* lease key for smb2 */
#endif
#endif
};
};


@@ -1012,6 +1019,9 @@ struct cifsInodeInfo {
	u64  server_eof;		/* current file size on server -- protected by i_lock */
	u64  server_eof;		/* current file size on server -- protected by i_lock */
	u64  uniqueid;			/* server inode number */
	u64  uniqueid;			/* server inode number */
	u64  createtime;		/* creation time on server */
	u64  createtime;		/* creation time on server */
#ifdef CONFIG_CIFS_SMB2
	__u8 lease_key[SMB2_LEASE_KEY_SIZE];	/* lease key for this inode */
#endif
#ifdef CONFIG_CIFS_FSCACHE
#ifdef CONFIG_CIFS_FSCACHE
	struct fscache_cookie *fscache;
	struct fscache_cookie *fscache;
#endif
#endif
+11 −2
Original line number Original line Diff line number Diff line
@@ -340,6 +340,8 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
		rc = cifs_get_inode_info(&newinode, full_path, buf, inode->i_sb,
		rc = cifs_get_inode_info(&newinode, full_path, buf, inode->i_sb,
					 xid, &fid->netfid);
					 xid, &fid->netfid);
		if (newinode) {
		if (newinode) {
			if (server->ops->set_lease_key)
				server->ops->set_lease_key(newinode, fid);
			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
				newinode->i_mode = mode;
				newinode->i_mode = mode;
			if ((*oplock & CIFS_CREATE_ACTION) &&
			if ((*oplock & CIFS_CREATE_ACTION) &&
@@ -418,6 +420,9 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry,
	tcon = tlink_tcon(tlink);
	tcon = tlink_tcon(tlink);
	server = tcon->ses->server;
	server = tcon->ses->server;


	if (server->ops->new_lease_key)
		server->ops->new_lease_key(&fid);

	rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode,
	rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode,
			    &oplock, &fid, opened);
			    &oplock, &fid, opened);


@@ -473,10 +478,14 @@ int cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode,
	if (IS_ERR(tlink))
	if (IS_ERR(tlink))
		goto out_free_xid;
		goto out_free_xid;


	rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode,
			    &oplock, &fid, &created);
	tcon = tlink_tcon(tlink);
	tcon = tlink_tcon(tlink);
	server = tcon->ses->server;
	server = tcon->ses->server;

	if (server->ops->new_lease_key)
		server->ops->new_lease_key(&fid);

	rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode,
			    &oplock, &fid, &created);
	if (!rc && server->ops->close)
	if (!rc && server->ops->close)
		server->ops->close(xid, tcon, &fid);
		server->ops->close(xid, tcon, &fid);


+15 −6
Original line number Original line Diff line number Diff line
@@ -177,8 +177,9 @@ cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
	int disposition;
	int disposition;
	int create_options = CREATE_NOT_DIR;
	int create_options = CREATE_NOT_DIR;
	FILE_ALL_INFO *buf;
	FILE_ALL_INFO *buf;
	struct TCP_Server_Info *server = tcon->ses->server;


	if (!tcon->ses->server->ops->open)
	if (!server->ops->open)
		return -ENOSYS;
		return -ENOSYS;


	desired_access = cifs_convert_flags(f_flags);
	desired_access = cifs_convert_flags(f_flags);
@@ -218,9 +219,9 @@ cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
	if (backup_cred(cifs_sb))
	if (backup_cred(cifs_sb))
		create_options |= CREATE_OPEN_BACKUP_INTENT;
		create_options |= CREATE_OPEN_BACKUP_INTENT;


	rc = tcon->ses->server->ops->open(xid, tcon, full_path, disposition,
	rc = server->ops->open(xid, tcon, full_path, disposition,
					  desired_access, create_options, fid,
			       desired_access, create_options, fid, oplock, buf,
					  oplock, buf, cifs_sb);
			       cifs_sb);


	if (rc)
	if (rc)
		goto out;
		goto out;
@@ -372,6 +373,7 @@ int cifs_open(struct inode *inode, struct file *file)
	unsigned int xid;
	unsigned int xid;
	__u32 oplock;
	__u32 oplock;
	struct cifs_sb_info *cifs_sb;
	struct cifs_sb_info *cifs_sb;
	struct TCP_Server_Info *server;
	struct cifs_tcon *tcon;
	struct cifs_tcon *tcon;
	struct tcon_link *tlink;
	struct tcon_link *tlink;
	struct cifsFileInfo *cfile = NULL;
	struct cifsFileInfo *cfile = NULL;
@@ -388,6 +390,7 @@ int cifs_open(struct inode *inode, struct file *file)
		return PTR_ERR(tlink);
		return PTR_ERR(tlink);
	}
	}
	tcon = tlink_tcon(tlink);
	tcon = tlink_tcon(tlink);
	server = tcon->ses->server;


	full_path = build_path_from_dentry(file->f_path.dentry);
	full_path = build_path_from_dentry(file->f_path.dentry);
	if (full_path == NULL) {
	if (full_path == NULL) {
@@ -432,6 +435,9 @@ int cifs_open(struct inode *inode, struct file *file)
	}
	}


	if (!posix_open_ok) {
	if (!posix_open_ok) {
		if (server->ops->get_lease_key)
			server->ops->get_lease_key(inode, &fid);

		rc = cifs_nt_open(full_path, inode, cifs_sb, tcon,
		rc = cifs_nt_open(full_path, inode, cifs_sb, tcon,
				  file->f_flags, &oplock, &fid, xid);
				  file->f_flags, &oplock, &fid, xid);
		if (rc)
		if (rc)
@@ -440,8 +446,8 @@ int cifs_open(struct inode *inode, struct file *file)


	cfile = cifs_new_fileinfo(&fid, file, tlink, oplock);
	cfile = cifs_new_fileinfo(&fid, file, tlink, oplock);
	if (cfile == NULL) {
	if (cfile == NULL) {
		if (tcon->ses->server->ops->close)
		if (server->ops->close)
			tcon->ses->server->ops->close(xid, tcon, &fid);
			server->ops->close(xid, tcon, &fid);
		rc = -ENOMEM;
		rc = -ENOMEM;
		goto out;
		goto out;
	}
	}
@@ -567,6 +573,9 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush)
	if (backup_cred(cifs_sb))
	if (backup_cred(cifs_sb))
		create_options |= CREATE_OPEN_BACKUP_INTENT;
		create_options |= CREATE_OPEN_BACKUP_INTENT;


	if (server->ops->get_lease_key)
		server->ops->get_lease_key(inode, &fid);

	/*
	/*
	 * Can not refresh inode by passing in file_info buf to be returned by
	 * Can not refresh inode by passing in file_info buf to be returned by
	 * CIFSSMBOpen and then calling get_inode_info with returned buf since
	 * CIFSSMBOpen and then calling get_inode_info with returned buf since
+7 −2
Original line number Original line Diff line number Diff line
@@ -63,6 +63,7 @@ smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon, const char *path,
	int rc;
	int rc;
	__le16 *smb2_path;
	__le16 *smb2_path;
	struct smb2_file_all_info *smb2_data = NULL;
	struct smb2_file_all_info *smb2_data = NULL;
	__u8 smb2_oplock[17];


	smb2_path = cifs_convert_path_to_utf16(path, cifs_sb);
	smb2_path = cifs_convert_path_to_utf16(path, cifs_sb);
	if (smb2_path == NULL) {
	if (smb2_path == NULL) {
@@ -78,11 +79,14 @@ smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon, const char *path,
	}
	}


	desired_access |= FILE_READ_ATTRIBUTES;
	desired_access |= FILE_READ_ATTRIBUTES;
	*oplock = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
	*smb2_oplock = SMB2_OPLOCK_LEVEL_EXCLUSIVE;

	if (tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_LEASING)
		memcpy(smb2_oplock + 1, fid->lease_key, SMB2_LEASE_KEY_SIZE);


	rc = SMB2_open(xid, tcon, smb2_path, &fid->persistent_fid,
	rc = SMB2_open(xid, tcon, smb2_path, &fid->persistent_fid,
		       &fid->volatile_fid, desired_access, disposition,
		       &fid->volatile_fid, desired_access, disposition,
		       0, 0, (__u8 *)oplock, smb2_data);
		       0, 0, smb2_oplock, smb2_data);
	if (rc)
	if (rc)
		goto out;
		goto out;


@@ -99,6 +103,7 @@ smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon, const char *path,
		move_smb2_info_to_cifs(buf, smb2_data);
		move_smb2_info_to_cifs(buf, smb2_data);
	}
	}


	*oplock = *smb2_oplock;
out:
out:
	kfree(smb2_data);
	kfree(smb2_data);
	kfree(smb2_path);
	kfree(smb2_path);
Loading