Skip to content

Commit 71f15c9

Browse files
meetakshi253Steve French
authored and
Steve French
committed
smb: client: retry compound request without reusing lease
There is a shortcoming in the current implementation of the file lease mechanism exposed when the lease keys were attempted to be reused for unlink, rename and set_path_size operations for a client. As per MS-SMB2, lease keys are associated with the file name. Linux smb client maintains lease keys with the inode. If the file has any hardlinks, it is possible that the lease for a file be wrongly reused for an operation on the hardlink or vice versa. In these cases, the mentioned compound operations fail with STATUS_INVALID_PARAMETER. This patch adds a fallback to the old mechanism of not sending any lease with these compound operations if the request with lease key fails with STATUS_INVALID_PARAMETER. Resending the same request without lease key should not hurt any functionality, but might impact performance especially in cases where the error is not because of the usage of wrong lease key and we might end up doing an extra roundtrip. Signed-off-by: Meetakshi Setiya <[email protected]> Signed-off-by: Steve French <[email protected]>
1 parent ffceb76 commit 71f15c9

File tree

1 file changed

+38
-3
lines changed

1 file changed

+38
-3
lines changed

fs/smb/client/smb2inode.c

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,17 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
154154
}
155155

156156
/* if there is an existing lease, reuse it */
157+
158+
/*
159+
* note: files with hardlinks cause unexpected behaviour. As per MS-SMB2,
160+
* lease keys are associated with the filepath. We are maintaining lease keys
161+
* with the inode on the client. If the file has hardlinks, it is possible
162+
* that the lease for a file be reused for an operation on its hardlink or
163+
* vice versa.
164+
* As a workaround, send request using an existing lease key and if the server
165+
* returns STATUS_INVALID_PARAMETER, which maps to EINVAL, send the request
166+
* again without the lease.
167+
*/
157168
if (dentry) {
158169
inode = d_inode(dentry);
159170
if (CIFS_I(inode)->lease_granted && server->ops->get_lease_key) {
@@ -874,11 +885,20 @@ int
874885
smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
875886
struct cifs_sb_info *cifs_sb, struct dentry *dentry)
876887
{
877-
return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
888+
int rc = smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
878889
CREATE_DELETE_ON_CLOSE | OPEN_REPARSE_POINT,
879890
ACL_NO_MODE, NULL,
880891
&(int){SMB2_OP_DELETE}, 1,
881892
NULL, NULL, NULL, dentry);
893+
if (rc == -EINVAL) {
894+
cifs_dbg(FYI, "invalid lease key, resending request without lease");
895+
rc = smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
896+
CREATE_DELETE_ON_CLOSE | OPEN_REPARSE_POINT,
897+
ACL_NO_MODE, NULL,
898+
&(int){SMB2_OP_DELETE}, 1,
899+
NULL, NULL, NULL, NULL);
900+
}
901+
return rc;
882902
}
883903

884904
static int smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
@@ -919,8 +939,14 @@ int smb2_rename_path(const unsigned int xid,
919939
drop_cached_dir_by_name(xid, tcon, from_name, cifs_sb);
920940
cifs_get_writable_path(tcon, from_name, FIND_WR_WITH_DELETE, &cfile);
921941

922-
return smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
942+
int rc = smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
923943
co, DELETE, SMB2_OP_RENAME, cfile, source_dentry);
944+
if (rc == -EINVAL) {
945+
cifs_dbg(FYI, "invalid lease key, resending request without lease");
946+
rc = smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
947+
co, DELETE, SMB2_OP_RENAME, cfile, NULL);
948+
}
949+
return rc;
924950
}
925951

926952
int smb2_create_hardlink(const unsigned int xid,
@@ -949,11 +975,20 @@ smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
949975
in_iov.iov_base = &eof;
950976
in_iov.iov_len = sizeof(eof);
951977
cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
952-
return smb2_compound_op(xid, tcon, cifs_sb, full_path,
978+
int rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
953979
FILE_WRITE_DATA, FILE_OPEN,
954980
0, ACL_NO_MODE, &in_iov,
955981
&(int){SMB2_OP_SET_EOF}, 1,
956982
cfile, NULL, NULL, dentry);
983+
if (rc == -EINVAL) {
984+
cifs_dbg(FYI, "invalid lease key, resending request without lease");
985+
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
986+
FILE_WRITE_DATA, FILE_OPEN,
987+
0, ACL_NO_MODE, &in_iov,
988+
&(int){SMB2_OP_SET_EOF}, 1,
989+
cfile, NULL, NULL, NULL);
990+
}
991+
return rc;
957992
}
958993

959994
int

0 commit comments

Comments
 (0)