summaryrefslogtreecommitdiff
path: root/fs/smb/client/smb2inode.c
diff options
context:
space:
mode:
authorMeetakshi Setiya <msetiya@microsoft.com>2024-03-06 06:43:51 +0300
committerSteve French <stfrench@microsoft.com>2024-03-11 03:33:54 +0300
commit2c7d399e551ccfd87bcae4ef5573097f3313d779 (patch)
treed17b01f395a7062d5b40b310e748a40ea3c53eda /fs/smb/client/smb2inode.c
parentdbfdff402d89854126658376cbcb08363194d3cd (diff)
downloadlinux-2c7d399e551ccfd87bcae4ef5573097f3313d779.tar.xz
smb: client: reuse file lease key in compound operations
Currently, when a rename, unlink or set path size compound operation is requested on a file that has a lot of dirty pages to be written to the server, we do not send the lease key for these requests. As a result, the server can assume that this request is from a new client, and send a lease break notification to the same client, on the same connection. As a response to the lease break, the client can consume several credits to write the dirty pages to the server. Depending on the server's credit grant implementation, the server can stop granting more credits to this connection, and this can cause a deadlock (which can only be resolved when the lease timer on the server expires). One of the problems here is that the client is sending no lease key, even if it has a lease for the file. This patch fixes the problem by reusing the existing lease key on the file for rename, unlink and set path size compound operations so that the client does not break its own lease. A very trivial example could be a set of commands by a client that maintains open handle (for write) to a file and then tries to copy the contents of that file to another one, eg., tail -f /dev/null > myfile & mv myfile myfile2 Presently, the network capture on the client shows that the move (or rename) would trigger a lease break on the same client, for the same file. With the lease key reused, the lease break request-response overhead is eliminated, thereby reducing the roundtrips performed for this set of operations. The patch fixes the bug described above and also provides perf benefit. Signed-off-by: Meetakshi Setiya <msetiya@microsoft.com> Signed-off-by: Steve French <stfrench@microsoft.com>
Diffstat (limited to 'fs/smb/client/smb2inode.c')
-rw-r--r--fs/smb/client/smb2inode.c48
1 files changed, 30 insertions, 18 deletions
diff --git a/fs/smb/client/smb2inode.c b/fs/smb/client/smb2inode.c
index 05818cd6d932..69f3442c5b96 100644
--- a/fs/smb/client/smb2inode.c
+++ b/fs/smb/client/smb2inode.c
@@ -98,7 +98,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
__u32 desired_access, __u32 create_disposition,
__u32 create_options, umode_t mode, struct kvec *in_iov,
int *cmds, int num_cmds, struct cifsFileInfo *cfile,
- struct kvec *out_iov, int *out_buftype)
+ struct kvec *out_iov, int *out_buftype, struct dentry *dentry)
{
struct reparse_data_buffer *rbuf;
@@ -115,6 +115,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
int resp_buftype[MAX_COMPOUND];
struct smb2_query_info_rsp *qi_rsp = NULL;
struct cifs_open_info_data *idata;
+ struct inode *inode = NULL;
int flags = 0;
__u8 delete_pending[8] = {1, 0, 0, 0, 0, 0, 0, 0};
unsigned int size[2];
@@ -152,6 +153,15 @@ replay_again:
goto finished;
}
+ /* if there is an existing lease, reuse it */
+ if (dentry) {
+ inode = d_inode(dentry);
+ if (CIFS_I(inode)->lease_granted && server->ops->get_lease_key) {
+ oplock = SMB2_OPLOCK_LEVEL_LEASE;
+ server->ops->get_lease_key(inode, &fid);
+ }
+ }
+
vars->oparms = (struct cifs_open_parms) {
.tcon = tcon,
.path = full_path,
@@ -747,7 +757,7 @@ int smb2_query_path_info(const unsigned int xid,
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
FILE_READ_ATTRIBUTES, FILE_OPEN,
create_options, ACL_NO_MODE, in_iov,
- cmds, 1, cfile, out_iov, out_buftype);
+ cmds, 1, cfile, out_iov, out_buftype, NULL);
hdr = out_iov[0].iov_base;
/*
* If first iov is unset, then SMB session was dropped or we've got a
@@ -779,7 +789,7 @@ int smb2_query_path_info(const unsigned int xid,
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
FILE_READ_ATTRIBUTES, FILE_OPEN,
create_options, ACL_NO_MODE, in_iov,
- cmds, num_cmds, cfile, NULL, NULL);
+ cmds, num_cmds, cfile, NULL, NULL, NULL);
break;
case -EREMOTE:
break;
@@ -811,7 +821,7 @@ smb2_mkdir(const unsigned int xid, struct inode *parent_inode, umode_t mode,
FILE_WRITE_ATTRIBUTES, FILE_CREATE,
CREATE_NOT_FILE, mode,
NULL, &(int){SMB2_OP_MKDIR}, 1,
- NULL, NULL, NULL);
+ NULL, NULL, NULL, NULL);
}
void
@@ -836,7 +846,7 @@ smb2_mkdir_setinfo(struct inode *inode, const char *name,
FILE_WRITE_ATTRIBUTES, FILE_CREATE,
CREATE_NOT_FILE, ACL_NO_MODE, &in_iov,
&(int){SMB2_OP_SET_INFO}, 1,
- cfile, NULL, NULL);
+ cfile, NULL, NULL, NULL);
if (tmprc == 0)
cifs_i->cifsAttrs = dosattrs;
}
@@ -850,25 +860,26 @@ smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
DELETE, FILE_OPEN, CREATE_NOT_FILE,
ACL_NO_MODE, NULL,
&(int){SMB2_OP_RMDIR}, 1,
- NULL, NULL, NULL);
+ NULL, NULL, NULL, NULL);
}
int
smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
- struct cifs_sb_info *cifs_sb)
+ struct cifs_sb_info *cifs_sb, struct dentry *dentry)
{
return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
CREATE_DELETE_ON_CLOSE | OPEN_REPARSE_POINT,
ACL_NO_MODE, NULL,
&(int){SMB2_OP_DELETE}, 1,
- NULL, NULL, NULL);
+ NULL, NULL, NULL, dentry);
}
static int smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
const char *from_name, const char *to_name,
struct cifs_sb_info *cifs_sb,
__u32 create_options, __u32 access,
- int command, struct cifsFileInfo *cfile)
+ int command, struct cifsFileInfo *cfile,
+ struct dentry *dentry)
{
struct kvec in_iov;
__le16 *smb2_to_name = NULL;
@@ -883,7 +894,7 @@ static int smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
in_iov.iov_len = 2 * UniStrnlen((wchar_t *)smb2_to_name, PATH_MAX);
rc = smb2_compound_op(xid, tcon, cifs_sb, from_name, access,
FILE_OPEN, create_options, ACL_NO_MODE,
- &in_iov, &command, 1, cfile, NULL, NULL);
+ &in_iov, &command, 1, cfile, NULL, NULL, dentry);
smb2_rename_path:
kfree(smb2_to_name);
return rc;
@@ -902,7 +913,7 @@ int smb2_rename_path(const unsigned int xid,
cifs_get_writable_path(tcon, from_name, FIND_WR_WITH_DELETE, &cfile);
return smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
- co, DELETE, SMB2_OP_RENAME, cfile);
+ co, DELETE, SMB2_OP_RENAME, cfile, source_dentry);
}
int smb2_create_hardlink(const unsigned int xid,
@@ -915,13 +926,14 @@ int smb2_create_hardlink(const unsigned int xid,
return smb2_set_path_attr(xid, tcon, from_name, to_name,
cifs_sb, co, FILE_READ_ATTRIBUTES,
- SMB2_OP_HARDLINK, NULL);
+ SMB2_OP_HARDLINK, NULL, NULL);
}
int
smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
const char *full_path, __u64 size,
- struct cifs_sb_info *cifs_sb, bool set_alloc)
+ struct cifs_sb_info *cifs_sb, bool set_alloc,
+ struct dentry *dentry)
{
struct cifsFileInfo *cfile;
struct kvec in_iov;
@@ -934,7 +946,7 @@ smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
FILE_WRITE_DATA, FILE_OPEN,
0, ACL_NO_MODE, &in_iov,
&(int){SMB2_OP_SET_EOF}, 1,
- cfile, NULL, NULL);
+ cfile, NULL, NULL, dentry);
}
int
@@ -963,7 +975,7 @@ smb2_set_file_info(struct inode *inode, const char *full_path,
FILE_WRITE_ATTRIBUTES, FILE_OPEN,
0, ACL_NO_MODE, &in_iov,
&(int){SMB2_OP_SET_INFO}, 1,
- cfile, NULL, NULL);
+ cfile, NULL, NULL, NULL);
cifs_put_tlink(tlink);
return rc;
}
@@ -998,7 +1010,7 @@ struct inode *smb2_get_reparse_inode(struct cifs_open_info_data *data,
cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
da, cd, co, ACL_NO_MODE, in_iov,
- cmds, 2, cfile, NULL, NULL);
+ cmds, 2, cfile, NULL, NULL, NULL);
if (!rc) {
rc = smb311_posix_get_inode_info(&new, full_path,
data, sb, xid);
@@ -1008,7 +1020,7 @@ struct inode *smb2_get_reparse_inode(struct cifs_open_info_data *data,
cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
da, cd, co, ACL_NO_MODE, in_iov,
- cmds, 2, cfile, NULL, NULL);
+ cmds, 2, cfile, NULL, NULL, NULL);
if (!rc) {
rc = cifs_get_inode_info(&new, full_path,
data, sb, xid, NULL);
@@ -1036,7 +1048,7 @@ int smb2_query_reparse_point(const unsigned int xid,
FILE_READ_ATTRIBUTES, FILE_OPEN,
OPEN_REPARSE_POINT, ACL_NO_MODE, &in_iov,
&(int){SMB2_OP_GET_REPARSE}, 1,
- cfile, NULL, NULL);
+ cfile, NULL, NULL, NULL);
if (rc)
goto out;