Skip to content

Commit

Permalink
CIFS: Request SMB2.1 leases
Browse files Browse the repository at this point in the history
if server supports them and we need oplocks.

Signed-off-by: Pavel Shilovsky <piastryyy@gmail.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
  • Loading branch information
piastry authored and smfrench committed Sep 25, 2012
1 parent 579f905 commit b8c32db
Show file tree
Hide file tree
Showing 8 changed files with 256 additions and 27 deletions.
28 changes: 21 additions & 7 deletions fs/cifs/cifsfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include <linux/kthread.h>
#include <linux/freezer.h>
#include <linux/namei.h>
#include <linux/random.h>
#include <net/ipv6.h>
#include "cifsfs.h"
#include "cifspdu.h"
Expand Down Expand Up @@ -88,6 +89,10 @@ extern mempool_t *cifs_mid_poolp;

struct workqueue_struct *cifsiod_wq;

#ifdef CONFIG_CIFS_SMB2
__u8 cifs_client_guid[SMB2_CLIENT_GUID_SIZE];
#endif

static int
cifs_read_super(struct super_block *sb)
{
Expand Down Expand Up @@ -218,20 +223,25 @@ cifs_alloc_inode(struct super_block *sb)
return NULL;
cifs_inode->cifsAttrs = 0x20; /* default */
cifs_inode->time = 0;
/* Until the file is open and we have gotten oplock
info back from the server, can not assume caching of
file data or metadata */
/*
* Until the file is open and we have gotten oplock info back from the
* server, can not assume caching of file data or metadata.
*/
cifs_set_oplock_level(cifs_inode, 0);
cifs_inode->delete_pending = false;
cifs_inode->invalid_mapping = false;
cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */
cifs_inode->server_eof = 0;
cifs_inode->uniqueid = 0;
cifs_inode->createtime = 0;

/* 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;*/
#ifdef CONFIG_CIFS_SMB2
get_random_bytes(cifs_inode->lease_key, SMB2_LEASE_KEY_SIZE);
#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; */
INIT_LIST_HEAD(&cifs_inode->openFileList);
INIT_LIST_HEAD(&cifs_inode->llist);
return &cifs_inode->vfs_inode;
Expand Down Expand Up @@ -1107,6 +1117,10 @@ init_cifs(void)
spin_lock_init(&cifs_file_list_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) {
cifs_max_pending = 2;
cFYI(1, "cifs_max_pending set to min of 2");
Expand Down
10 changes: 10 additions & 0 deletions fs/cifs/cifsglob.h
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,12 @@ struct smb_version_operations {
const unsigned int);
/* push brlocks from the cache to the server */
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 {
Expand Down Expand Up @@ -895,6 +901,7 @@ struct cifs_fid {
#ifdef CONFIG_CIFS_SMB2
__u64 persistent_fid; /* persist file id for smb2 */
__u64 volatile_fid; /* volatile file id for smb2 */
__u8 lease_key[SMB2_LEASE_KEY_SIZE]; /* lease key for smb2 */
#endif
};

Expand Down Expand Up @@ -1012,6 +1019,9 @@ struct cifsInodeInfo {
u64 server_eof; /* current file size on server -- protected by i_lock */
u64 uniqueid; /* server inode number */
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
struct fscache_cookie *fscache;
#endif
Expand Down
13 changes: 11 additions & 2 deletions fs/cifs/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
xid, &fid->netfid);
if (newinode) {
if (server->ops->set_lease_key)
server->ops->set_lease_key(newinode, fid);
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
newinode->i_mode = mode;
if ((*oplock & CIFS_CREATE_ACTION) &&
Expand Down Expand Up @@ -418,6 +420,9 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry,
tcon = tlink_tcon(tlink);
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, opened);

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

rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode,
&oplock, &fid, &created);
tcon = tlink_tcon(tlink);
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)
server->ops->close(xid, tcon, &fid);

Expand Down
21 changes: 15 additions & 6 deletions fs/cifs/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,9 @@ cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
int disposition;
int create_options = CREATE_NOT_DIR;
FILE_ALL_INFO *buf;
struct TCP_Server_Info *server = tcon->ses->server;

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

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

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

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

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

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,
file->f_flags, &oplock, &fid, xid);
if (rc)
Expand All @@ -440,8 +446,8 @@ int cifs_open(struct inode *inode, struct file *file)

cfile = cifs_new_fileinfo(&fid, file, tlink, oplock);
if (cfile == NULL) {
if (tcon->ses->server->ops->close)
tcon->ses->server->ops->close(xid, tcon, &fid);
if (server->ops->close)
server->ops->close(xid, tcon, &fid);
rc = -ENOMEM;
goto out;
}
Expand Down Expand Up @@ -567,6 +573,9 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush)
if (backup_cred(cifs_sb))
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
* CIFSSMBOpen and then calling get_inode_info with returned buf since
Expand Down
9 changes: 7 additions & 2 deletions fs/cifs/smb2file.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon, const char *path,
int rc;
__le16 *smb2_path;
struct smb2_file_all_info *smb2_data = NULL;
__u8 smb2_oplock[17];

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

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,
&fid->volatile_fid, desired_access, disposition,
0, 0, (__u8 *)oplock, smb2_data);
0, 0, smb2_oplock, smb2_data);
if (rc)
goto out;

Expand All @@ -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);
}

*oplock = *smb2_oplock;
out:
kfree(smb2_data);
kfree(smb2_path);
Expand Down
21 changes: 21 additions & 0 deletions fs/cifs/smb2ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,24 @@ smb2_mand_lock(const unsigned int xid, struct cifsFileInfo *cfile, __u64 offset,
current->tgid, length, offset, type, wait);
}

static void
smb2_get_lease_key(struct inode *inode, struct cifs_fid *fid)
{
memcpy(fid->lease_key, CIFS_I(inode)->lease_key, SMB2_LEASE_KEY_SIZE);
}

static void
smb2_set_lease_key(struct inode *inode, struct cifs_fid *fid)
{
memcpy(CIFS_I(inode)->lease_key, fid->lease_key, SMB2_LEASE_KEY_SIZE);
}

static void
smb2_new_lease_key(struct cifs_fid *fid)
{
get_random_bytes(fid->lease_key, SMB2_LEASE_KEY_SIZE);
}

struct smb_version_operations smb21_operations = {
.compare_fids = smb2_compare_fids,
.setup_request = smb2_setup_request,
Expand Down Expand Up @@ -616,6 +634,9 @@ struct smb_version_operations smb21_operations = {
.mand_lock = smb2_mand_lock,
.mand_unlock_range = smb2_unlock_range,
.push_mand_locks = smb2_push_mandatory_locks,
.get_lease_key = smb2_get_lease_key,
.set_lease_key = smb2_set_lease_key,
.new_lease_key = smb2_new_lease_key,
};

struct smb_version_values smb21_values = {
Expand Down
Loading

0 comments on commit b8c32db

Please sign in to comment.