2021-06-18 13:31:49 +08:00
|
|
|
// SPDX-License-Identifier: LGPL-2.1
|
2011-12-29 21:06:33 +08:00
|
|
|
/*
|
|
|
|
*
|
|
|
|
* Copyright (C) International Business Machines Corp., 2002, 2011
|
|
|
|
* Etersoft, 2012
|
|
|
|
* Author(s): Pavel Shilovsky (pshilovsky@samba.org),
|
|
|
|
* Steve French (sfrench@us.ibm.com)
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
#include <linux/fs.h>
|
|
|
|
#include <linux/stat.h>
|
|
|
|
#include <linux/slab.h>
|
|
|
|
#include <linux/pagemap.h>
|
|
|
|
#include <asm/div64.h>
|
|
|
|
#include "cifsfs.h"
|
|
|
|
#include "cifspdu.h"
|
|
|
|
#include "cifsglob.h"
|
|
|
|
#include "cifsproto.h"
|
|
|
|
#include "cifs_debug.h"
|
|
|
|
#include "cifs_fs_sb.h"
|
|
|
|
#include "cifs_unicode.h"
|
|
|
|
#include "fscache.h"
|
|
|
|
#include "smb2glob.h"
|
|
|
|
#include "smb2pdu.h"
|
|
|
|
#include "smb2proto.h"
|
2022-08-11 11:00:08 +08:00
|
|
|
#include "cached_dir.h"
|
2022-10-04 05:43:50 +08:00
|
|
|
#include "smb2status.h"
|
2011-12-29 21:06:33 +08:00
|
|
|
|
2023-11-26 10:55:05 +08:00
|
|
|
static struct reparse_data_buffer *reparse_buf_ptr(struct kvec *iov)
|
|
|
|
{
|
|
|
|
struct reparse_data_buffer *buf;
|
|
|
|
struct smb2_ioctl_rsp *io = iov->iov_base;
|
|
|
|
u32 off, count, len;
|
|
|
|
|
|
|
|
count = le32_to_cpu(io->OutputCount);
|
|
|
|
off = le32_to_cpu(io->OutputOffset);
|
|
|
|
if (check_add_overflow(off, count, &len) || len > iov->iov_len)
|
|
|
|
return ERR_PTR(-EIO);
|
|
|
|
|
|
|
|
buf = (struct reparse_data_buffer *)((u8 *)io + off);
|
|
|
|
len = sizeof(*buf);
|
|
|
|
if (count < len || count < le16_to_cpu(buf->ReparseDataLength) + len)
|
|
|
|
return ERR_PTR(-EIO);
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
2023-11-26 10:55:07 +08:00
|
|
|
static inline __u32 file_create_options(struct dentry *dentry)
|
|
|
|
{
|
|
|
|
struct cifsInodeInfo *ci;
|
|
|
|
|
|
|
|
if (dentry) {
|
|
|
|
ci = CIFS_I(d_inode(dentry));
|
|
|
|
if (ci->cifsAttrs & ATTR_REPARSE)
|
|
|
|
return OPEN_REPARSE_POINT;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2024-01-19 12:08:27 +08:00
|
|
|
/* Parse owner and group from SMB3.1.1 POSIX query info */
|
|
|
|
static int parse_posix_sids(struct cifs_open_info_data *data,
|
|
|
|
struct kvec *rsp_iov)
|
|
|
|
{
|
|
|
|
struct smb2_query_info_rsp *qi = rsp_iov->iov_base;
|
|
|
|
unsigned int out_len = le32_to_cpu(qi->OutputBufferLength);
|
|
|
|
unsigned int qi_len = sizeof(data->posix_fi);
|
|
|
|
int owner_len, group_len;
|
|
|
|
u8 *sidsbuf, *sidsbuf_end;
|
|
|
|
|
|
|
|
if (out_len <= qi_len)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
sidsbuf = (u8 *)qi + le16_to_cpu(qi->OutputBufferOffset) + qi_len;
|
|
|
|
sidsbuf_end = sidsbuf + out_len - qi_len;
|
|
|
|
|
|
|
|
owner_len = posix_info_sid_size(sidsbuf, sidsbuf_end);
|
|
|
|
if (owner_len == -1)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
memcpy(&data->posix_owner, sidsbuf, owner_len);
|
|
|
|
group_len = posix_info_sid_size(sidsbuf + owner_len, sidsbuf_end);
|
|
|
|
if (group_len == -1)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
memcpy(&data->posix_group, sidsbuf + owner_len, group_len);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2024-01-28 12:12:01 +08:00
|
|
|
struct wsl_query_ea {
|
|
|
|
__le32 next;
|
|
|
|
__u8 name_len;
|
|
|
|
__u8 name[SMB2_WSL_XATTR_NAME_LEN + 1];
|
|
|
|
} __packed;
|
|
|
|
|
|
|
|
#define NEXT_OFF cpu_to_le32(sizeof(struct wsl_query_ea))
|
|
|
|
|
|
|
|
static const struct wsl_query_ea wsl_query_eas[] = {
|
|
|
|
{ .next = NEXT_OFF, .name_len = SMB2_WSL_XATTR_NAME_LEN, .name = SMB2_WSL_XATTR_UID, },
|
|
|
|
{ .next = NEXT_OFF, .name_len = SMB2_WSL_XATTR_NAME_LEN, .name = SMB2_WSL_XATTR_GID, },
|
|
|
|
{ .next = NEXT_OFF, .name_len = SMB2_WSL_XATTR_NAME_LEN, .name = SMB2_WSL_XATTR_MODE, },
|
|
|
|
{ .next = 0, .name_len = SMB2_WSL_XATTR_NAME_LEN, .name = SMB2_WSL_XATTR_DEV, },
|
|
|
|
};
|
|
|
|
|
|
|
|
static int check_wsl_eas(struct kvec *rsp_iov)
|
|
|
|
{
|
|
|
|
struct smb2_file_full_ea_info *ea;
|
|
|
|
struct smb2_query_info_rsp *rsp = rsp_iov->iov_base;
|
|
|
|
unsigned long addr;
|
|
|
|
u32 outlen, next;
|
|
|
|
u16 vlen;
|
|
|
|
u8 nlen;
|
|
|
|
u8 *end;
|
|
|
|
|
|
|
|
outlen = le32_to_cpu(rsp->OutputBufferLength);
|
|
|
|
if (outlen < SMB2_WSL_MIN_QUERY_EA_RESP_SIZE ||
|
|
|
|
outlen > SMB2_WSL_MAX_QUERY_EA_RESP_SIZE)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
ea = (void *)((u8 *)rsp_iov->iov_base +
|
|
|
|
le16_to_cpu(rsp->OutputBufferOffset));
|
|
|
|
end = (u8 *)rsp_iov->iov_base + rsp_iov->iov_len;
|
|
|
|
for (;;) {
|
|
|
|
if ((u8 *)ea > end - sizeof(*ea))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
nlen = ea->ea_name_length;
|
|
|
|
vlen = le16_to_cpu(ea->ea_value_length);
|
|
|
|
if (nlen != SMB2_WSL_XATTR_NAME_LEN ||
|
|
|
|
(u8 *)ea + nlen + 1 + vlen > end)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
switch (vlen) {
|
|
|
|
case 4:
|
|
|
|
if (strncmp(ea->ea_data, SMB2_WSL_XATTR_UID, nlen) &&
|
|
|
|
strncmp(ea->ea_data, SMB2_WSL_XATTR_GID, nlen) &&
|
|
|
|
strncmp(ea->ea_data, SMB2_WSL_XATTR_MODE, nlen))
|
|
|
|
return -EINVAL;
|
|
|
|
break;
|
|
|
|
case 8:
|
|
|
|
if (strncmp(ea->ea_data, SMB2_WSL_XATTR_DEV, nlen))
|
|
|
|
return -EINVAL;
|
|
|
|
break;
|
|
|
|
case 0:
|
|
|
|
if (!strncmp(ea->ea_data, SMB2_WSL_XATTR_UID, nlen) ||
|
|
|
|
!strncmp(ea->ea_data, SMB2_WSL_XATTR_GID, nlen) ||
|
|
|
|
!strncmp(ea->ea_data, SMB2_WSL_XATTR_MODE, nlen) ||
|
|
|
|
!strncmp(ea->ea_data, SMB2_WSL_XATTR_DEV, nlen))
|
|
|
|
break;
|
|
|
|
fallthrough;
|
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
next = le32_to_cpu(ea->next_entry_offset);
|
|
|
|
if (!next)
|
|
|
|
break;
|
|
|
|
if (!IS_ALIGNED(next, 4) ||
|
|
|
|
check_add_overflow((unsigned long)ea, next, &addr))
|
|
|
|
return -EINVAL;
|
|
|
|
ea = (void *)addr;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-07-30 14:43:09 +08:00
|
|
|
/*
|
|
|
|
* note: If cfile is passed, the reference to it is dropped here.
|
|
|
|
* So make sure that you do not reuse cfile after return from this func.
|
2022-10-04 05:43:50 +08:00
|
|
|
*
|
2023-08-17 23:34:02 +08:00
|
|
|
* If passing @out_iov and @out_buftype, ensure to make them both large enough
|
|
|
|
* (>= 3) to hold all compounded responses. Caller is also responsible for
|
|
|
|
* freeing them up with free_rsp_buf().
|
2021-07-30 14:43:09 +08:00
|
|
|
*/
|
2022-10-04 05:43:50 +08:00
|
|
|
static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
|
struct cifs_sb_info *cifs_sb, const char *full_path,
|
2024-01-26 06:21:48 +08:00
|
|
|
struct cifs_open_parms *oparms, struct kvec *in_iov,
|
2023-11-26 10:55:02 +08:00
|
|
|
int *cmds, int num_cmds, struct cifsFileInfo *cfile,
|
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>
2024-03-06 11:43:51 +08:00
|
|
|
struct kvec *out_iov, int *out_buftype, struct dentry *dentry)
|
2018-09-03 11:33:41 +08:00
|
|
|
{
|
2023-11-26 10:55:05 +08:00
|
|
|
|
|
|
|
struct reparse_data_buffer *rbuf;
|
2023-08-17 23:34:13 +08:00
|
|
|
struct smb2_compound_vars *vars = NULL;
|
2023-11-26 10:55:05 +08:00
|
|
|
struct kvec *rsp_iov, *iov;
|
2020-05-20 10:19:59 +08:00
|
|
|
struct smb_rqst *rqst;
|
2018-09-03 11:33:41 +08:00
|
|
|
int rc;
|
|
|
|
__le16 *utf16_path = NULL;
|
|
|
|
__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
|
|
|
struct cifs_fid fid;
|
|
|
|
struct cifs_ses *ses = tcon->ses;
|
2020-06-01 01:38:22 +08:00
|
|
|
struct TCP_Server_Info *server;
|
2023-11-26 10:55:02 +08:00
|
|
|
int num_rqst = 0, i;
|
|
|
|
int resp_buftype[MAX_COMPOUND];
|
2018-09-03 11:33:45 +08:00
|
|
|
struct smb2_query_info_rsp *qi_rsp = NULL;
|
2022-10-04 05:43:50 +08:00
|
|
|
struct cifs_open_info_data *idata;
|
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>
2024-03-06 11:43:51 +08:00
|
|
|
struct inode *inode = NULL;
|
2018-09-03 11:33:41 +08:00
|
|
|
int flags = 0;
|
2018-09-03 11:33:45 +08:00
|
|
|
__u8 delete_pending[8] = {1, 0, 0, 0, 0, 0, 0, 0};
|
2018-09-03 11:33:49 +08:00
|
|
|
unsigned int size[2];
|
|
|
|
void *data[2];
|
2024-01-28 12:12:01 +08:00
|
|
|
unsigned int len;
|
2024-01-21 11:32:47 +08:00
|
|
|
int retries = 0, cur_sleep = 1;
|
|
|
|
|
|
|
|
replay_again:
|
|
|
|
/* reinitialize for possible replay */
|
|
|
|
flags = 0;
|
|
|
|
oplock = SMB2_OPLOCK_LEVEL_NONE;
|
|
|
|
num_rqst = 0;
|
|
|
|
server = cifs_pick_channel(ses);
|
2018-09-03 11:33:41 +08:00
|
|
|
|
2020-05-20 10:19:59 +08:00
|
|
|
vars = kzalloc(sizeof(*vars), GFP_ATOMIC);
|
|
|
|
if (vars == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
rqst = &vars->rqst[0];
|
|
|
|
rsp_iov = &vars->rsp_iov[0];
|
|
|
|
|
2018-09-03 11:33:41 +08:00
|
|
|
if (smb3_encryption_required(tcon))
|
|
|
|
flags |= CIFS_TRANSFORM_REQ;
|
|
|
|
|
2023-11-26 10:55:02 +08:00
|
|
|
for (i = 0; i < ARRAY_SIZE(resp_buftype); i++)
|
|
|
|
resp_buftype[i] = CIFS_NO_BUFFER;
|
2018-09-03 11:33:41 +08:00
|
|
|
|
2019-08-30 06:25:46 +08:00
|
|
|
/* We already have a handle so we can skip the open */
|
|
|
|
if (cfile)
|
|
|
|
goto after_open;
|
|
|
|
|
2018-09-03 11:33:41 +08:00
|
|
|
/* Open */
|
|
|
|
utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
|
2019-08-30 06:25:46 +08:00
|
|
|
if (!utf16_path) {
|
|
|
|
rc = -ENOMEM;
|
|
|
|
goto finished;
|
|
|
|
}
|
2018-09-03 11:33:41 +08:00
|
|
|
|
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>
2024-03-06 11:43:51 +08:00
|
|
|
/* if there is an existing lease, reuse it */
|
2024-03-06 11:43:53 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* note: files with hardlinks cause unexpected behaviour. As per MS-SMB2,
|
|
|
|
* lease keys are associated with the filepath. We are maintaining lease keys
|
|
|
|
* with the inode on the client. If the file has hardlinks, it is possible
|
|
|
|
* that the lease for a file be reused for an operation on its hardlink or
|
|
|
|
* vice versa.
|
|
|
|
* As a workaround, send request using an existing lease key and if the server
|
|
|
|
* returns STATUS_INVALID_PARAMETER, which maps to EINVAL, send the request
|
|
|
|
* again without the lease.
|
|
|
|
*/
|
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>
2024-03-06 11:43:51 +08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-26 06:21:48 +08:00
|
|
|
vars->oparms = *oparms;
|
|
|
|
vars->oparms.fid = &fid;
|
2020-05-20 10:19:59 +08:00
|
|
|
|
|
|
|
rqst[num_rqst].rq_iov = &vars->open_iov[0];
|
2018-09-03 11:33:41 +08:00
|
|
|
rqst[num_rqst].rq_nvec = SMB2_CREATE_IOV_SIZE;
|
2020-06-01 01:38:22 +08:00
|
|
|
rc = SMB2_open_init(tcon, server,
|
|
|
|
&rqst[num_rqst], &oplock, &vars->oparms,
|
2018-09-03 11:33:41 +08:00
|
|
|
utf16_path);
|
|
|
|
kfree(utf16_path);
|
|
|
|
if (rc)
|
|
|
|
goto finished;
|
|
|
|
|
2019-08-30 06:25:46 +08:00
|
|
|
smb2_set_next_command(tcon, &rqst[num_rqst]);
|
|
|
|
after_open:
|
|
|
|
num_rqst++;
|
|
|
|
rc = 0;
|
2018-09-03 11:33:41 +08:00
|
|
|
|
2023-11-26 10:55:02 +08:00
|
|
|
for (i = 0; i < num_cmds; i++) {
|
|
|
|
/* Operation */
|
|
|
|
switch (cmds[i]) {
|
|
|
|
case SMB2_OP_QUERY_INFO:
|
|
|
|
rqst[num_rqst].rq_iov = &vars->qi_iov;
|
|
|
|
rqst[num_rqst].rq_nvec = 1;
|
|
|
|
|
|
|
|
if (cfile) {
|
|
|
|
rc = SMB2_query_info_init(tcon, server,
|
|
|
|
&rqst[num_rqst],
|
|
|
|
cfile->fid.persistent_fid,
|
|
|
|
cfile->fid.volatile_fid,
|
|
|
|
FILE_ALL_INFORMATION,
|
|
|
|
SMB2_O_INFO_FILE, 0,
|
|
|
|
sizeof(struct smb2_file_all_info) +
|
|
|
|
PATH_MAX * 2, 0, NULL);
|
|
|
|
} else {
|
|
|
|
rc = SMB2_query_info_init(tcon, server,
|
|
|
|
&rqst[num_rqst],
|
|
|
|
COMPOUND_FID,
|
|
|
|
COMPOUND_FID,
|
|
|
|
FILE_ALL_INFORMATION,
|
|
|
|
SMB2_O_INFO_FILE, 0,
|
|
|
|
sizeof(struct smb2_file_all_info) +
|
|
|
|
PATH_MAX * 2, 0, NULL);
|
2019-09-09 13:30:00 +08:00
|
|
|
}
|
2024-01-26 04:04:05 +08:00
|
|
|
if (!rc && (!cfile || num_rqst > 1)) {
|
|
|
|
smb2_set_next_command(tcon, &rqst[num_rqst]);
|
|
|
|
smb2_set_related(&rqst[num_rqst]);
|
|
|
|
} else if (rc) {
|
2023-11-26 10:55:02 +08:00
|
|
|
goto finished;
|
2024-01-26 04:04:05 +08:00
|
|
|
}
|
2023-11-26 10:55:02 +08:00
|
|
|
num_rqst++;
|
|
|
|
trace_smb3_query_info_compound_enter(xid, ses->Suid,
|
|
|
|
tcon->tid, full_path);
|
|
|
|
break;
|
|
|
|
case SMB2_OP_POSIX_QUERY_INFO:
|
|
|
|
rqst[num_rqst].rq_iov = &vars->qi_iov;
|
|
|
|
rqst[num_rqst].rq_nvec = 1;
|
|
|
|
|
|
|
|
if (cfile) {
|
2020-06-12 08:25:47 +08:00
|
|
|
/* TBD: fix following to allow for longer SIDs */
|
2023-11-26 10:55:02 +08:00
|
|
|
rc = SMB2_query_info_init(tcon, server,
|
|
|
|
&rqst[num_rqst],
|
|
|
|
cfile->fid.persistent_fid,
|
|
|
|
cfile->fid.volatile_fid,
|
|
|
|
SMB_FIND_FILE_POSIX_INFO,
|
|
|
|
SMB2_O_INFO_FILE, 0,
|
|
|
|
sizeof(struct smb311_posix_qinfo *) +
|
|
|
|
(PATH_MAX * 2) +
|
|
|
|
(sizeof(struct cifs_sid) * 2), 0, NULL);
|
|
|
|
} else {
|
|
|
|
rc = SMB2_query_info_init(tcon, server,
|
|
|
|
&rqst[num_rqst],
|
|
|
|
COMPOUND_FID,
|
|
|
|
COMPOUND_FID,
|
|
|
|
SMB_FIND_FILE_POSIX_INFO,
|
|
|
|
SMB2_O_INFO_FILE, 0,
|
|
|
|
sizeof(struct smb311_posix_qinfo *) +
|
|
|
|
(PATH_MAX * 2) +
|
|
|
|
(sizeof(struct cifs_sid) * 2), 0, NULL);
|
2020-06-12 08:25:47 +08:00
|
|
|
}
|
2024-01-26 04:04:05 +08:00
|
|
|
if (!rc && (!cfile || num_rqst > 1)) {
|
|
|
|
smb2_set_next_command(tcon, &rqst[num_rqst]);
|
|
|
|
smb2_set_related(&rqst[num_rqst]);
|
|
|
|
} else if (rc) {
|
2023-11-26 10:55:02 +08:00
|
|
|
goto finished;
|
2024-01-26 04:04:05 +08:00
|
|
|
}
|
2023-11-26 10:55:02 +08:00
|
|
|
num_rqst++;
|
|
|
|
trace_smb3_posix_query_info_compound_enter(xid, ses->Suid,
|
|
|
|
tcon->tid, full_path);
|
|
|
|
break;
|
|
|
|
case SMB2_OP_DELETE:
|
|
|
|
trace_smb3_delete_enter(xid, ses->Suid, tcon->tid, full_path);
|
|
|
|
break;
|
|
|
|
case SMB2_OP_MKDIR:
|
|
|
|
/*
|
|
|
|
* Directories are created through parameters in the
|
|
|
|
* SMB2_open() call.
|
|
|
|
*/
|
|
|
|
trace_smb3_mkdir_enter(xid, ses->Suid, tcon->tid, full_path);
|
|
|
|
break;
|
|
|
|
case SMB2_OP_RMDIR:
|
|
|
|
rqst[num_rqst].rq_iov = &vars->si_iov[0];
|
|
|
|
rqst[num_rqst].rq_nvec = 1;
|
2018-09-03 11:33:46 +08:00
|
|
|
|
2023-11-26 10:55:02 +08:00
|
|
|
size[0] = 1; /* sizeof __u8 See MS-FSCC section 2.4.11 */
|
|
|
|
data[0] = &delete_pending[0];
|
2018-09-03 11:33:46 +08:00
|
|
|
|
2023-03-13 23:09:54 +08:00
|
|
|
rc = SMB2_set_info_init(tcon, server,
|
2023-11-26 10:55:02 +08:00
|
|
|
&rqst[num_rqst], COMPOUND_FID,
|
|
|
|
COMPOUND_FID, current->tgid,
|
|
|
|
FILE_DISPOSITION_INFORMATION,
|
|
|
|
SMB2_O_INFO_FILE, 0, data, size);
|
|
|
|
if (rc)
|
|
|
|
goto finished;
|
|
|
|
smb2_set_next_command(tcon, &rqst[num_rqst]);
|
|
|
|
smb2_set_related(&rqst[num_rqst++]);
|
|
|
|
trace_smb3_rmdir_enter(xid, ses->Suid, tcon->tid, full_path);
|
|
|
|
break;
|
|
|
|
case SMB2_OP_SET_EOF:
|
|
|
|
rqst[num_rqst].rq_iov = &vars->si_iov[0];
|
|
|
|
rqst[num_rqst].rq_nvec = 1;
|
|
|
|
|
|
|
|
size[0] = in_iov[i].iov_len;
|
|
|
|
data[0] = in_iov[i].iov_base;
|
|
|
|
|
|
|
|
if (cfile) {
|
|
|
|
rc = SMB2_set_info_init(tcon, server,
|
|
|
|
&rqst[num_rqst],
|
|
|
|
cfile->fid.persistent_fid,
|
|
|
|
cfile->fid.volatile_fid,
|
|
|
|
current->tgid,
|
|
|
|
FILE_END_OF_FILE_INFORMATION,
|
|
|
|
SMB2_O_INFO_FILE, 0,
|
|
|
|
data, size);
|
|
|
|
} else {
|
|
|
|
rc = SMB2_set_info_init(tcon, server,
|
|
|
|
&rqst[num_rqst],
|
|
|
|
COMPOUND_FID,
|
|
|
|
COMPOUND_FID,
|
|
|
|
current->tgid,
|
|
|
|
FILE_END_OF_FILE_INFORMATION,
|
|
|
|
SMB2_O_INFO_FILE, 0,
|
|
|
|
data, size);
|
2023-03-13 23:09:54 +08:00
|
|
|
}
|
2024-01-26 04:04:05 +08:00
|
|
|
if (!rc && (!cfile || num_rqst > 1)) {
|
|
|
|
smb2_set_next_command(tcon, &rqst[num_rqst]);
|
|
|
|
smb2_set_related(&rqst[num_rqst]);
|
|
|
|
} else if (rc) {
|
2023-11-26 10:55:02 +08:00
|
|
|
goto finished;
|
2024-01-26 04:04:05 +08:00
|
|
|
}
|
2023-11-26 10:55:02 +08:00
|
|
|
num_rqst++;
|
|
|
|
trace_smb3_set_eof_enter(xid, ses->Suid, tcon->tid, full_path);
|
|
|
|
break;
|
|
|
|
case SMB2_OP_SET_INFO:
|
|
|
|
rqst[num_rqst].rq_iov = &vars->si_iov[0];
|
|
|
|
rqst[num_rqst].rq_nvec = 1;
|
|
|
|
|
|
|
|
size[0] = in_iov[i].iov_len;
|
|
|
|
data[0] = in_iov[i].iov_base;
|
|
|
|
|
|
|
|
if (cfile) {
|
|
|
|
rc = SMB2_set_info_init(tcon, server,
|
|
|
|
&rqst[num_rqst],
|
|
|
|
cfile->fid.persistent_fid,
|
|
|
|
cfile->fid.volatile_fid, current->tgid,
|
|
|
|
FILE_BASIC_INFORMATION,
|
|
|
|
SMB2_O_INFO_FILE, 0, data, size);
|
|
|
|
} else {
|
|
|
|
rc = SMB2_set_info_init(tcon, server,
|
|
|
|
&rqst[num_rqst],
|
|
|
|
COMPOUND_FID,
|
|
|
|
COMPOUND_FID, current->tgid,
|
|
|
|
FILE_BASIC_INFORMATION,
|
|
|
|
SMB2_O_INFO_FILE, 0, data, size);
|
2019-08-30 07:53:56 +08:00
|
|
|
}
|
2024-01-26 04:04:05 +08:00
|
|
|
if (!rc && (!cfile || num_rqst > 1)) {
|
|
|
|
smb2_set_next_command(tcon, &rqst[num_rqst]);
|
|
|
|
smb2_set_related(&rqst[num_rqst]);
|
|
|
|
} else if (rc) {
|
2023-11-26 10:55:02 +08:00
|
|
|
goto finished;
|
2024-01-26 04:04:05 +08:00
|
|
|
}
|
2023-11-26 10:55:02 +08:00
|
|
|
num_rqst++;
|
|
|
|
trace_smb3_set_info_compound_enter(xid, ses->Suid,
|
|
|
|
tcon->tid, full_path);
|
|
|
|
break;
|
|
|
|
case SMB2_OP_RENAME:
|
|
|
|
rqst[num_rqst].rq_iov = &vars->si_iov[0];
|
|
|
|
rqst[num_rqst].rq_nvec = 2;
|
2018-09-03 11:33:49 +08:00
|
|
|
|
2023-11-26 10:55:02 +08:00
|
|
|
len = in_iov[i].iov_len;
|
2018-09-03 11:33:49 +08:00
|
|
|
|
2023-11-26 10:55:02 +08:00
|
|
|
vars->rename_info.ReplaceIfExists = 1;
|
|
|
|
vars->rename_info.RootDirectory = 0;
|
|
|
|
vars->rename_info.FileNameLength = cpu_to_le32(len);
|
2018-09-03 11:33:49 +08:00
|
|
|
|
2023-11-26 10:55:02 +08:00
|
|
|
size[0] = sizeof(struct smb2_file_rename_info);
|
|
|
|
data[0] = &vars->rename_info;
|
2018-09-03 11:33:49 +08:00
|
|
|
|
2023-11-26 10:55:02 +08:00
|
|
|
size[1] = len + 2 /* null */;
|
|
|
|
data[1] = in_iov[i].iov_base;
|
2018-09-03 11:33:49 +08:00
|
|
|
|
2023-11-26 10:55:02 +08:00
|
|
|
if (cfile) {
|
|
|
|
rc = SMB2_set_info_init(tcon, server,
|
|
|
|
&rqst[num_rqst],
|
|
|
|
cfile->fid.persistent_fid,
|
|
|
|
cfile->fid.volatile_fid,
|
|
|
|
current->tgid, FILE_RENAME_INFORMATION,
|
|
|
|
SMB2_O_INFO_FILE, 0, data, size);
|
|
|
|
} else {
|
|
|
|
rc = SMB2_set_info_init(tcon, server,
|
|
|
|
&rqst[num_rqst],
|
|
|
|
COMPOUND_FID, COMPOUND_FID,
|
|
|
|
current->tgid, FILE_RENAME_INFORMATION,
|
|
|
|
SMB2_O_INFO_FILE, 0, data, size);
|
2019-08-30 07:53:56 +08:00
|
|
|
}
|
2024-01-26 04:04:05 +08:00
|
|
|
if (!rc && (!cfile || num_rqst > 1)) {
|
|
|
|
smb2_set_next_command(tcon, &rqst[num_rqst]);
|
|
|
|
smb2_set_related(&rqst[num_rqst]);
|
|
|
|
} else if (rc) {
|
2023-11-26 10:55:02 +08:00
|
|
|
goto finished;
|
2024-01-26 04:04:05 +08:00
|
|
|
}
|
2023-11-26 10:55:02 +08:00
|
|
|
num_rqst++;
|
|
|
|
trace_smb3_rename_enter(xid, ses->Suid, tcon->tid, full_path);
|
|
|
|
break;
|
|
|
|
case SMB2_OP_HARDLINK:
|
|
|
|
rqst[num_rqst].rq_iov = &vars->si_iov[0];
|
|
|
|
rqst[num_rqst].rq_nvec = 2;
|
2018-09-03 11:33:49 +08:00
|
|
|
|
2023-11-26 10:55:02 +08:00
|
|
|
len = in_iov[i].iov_len;
|
2018-09-03 11:33:49 +08:00
|
|
|
|
2023-11-26 10:55:02 +08:00
|
|
|
vars->link_info.ReplaceIfExists = 0;
|
|
|
|
vars->link_info.RootDirectory = 0;
|
|
|
|
vars->link_info.FileNameLength = cpu_to_le32(len);
|
2018-09-03 11:33:49 +08:00
|
|
|
|
2023-11-26 10:55:02 +08:00
|
|
|
size[0] = sizeof(struct smb2_file_link_info);
|
|
|
|
data[0] = &vars->link_info;
|
2018-09-03 11:33:49 +08:00
|
|
|
|
2023-11-26 10:55:02 +08:00
|
|
|
size[1] = len + 2 /* null */;
|
|
|
|
data[1] = in_iov[i].iov_base;
|
2018-09-03 11:33:49 +08:00
|
|
|
|
2023-11-26 10:55:02 +08:00
|
|
|
rc = SMB2_set_info_init(tcon, server,
|
|
|
|
&rqst[num_rqst], COMPOUND_FID,
|
|
|
|
COMPOUND_FID, current->tgid,
|
|
|
|
FILE_LINK_INFORMATION,
|
|
|
|
SMB2_O_INFO_FILE, 0, data, size);
|
|
|
|
if (rc)
|
|
|
|
goto finished;
|
|
|
|
smb2_set_next_command(tcon, &rqst[num_rqst]);
|
|
|
|
smb2_set_related(&rqst[num_rqst++]);
|
|
|
|
trace_smb3_hardlink_enter(xid, ses->Suid, tcon->tid, full_path);
|
|
|
|
break;
|
2023-11-26 10:55:03 +08:00
|
|
|
case SMB2_OP_SET_REPARSE:
|
|
|
|
rqst[num_rqst].rq_iov = vars->io_iov;
|
|
|
|
rqst[num_rqst].rq_nvec = ARRAY_SIZE(vars->io_iov);
|
|
|
|
|
2024-01-26 04:04:05 +08:00
|
|
|
if (cfile) {
|
|
|
|
rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
|
|
|
|
cfile->fid.persistent_fid,
|
|
|
|
cfile->fid.volatile_fid,
|
|
|
|
FSCTL_SET_REPARSE_POINT,
|
|
|
|
in_iov[i].iov_base,
|
|
|
|
in_iov[i].iov_len, 0);
|
|
|
|
} else {
|
|
|
|
rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
|
|
|
|
COMPOUND_FID, COMPOUND_FID,
|
|
|
|
FSCTL_SET_REPARSE_POINT,
|
|
|
|
in_iov[i].iov_base,
|
|
|
|
in_iov[i].iov_len, 0);
|
|
|
|
}
|
|
|
|
if (!rc && (!cfile || num_rqst > 1)) {
|
|
|
|
smb2_set_next_command(tcon, &rqst[num_rqst]);
|
|
|
|
smb2_set_related(&rqst[num_rqst]);
|
|
|
|
} else if (rc) {
|
2023-11-26 10:55:03 +08:00
|
|
|
goto finished;
|
2024-01-26 04:04:05 +08:00
|
|
|
}
|
|
|
|
num_rqst++;
|
2023-11-26 10:55:03 +08:00
|
|
|
trace_smb3_set_reparse_compound_enter(xid, ses->Suid,
|
|
|
|
tcon->tid, full_path);
|
|
|
|
break;
|
2023-11-26 10:55:05 +08:00
|
|
|
case SMB2_OP_GET_REPARSE:
|
|
|
|
rqst[num_rqst].rq_iov = vars->io_iov;
|
|
|
|
rqst[num_rqst].rq_nvec = ARRAY_SIZE(vars->io_iov);
|
|
|
|
|
2024-01-26 04:04:05 +08:00
|
|
|
if (cfile) {
|
|
|
|
rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
|
|
|
|
cfile->fid.persistent_fid,
|
|
|
|
cfile->fid.volatile_fid,
|
|
|
|
FSCTL_GET_REPARSE_POINT,
|
|
|
|
NULL, 0, CIFSMaxBufSize);
|
|
|
|
} else {
|
|
|
|
rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
|
|
|
|
COMPOUND_FID, COMPOUND_FID,
|
|
|
|
FSCTL_GET_REPARSE_POINT,
|
|
|
|
NULL, 0, CIFSMaxBufSize);
|
|
|
|
}
|
|
|
|
if (!rc && (!cfile || num_rqst > 1)) {
|
|
|
|
smb2_set_next_command(tcon, &rqst[num_rqst]);
|
|
|
|
smb2_set_related(&rqst[num_rqst]);
|
|
|
|
} else if (rc) {
|
2023-11-26 10:55:05 +08:00
|
|
|
goto finished;
|
2024-01-26 04:04:05 +08:00
|
|
|
}
|
|
|
|
num_rqst++;
|
2023-11-26 10:55:05 +08:00
|
|
|
trace_smb3_get_reparse_compound_enter(xid, ses->Suid,
|
|
|
|
tcon->tid, full_path);
|
|
|
|
break;
|
2024-01-28 12:12:01 +08:00
|
|
|
case SMB2_OP_QUERY_WSL_EA:
|
|
|
|
rqst[num_rqst].rq_iov = &vars->ea_iov;
|
|
|
|
rqst[num_rqst].rq_nvec = 1;
|
|
|
|
|
|
|
|
if (cfile) {
|
|
|
|
rc = SMB2_query_info_init(tcon, server,
|
|
|
|
&rqst[num_rqst],
|
|
|
|
cfile->fid.persistent_fid,
|
|
|
|
cfile->fid.volatile_fid,
|
|
|
|
FILE_FULL_EA_INFORMATION,
|
|
|
|
SMB2_O_INFO_FILE, 0,
|
|
|
|
SMB2_WSL_MAX_QUERY_EA_RESP_SIZE,
|
|
|
|
sizeof(wsl_query_eas),
|
|
|
|
(void *)wsl_query_eas);
|
|
|
|
} else {
|
|
|
|
rc = SMB2_query_info_init(tcon, server,
|
|
|
|
&rqst[num_rqst],
|
|
|
|
COMPOUND_FID,
|
|
|
|
COMPOUND_FID,
|
|
|
|
FILE_FULL_EA_INFORMATION,
|
|
|
|
SMB2_O_INFO_FILE, 0,
|
|
|
|
SMB2_WSL_MAX_QUERY_EA_RESP_SIZE,
|
|
|
|
sizeof(wsl_query_eas),
|
|
|
|
(void *)wsl_query_eas);
|
|
|
|
}
|
|
|
|
if (!rc && (!cfile || num_rqst > 1)) {
|
|
|
|
smb2_set_next_command(tcon, &rqst[num_rqst]);
|
|
|
|
smb2_set_related(&rqst[num_rqst]);
|
|
|
|
} else if (rc) {
|
|
|
|
goto finished;
|
|
|
|
}
|
|
|
|
num_rqst++;
|
|
|
|
break;
|
2023-11-26 10:55:02 +08:00
|
|
|
default:
|
|
|
|
cifs_dbg(VFS, "Invalid command\n");
|
|
|
|
rc = -EINVAL;
|
|
|
|
}
|
2018-09-03 11:33:41 +08:00
|
|
|
}
|
|
|
|
if (rc)
|
|
|
|
goto finished;
|
|
|
|
|
2019-08-30 06:25:46 +08:00
|
|
|
/* We already have a handle so we can skip the close */
|
|
|
|
if (cfile)
|
|
|
|
goto after_close;
|
2018-09-03 11:33:41 +08:00
|
|
|
/* Close */
|
2021-03-08 23:00:50 +08:00
|
|
|
flags |= CIFS_CP_CREATE_CLOSE_OP;
|
2023-08-17 23:34:13 +08:00
|
|
|
rqst[num_rqst].rq_iov = &vars->close_iov;
|
2018-09-03 11:33:41 +08:00
|
|
|
rqst[num_rqst].rq_nvec = 1;
|
2020-06-01 01:38:22 +08:00
|
|
|
rc = SMB2_close_init(tcon, server,
|
|
|
|
&rqst[num_rqst], COMPOUND_FID,
|
2019-12-03 11:46:54 +08:00
|
|
|
COMPOUND_FID, false);
|
2019-08-30 06:25:46 +08:00
|
|
|
smb2_set_related(&rqst[num_rqst]);
|
2018-09-03 11:33:41 +08:00
|
|
|
if (rc)
|
|
|
|
goto finished;
|
2019-08-30 06:25:46 +08:00
|
|
|
after_close:
|
|
|
|
num_rqst++;
|
|
|
|
|
|
|
|
if (cfile) {
|
2024-01-21 11:32:47 +08:00
|
|
|
if (retries)
|
|
|
|
for (i = 1; i < num_rqst - 2; i++)
|
|
|
|
smb2_set_replay(server, &rqst[i]);
|
|
|
|
|
2020-06-01 01:38:22 +08:00
|
|
|
rc = compound_send_recv(xid, ses, server,
|
|
|
|
flags, num_rqst - 2,
|
2019-08-30 06:25:46 +08:00
|
|
|
&rqst[1], &resp_buftype[1],
|
|
|
|
&rsp_iov[1]);
|
2024-01-21 11:32:47 +08:00
|
|
|
} else {
|
|
|
|
if (retries)
|
|
|
|
for (i = 0; i < num_rqst; i++)
|
|
|
|
smb2_set_replay(server, &rqst[i]);
|
|
|
|
|
2020-06-01 01:38:22 +08:00
|
|
|
rc = compound_send_recv(xid, ses, server,
|
|
|
|
flags, num_rqst,
|
2019-08-30 06:25:46 +08:00
|
|
|
rqst, resp_buftype,
|
|
|
|
rsp_iov);
|
2024-01-21 11:32:47 +08:00
|
|
|
}
|
2018-09-03 11:33:41 +08:00
|
|
|
|
2023-11-26 10:55:02 +08:00
|
|
|
finished:
|
|
|
|
num_rqst = 0;
|
|
|
|
SMB2_open_free(&rqst[num_rqst++]);
|
2019-09-11 13:07:36 +08:00
|
|
|
if (rc == -EREMCHG) {
|
2022-09-22 03:05:53 +08:00
|
|
|
pr_warn_once("server share %s deleted\n", tcon->tree_name);
|
2019-09-11 13:07:36 +08:00
|
|
|
tcon->need_reconnect = true;
|
|
|
|
}
|
|
|
|
|
2023-11-26 10:55:02 +08:00
|
|
|
for (i = 0; i < num_cmds; i++) {
|
|
|
|
switch (cmds[i]) {
|
|
|
|
case SMB2_OP_QUERY_INFO:
|
|
|
|
idata = in_iov[i].iov_base;
|
|
|
|
if (rc == 0 && cfile && cfile->symlink_target) {
|
|
|
|
idata->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL);
|
|
|
|
if (!idata->symlink_target)
|
|
|
|
rc = -ENOMEM;
|
|
|
|
}
|
|
|
|
if (rc == 0) {
|
|
|
|
qi_rsp = (struct smb2_query_info_rsp *)
|
|
|
|
rsp_iov[i + 1].iov_base;
|
|
|
|
rc = smb2_validate_and_copy_iov(
|
|
|
|
le16_to_cpu(qi_rsp->OutputBufferOffset),
|
|
|
|
le32_to_cpu(qi_rsp->OutputBufferLength),
|
|
|
|
&rsp_iov[i + 1], sizeof(idata->fi), (char *)&idata->fi);
|
|
|
|
}
|
|
|
|
SMB2_query_info_free(&rqst[num_rqst++]);
|
|
|
|
if (rc)
|
|
|
|
trace_smb3_query_info_compound_err(xid, ses->Suid,
|
|
|
|
tcon->tid, rc);
|
|
|
|
else
|
|
|
|
trace_smb3_query_info_compound_done(xid, ses->Suid,
|
|
|
|
tcon->tid);
|
|
|
|
break;
|
|
|
|
case SMB2_OP_POSIX_QUERY_INFO:
|
|
|
|
idata = in_iov[i].iov_base;
|
|
|
|
if (rc == 0 && cfile && cfile->symlink_target) {
|
|
|
|
idata->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL);
|
|
|
|
if (!idata->symlink_target)
|
2022-11-25 19:37:44 +08:00
|
|
|
rc = -ENOMEM;
|
|
|
|
}
|
2023-11-26 10:55:02 +08:00
|
|
|
if (rc == 0) {
|
|
|
|
qi_rsp = (struct smb2_query_info_rsp *)
|
|
|
|
rsp_iov[i + 1].iov_base;
|
|
|
|
rc = smb2_validate_and_copy_iov(
|
|
|
|
le16_to_cpu(qi_rsp->OutputBufferOffset),
|
|
|
|
le32_to_cpu(qi_rsp->OutputBufferLength),
|
|
|
|
&rsp_iov[i + 1], sizeof(idata->posix_fi) /* add SIDs */,
|
|
|
|
(char *)&idata->posix_fi);
|
|
|
|
}
|
2024-01-19 12:08:27 +08:00
|
|
|
if (rc == 0)
|
|
|
|
rc = parse_posix_sids(idata, &rsp_iov[i + 1]);
|
|
|
|
|
2023-11-26 10:55:02 +08:00
|
|
|
SMB2_query_info_free(&rqst[num_rqst++]);
|
|
|
|
if (rc)
|
|
|
|
trace_smb3_posix_query_info_compound_err(xid, ses->Suid,
|
|
|
|
tcon->tid, rc);
|
|
|
|
else
|
|
|
|
trace_smb3_posix_query_info_compound_done(xid, ses->Suid,
|
|
|
|
tcon->tid);
|
|
|
|
break;
|
|
|
|
case SMB2_OP_DELETE:
|
|
|
|
if (rc)
|
|
|
|
trace_smb3_delete_err(xid, ses->Suid, tcon->tid, rc);
|
2024-03-06 13:07:52 +08:00
|
|
|
else {
|
|
|
|
/*
|
|
|
|
* If dentry (hence, inode) is NULL, lease break is going to
|
|
|
|
* take care of degrading leases on handles for deleted files.
|
|
|
|
*/
|
|
|
|
if (inode)
|
|
|
|
cifs_mark_open_handles_for_deleted_file(inode, full_path);
|
2023-11-26 10:55:02 +08:00
|
|
|
trace_smb3_delete_done(xid, ses->Suid, tcon->tid);
|
2024-03-06 13:07:52 +08:00
|
|
|
}
|
2023-11-26 10:55:02 +08:00
|
|
|
break;
|
|
|
|
case SMB2_OP_MKDIR:
|
|
|
|
if (rc)
|
|
|
|
trace_smb3_mkdir_err(xid, ses->Suid, tcon->tid, rc);
|
|
|
|
else
|
|
|
|
trace_smb3_mkdir_done(xid, ses->Suid, tcon->tid);
|
|
|
|
break;
|
|
|
|
case SMB2_OP_HARDLINK:
|
|
|
|
if (rc)
|
|
|
|
trace_smb3_hardlink_err(xid, ses->Suid, tcon->tid, rc);
|
|
|
|
else
|
|
|
|
trace_smb3_hardlink_done(xid, ses->Suid, tcon->tid);
|
|
|
|
SMB2_set_info_free(&rqst[num_rqst++]);
|
|
|
|
break;
|
|
|
|
case SMB2_OP_RENAME:
|
|
|
|
if (rc)
|
|
|
|
trace_smb3_rename_err(xid, ses->Suid, tcon->tid, rc);
|
|
|
|
else
|
|
|
|
trace_smb3_rename_done(xid, ses->Suid, tcon->tid);
|
|
|
|
SMB2_set_info_free(&rqst[num_rqst++]);
|
|
|
|
break;
|
|
|
|
case SMB2_OP_RMDIR:
|
|
|
|
if (rc)
|
|
|
|
trace_smb3_rmdir_err(xid, ses->Suid, tcon->tid, rc);
|
|
|
|
else
|
|
|
|
trace_smb3_rmdir_done(xid, ses->Suid, tcon->tid);
|
|
|
|
SMB2_set_info_free(&rqst[num_rqst++]);
|
|
|
|
break;
|
|
|
|
case SMB2_OP_SET_EOF:
|
|
|
|
if (rc)
|
|
|
|
trace_smb3_set_eof_err(xid, ses->Suid, tcon->tid, rc);
|
|
|
|
else
|
|
|
|
trace_smb3_set_eof_done(xid, ses->Suid, tcon->tid);
|
|
|
|
SMB2_set_info_free(&rqst[num_rqst++]);
|
|
|
|
break;
|
|
|
|
case SMB2_OP_SET_INFO:
|
|
|
|
if (rc)
|
|
|
|
trace_smb3_set_info_compound_err(xid, ses->Suid,
|
|
|
|
tcon->tid, rc);
|
|
|
|
else
|
|
|
|
trace_smb3_set_info_compound_done(xid, ses->Suid,
|
|
|
|
tcon->tid);
|
|
|
|
SMB2_set_info_free(&rqst[num_rqst++]);
|
|
|
|
break;
|
2023-11-26 10:55:03 +08:00
|
|
|
case SMB2_OP_SET_REPARSE:
|
|
|
|
if (rc) {
|
|
|
|
trace_smb3_set_reparse_compound_err(xid, ses->Suid,
|
|
|
|
tcon->tid, rc);
|
|
|
|
} else {
|
|
|
|
trace_smb3_set_reparse_compound_done(xid, ses->Suid,
|
|
|
|
tcon->tid);
|
|
|
|
}
|
|
|
|
SMB2_ioctl_free(&rqst[num_rqst++]);
|
|
|
|
break;
|
2023-11-26 10:55:05 +08:00
|
|
|
case SMB2_OP_GET_REPARSE:
|
|
|
|
if (!rc) {
|
|
|
|
iov = &rsp_iov[i + 1];
|
|
|
|
idata = in_iov[i].iov_base;
|
|
|
|
idata->reparse.io.iov = *iov;
|
|
|
|
idata->reparse.io.buftype = resp_buftype[i + 1];
|
|
|
|
rbuf = reparse_buf_ptr(iov);
|
|
|
|
if (IS_ERR(rbuf)) {
|
|
|
|
rc = PTR_ERR(rbuf);
|
|
|
|
trace_smb3_set_reparse_compound_err(xid, ses->Suid,
|
|
|
|
tcon->tid, rc);
|
|
|
|
} else {
|
|
|
|
idata->reparse.tag = le32_to_cpu(rbuf->ReparseTag);
|
|
|
|
trace_smb3_set_reparse_compound_done(xid, ses->Suid,
|
|
|
|
tcon->tid);
|
|
|
|
}
|
|
|
|
memset(iov, 0, sizeof(*iov));
|
|
|
|
resp_buftype[i + 1] = CIFS_NO_BUFFER;
|
|
|
|
} else {
|
2024-01-28 12:12:01 +08:00
|
|
|
trace_smb3_set_reparse_compound_err(xid, ses->Suid,
|
2023-11-26 10:55:05 +08:00
|
|
|
tcon->tid, rc);
|
|
|
|
}
|
|
|
|
SMB2_ioctl_free(&rqst[num_rqst++]);
|
|
|
|
break;
|
2024-01-28 12:12:01 +08:00
|
|
|
case SMB2_OP_QUERY_WSL_EA:
|
|
|
|
if (!rc) {
|
|
|
|
idata = in_iov[i].iov_base;
|
|
|
|
qi_rsp = rsp_iov[i + 1].iov_base;
|
|
|
|
data[0] = (u8 *)qi_rsp + le16_to_cpu(qi_rsp->OutputBufferOffset);
|
|
|
|
size[0] = le32_to_cpu(qi_rsp->OutputBufferLength);
|
|
|
|
rc = check_wsl_eas(&rsp_iov[i + 1]);
|
|
|
|
if (!rc) {
|
|
|
|
memcpy(idata->wsl.eas, data[0], size[0]);
|
|
|
|
idata->wsl.eas_len = size[0];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!rc) {
|
|
|
|
trace_smb3_query_wsl_ea_compound_done(xid, ses->Suid,
|
|
|
|
tcon->tid);
|
|
|
|
} else {
|
|
|
|
trace_smb3_query_wsl_ea_compound_err(xid, ses->Suid,
|
|
|
|
tcon->tid, rc);
|
|
|
|
}
|
|
|
|
SMB2_query_info_free(&rqst[num_rqst++]);
|
|
|
|
break;
|
2022-11-25 19:37:44 +08:00
|
|
|
}
|
2018-09-03 11:33:41 +08:00
|
|
|
}
|
2023-11-26 10:55:02 +08:00
|
|
|
SMB2_close_free(&rqst[num_rqst]);
|
2022-10-04 05:43:50 +08:00
|
|
|
|
2023-11-26 10:55:02 +08:00
|
|
|
num_cmds += 2;
|
2023-08-17 23:34:02 +08:00
|
|
|
if (out_iov && out_buftype) {
|
2023-11-26 10:55:02 +08:00
|
|
|
memcpy(out_iov, rsp_iov, num_cmds * sizeof(*out_iov));
|
|
|
|
memcpy(out_buftype, resp_buftype,
|
|
|
|
num_cmds * sizeof(*out_buftype));
|
2022-10-04 05:43:50 +08:00
|
|
|
} else {
|
2023-11-26 10:55:02 +08:00
|
|
|
for (i = 0; i < num_cmds; i++)
|
|
|
|
free_rsp_buf(resp_buftype[i], rsp_iov[i].iov_base);
|
2022-10-04 05:43:50 +08:00
|
|
|
}
|
2024-01-21 11:32:47 +08:00
|
|
|
num_cmds -= 2; /* correct num_cmds as there could be a retry */
|
2020-05-20 10:19:59 +08:00
|
|
|
kfree(vars);
|
2024-01-21 11:32:47 +08:00
|
|
|
|
|
|
|
if (is_replayable_error(rc) &&
|
|
|
|
smb2_should_replay(tcon, &retries, &cur_sleep))
|
|
|
|
goto replay_again;
|
|
|
|
|
|
|
|
if (cfile)
|
|
|
|
cifsFileInfo_put(cfile);
|
|
|
|
|
2018-09-03 11:33:41 +08:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2023-08-17 23:34:06 +08:00
|
|
|
static int parse_create_response(struct cifs_open_info_data *data,
|
|
|
|
struct cifs_sb_info *cifs_sb,
|
|
|
|
const struct kvec *iov)
|
|
|
|
{
|
|
|
|
struct smb2_create_rsp *rsp = iov->iov_base;
|
|
|
|
bool reparse_point = false;
|
|
|
|
u32 tag = 0;
|
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
switch (rsp->hdr.Status) {
|
2023-09-21 04:42:11 +08:00
|
|
|
case STATUS_IO_REPARSE_TAG_NOT_HANDLED:
|
|
|
|
reparse_point = true;
|
|
|
|
break;
|
2023-08-17 23:34:06 +08:00
|
|
|
case STATUS_STOPPED_ON_SYMLINK:
|
|
|
|
rc = smb2_parse_symlink_response(cifs_sb, iov,
|
|
|
|
&data->symlink_target);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
tag = IO_REPARSE_TAG_SYMLINK;
|
|
|
|
reparse_point = true;
|
|
|
|
break;
|
|
|
|
case STATUS_SUCCESS:
|
|
|
|
reparse_point = !!(rsp->Flags & SMB2_CREATE_FLAG_REPARSEPOINT);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
data->reparse_point = reparse_point;
|
2023-11-22 07:12:54 +08:00
|
|
|
data->reparse.tag = tag;
|
2023-08-17 23:34:06 +08:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2023-08-17 23:34:01 +08:00
|
|
|
int smb2_query_path_info(const unsigned int xid,
|
|
|
|
struct cifs_tcon *tcon,
|
|
|
|
struct cifs_sb_info *cifs_sb,
|
|
|
|
const char *full_path,
|
|
|
|
struct cifs_open_info_data *data)
|
2011-12-29 21:06:33 +08:00
|
|
|
{
|
2024-01-26 06:21:48 +08:00
|
|
|
struct cifs_open_parms oparms;
|
2018-10-19 13:32:41 +08:00
|
|
|
__u32 create_options = 0;
|
2019-09-09 13:30:00 +08:00
|
|
|
struct cifsFileInfo *cfile;
|
2020-10-05 10:37:52 +08:00
|
|
|
struct cached_fid *cfid = NULL;
|
2023-08-17 23:34:06 +08:00
|
|
|
struct smb2_hdr *hdr;
|
2024-01-28 12:12:01 +08:00
|
|
|
struct kvec in_iov[3], out_iov[3] = {};
|
2023-08-17 23:34:02 +08:00
|
|
|
int out_buftype[3] = {};
|
2024-01-28 12:12:01 +08:00
|
|
|
int cmds[3];
|
2023-03-01 06:01:54 +08:00
|
|
|
bool islink;
|
2024-01-28 12:12:01 +08:00
|
|
|
int i, num_cmds = 0;
|
2023-03-01 06:01:54 +08:00
|
|
|
int rc, rc2;
|
2011-12-29 21:06:33 +08:00
|
|
|
|
2023-08-17 23:34:01 +08:00
|
|
|
data->adjust_tz = false;
|
|
|
|
data->reparse_point = false;
|
2011-12-29 21:06:33 +08:00
|
|
|
|
2024-01-19 12:08:28 +08:00
|
|
|
/*
|
|
|
|
* BB TODO: Add support for using cached root handle in SMB3.1.1 POSIX.
|
|
|
|
* Create SMB2_query_posix_info worker function to do non-compounded
|
|
|
|
* query when we already have an open file handle for this. For now this
|
|
|
|
* is fast enough (always using the compounded version).
|
|
|
|
*/
|
|
|
|
if (!tcon->posix_extensions) {
|
|
|
|
if (*full_path) {
|
|
|
|
rc = -ENOENT;
|
2021-03-09 07:07:28 +08:00
|
|
|
} else {
|
2024-01-19 12:08:28 +08:00
|
|
|
rc = open_cached_dir(xid, tcon, full_path,
|
|
|
|
cifs_sb, false, &cfid);
|
2019-03-12 11:58:31 +08:00
|
|
|
}
|
2024-01-19 12:08:28 +08:00
|
|
|
/* If it is a root and its handle is cached then use it */
|
|
|
|
if (!rc) {
|
|
|
|
if (cfid->file_all_info_is_valid) {
|
|
|
|
memcpy(&data->fi, &cfid->file_all_info,
|
|
|
|
sizeof(data->fi));
|
|
|
|
} else {
|
|
|
|
rc = SMB2_query_info(xid, tcon,
|
|
|
|
cfid->fid.persistent_fid,
|
|
|
|
cfid->fid.volatile_fid,
|
|
|
|
&data->fi);
|
|
|
|
}
|
|
|
|
close_cached_dir(cfid);
|
|
|
|
return rc;
|
|
|
|
}
|
2024-01-28 12:12:01 +08:00
|
|
|
cmds[num_cmds++] = SMB2_OP_QUERY_INFO;
|
2024-01-19 12:08:28 +08:00
|
|
|
} else {
|
2024-01-28 12:12:01 +08:00
|
|
|
cmds[num_cmds++] = SMB2_OP_POSIX_QUERY_INFO;
|
2019-01-17 03:48:42 +08:00
|
|
|
}
|
|
|
|
|
2023-11-26 10:55:05 +08:00
|
|
|
in_iov[0].iov_base = data;
|
|
|
|
in_iov[0].iov_len = sizeof(*data);
|
|
|
|
in_iov[1] = in_iov[0];
|
2024-01-28 12:12:01 +08:00
|
|
|
in_iov[2] = in_iov[0];
|
2023-11-26 10:55:02 +08:00
|
|
|
|
2019-09-09 13:30:00 +08:00
|
|
|
cifs_get_readable_path(tcon, full_path, &cfile);
|
2024-01-26 06:21:48 +08:00
|
|
|
oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, FILE_READ_ATTRIBUTES,
|
|
|
|
FILE_OPEN, create_options, ACL_NO_MODE);
|
2023-11-26 10:55:02 +08:00
|
|
|
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
|
2024-01-28 12:12:01 +08:00
|
|
|
&oparms, in_iov, cmds, num_cmds,
|
|
|
|
cfile, out_iov, out_buftype, NULL);
|
2023-08-17 23:34:06 +08:00
|
|
|
hdr = out_iov[0].iov_base;
|
|
|
|
/*
|
|
|
|
* If first iov is unset, then SMB session was dropped or we've got a
|
|
|
|
* cached open file (@cfile).
|
|
|
|
*/
|
|
|
|
if (!hdr || out_buftype[0] == CIFS_NO_BUFFER)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
switch (rc) {
|
|
|
|
case 0:
|
|
|
|
case -EOPNOTSUPP:
|
2024-01-19 12:08:28 +08:00
|
|
|
/*
|
|
|
|
* BB TODO: When support for special files added to Samba
|
|
|
|
* re-verify this path.
|
|
|
|
*/
|
2023-08-17 23:34:06 +08:00
|
|
|
rc = parse_create_response(data, cifs_sb, &out_iov[0]);
|
|
|
|
if (rc || !data->reparse_point)
|
cifs: reduce roundtrips on create/qinfo requests
To work around some Window servers that return
STATUS_OBJECT_NAME_INVALID on query infos under DFS namespaces that
contain non-ASCII characters, we started checking for -ENOENT on every
file open, and if so, then send additional requests to figure out
whether it is a DFS link or not. It means that all those requests
will be sent to every non-existing file.
So, in order to reduce the number of roundtrips, check earlier whether
status code is STATUS_OBJECT_NAME_INVALID and tcon supports dfs, and
if so, then map -ENOENT to -EREMOTE so mount or automount will take
care of chasing the DFS link -- if it isn't an DFS link, then -ENOENT
will be returned appropriately.
Before patch
SMB2 438 Create Request File: ada.test\dfs\foo;GetInfo Request...
SMB2 310 Create Response, Error: STATUS_OBJECT_NAME_NOT_FOUND;...
SMB2 228 Ioctl Request FSCTL_DFS_GET_REFERRALS, File: \ada.test\dfs\foo
SMB2 143 Ioctl Response, Error: STATUS_OBJECT_PATH_NOT_FOUND
SMB2 438 Create Request File: ada.test\dfs\foo;GetInfo Request...
SMB2 310 Create Response, Error: STATUS_OBJECT_NAME_NOT_FOUND;...
SMB2 228 Ioctl Request FSCTL_DFS_GET_REFERRALS, File: \ada.test\dfs\foo
SMB2 143 Ioctl Response, Error: STATUS_OBJECT_PATH_NOT_FOUND
After patch
SMB2 438 Create Request File: ada.test\dfs\foo;GetInfo Request...
SMB2 310 Create Response, Error: STATUS_OBJECT_NAME_NOT_FOUND;...
SMB2 438 Create Request File: ada.test\dfs\foo;GetInfo Request...
SMB2 310 Create Response, Error: STATUS_OBJECT_NAME_NOT_FOUND;...
Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: Steve French <stfrench@microsoft.com>
2022-12-13 10:39:37 +08:00
|
|
|
goto out;
|
2023-08-17 23:34:06 +08:00
|
|
|
|
2024-01-28 12:12:01 +08:00
|
|
|
cmds[num_cmds++] = SMB2_OP_QUERY_WSL_EA;
|
|
|
|
/*
|
|
|
|
* Skip SMB2_OP_GET_REPARSE if symlink already parsed in create
|
|
|
|
* response.
|
|
|
|
*/
|
|
|
|
if (data->reparse.tag != IO_REPARSE_TAG_SYMLINK)
|
|
|
|
cmds[num_cmds++] = SMB2_OP_GET_REPARSE;
|
|
|
|
|
2024-01-26 06:21:48 +08:00
|
|
|
oparms = CIFS_OPARMS(cifs_sb, tcon, full_path,
|
2024-01-28 12:12:01 +08:00
|
|
|
FILE_READ_ATTRIBUTES | FILE_READ_EA,
|
|
|
|
FILE_OPEN, create_options |
|
|
|
|
OPEN_REPARSE_POINT, ACL_NO_MODE);
|
2023-08-17 23:34:06 +08:00
|
|
|
cifs_get_readable_path(tcon, full_path, &cfile);
|
|
|
|
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
|
2024-01-26 06:21:48 +08:00
|
|
|
&oparms, in_iov, cmds, num_cmds,
|
|
|
|
cfile, NULL, NULL, NULL);
|
2023-08-17 23:34:06 +08:00
|
|
|
break;
|
|
|
|
case -EREMOTE:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (hdr->Status != STATUS_OBJECT_NAME_INVALID)
|
|
|
|
break;
|
|
|
|
rc2 = cifs_inval_name_dfs_link_error(xid, tcon, cifs_sb,
|
|
|
|
full_path, &islink);
|
|
|
|
if (rc2) {
|
|
|
|
rc = rc2;
|
cifs: reduce roundtrips on create/qinfo requests
To work around some Window servers that return
STATUS_OBJECT_NAME_INVALID on query infos under DFS namespaces that
contain non-ASCII characters, we started checking for -ENOENT on every
file open, and if so, then send additional requests to figure out
whether it is a DFS link or not. It means that all those requests
will be sent to every non-existing file.
So, in order to reduce the number of roundtrips, check earlier whether
status code is STATUS_OBJECT_NAME_INVALID and tcon supports dfs, and
if so, then map -ENOENT to -EREMOTE so mount or automount will take
care of chasing the DFS link -- if it isn't an DFS link, then -ENOENT
will be returned appropriately.
Before patch
SMB2 438 Create Request File: ada.test\dfs\foo;GetInfo Request...
SMB2 310 Create Response, Error: STATUS_OBJECT_NAME_NOT_FOUND;...
SMB2 228 Ioctl Request FSCTL_DFS_GET_REFERRALS, File: \ada.test\dfs\foo
SMB2 143 Ioctl Response, Error: STATUS_OBJECT_PATH_NOT_FOUND
SMB2 438 Create Request File: ada.test\dfs\foo;GetInfo Request...
SMB2 310 Create Response, Error: STATUS_OBJECT_NAME_NOT_FOUND;...
SMB2 228 Ioctl Request FSCTL_DFS_GET_REFERRALS, File: \ada.test\dfs\foo
SMB2 143 Ioctl Response, Error: STATUS_OBJECT_PATH_NOT_FOUND
After patch
SMB2 438 Create Request File: ada.test\dfs\foo;GetInfo Request...
SMB2 310 Create Response, Error: STATUS_OBJECT_NAME_NOT_FOUND;...
SMB2 438 Create Request File: ada.test\dfs\foo;GetInfo Request...
SMB2 310 Create Response, Error: STATUS_OBJECT_NAME_NOT_FOUND;...
Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: Steve French <stfrench@microsoft.com>
2022-12-13 10:39:37 +08:00
|
|
|
goto out;
|
2022-10-04 05:43:50 +08:00
|
|
|
}
|
2023-08-17 23:34:06 +08:00
|
|
|
if (islink)
|
|
|
|
rc = -EREMOTE;
|
2013-10-23 21:49:47 +08:00
|
|
|
}
|
2011-12-29 21:06:33 +08:00
|
|
|
|
|
|
|
out:
|
2023-11-26 10:55:05 +08:00
|
|
|
for (i = 0; i < ARRAY_SIZE(out_buftype); i++)
|
|
|
|
free_rsp_buf(out_buftype[i], out_iov[i].iov_base);
|
2011-12-29 21:06:33 +08:00
|
|
|
return rc;
|
|
|
|
}
|
2011-07-19 16:56:37 +08:00
|
|
|
|
|
|
|
int
|
2019-09-25 13:32:13 +08:00
|
|
|
smb2_mkdir(const unsigned int xid, struct inode *parent_inode, umode_t mode,
|
|
|
|
struct cifs_tcon *tcon, const char *name,
|
2011-07-19 16:56:37 +08:00
|
|
|
struct cifs_sb_info *cifs_sb)
|
|
|
|
{
|
2024-01-26 06:21:48 +08:00
|
|
|
struct cifs_open_parms oparms;
|
|
|
|
|
|
|
|
oparms = CIFS_OPARMS(cifs_sb, tcon, name, FILE_WRITE_ATTRIBUTES,
|
|
|
|
FILE_CREATE, CREATE_NOT_FILE, mode);
|
|
|
|
return smb2_compound_op(xid, tcon, cifs_sb,
|
|
|
|
name, &oparms, NULL,
|
|
|
|
&(int){SMB2_OP_MKDIR}, 1,
|
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>
2024-03-06 11:43:51 +08:00
|
|
|
NULL, NULL, NULL, NULL);
|
2011-07-19 16:56:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
smb2_mkdir_setinfo(struct inode *inode, const char *name,
|
|
|
|
struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon,
|
|
|
|
const unsigned int xid)
|
|
|
|
{
|
2024-01-26 06:21:48 +08:00
|
|
|
struct cifs_open_parms oparms;
|
2023-11-26 10:55:02 +08:00
|
|
|
FILE_BASIC_INFO data = {};
|
2011-07-19 16:56:37 +08:00
|
|
|
struct cifsInodeInfo *cifs_i;
|
2019-08-30 07:53:56 +08:00
|
|
|
struct cifsFileInfo *cfile;
|
2023-11-26 10:55:02 +08:00
|
|
|
struct kvec in_iov;
|
2011-07-19 16:56:37 +08:00
|
|
|
u32 dosattrs;
|
|
|
|
int tmprc;
|
|
|
|
|
2023-11-26 10:55:02 +08:00
|
|
|
in_iov.iov_base = &data;
|
|
|
|
in_iov.iov_len = sizeof(data);
|
2011-07-19 16:56:37 +08:00
|
|
|
cifs_i = CIFS_I(inode);
|
|
|
|
dosattrs = cifs_i->cifsAttrs | ATTR_READONLY;
|
|
|
|
data.Attributes = cpu_to_le32(dosattrs);
|
cifs: fix rename() by ensuring source handle opened with DELETE bit
To rename a file in SMB2 we open it with the DELETE access and do a
special SetInfo on it. If the handle is missing the DELETE bit the
server will fail the SetInfo with STATUS_ACCESS_DENIED.
We currently try to reuse any existing opened handle we have with
cifs_get_writable_path(). That function looks for handles with WRITE
access but doesn't check for DELETE, making rename() fail if it finds
a handle to reuse. Simple reproducer below.
To select handles with the DELETE bit, this patch adds a flag argument
to cifs_get_writable_path() and find_writable_file() and the existing
'bool fsuid_only' argument is converted to a flag.
The cifsFileInfo struct only stores the UNIX open mode but not the
original SMB access flags. Since the DELETE bit is not mapped in that
mode, this patch stores the access mask in cifs_fid on file open,
which is accessible from cifsFileInfo.
Simple reproducer:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define E(s) perror(s), exit(1)
int main(int argc, char *argv[])
{
int fd, ret;
if (argc != 3) {
fprintf(stderr, "Usage: %s A B\n"
"create&open A in write mode, "
"rename A to B, close A\n", argv[0]);
return 0;
}
fd = openat(AT_FDCWD, argv[1], O_WRONLY|O_CREAT|O_SYNC, 0666);
if (fd == -1) E("openat()");
ret = rename(argv[1], argv[2]);
if (ret) E("rename()");
ret = close(fd);
if (ret) E("close()");
return ret;
}
$ gcc -o bugrename bugrename.c
$ ./bugrename /mnt/a /mnt/b
rename(): Permission denied
Fixes: 8de9e86c67ba ("cifs: create a helper to find a writeable handle by path name")
CC: Stable <stable@vger.kernel.org>
Signed-off-by: Aurelien Aptel <aaptel@suse.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com>
Reviewed-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
2020-02-21 18:19:06 +08:00
|
|
|
cifs_get_writable_path(tcon, name, FIND_WR_ANY, &cfile);
|
2024-01-26 06:21:48 +08:00
|
|
|
oparms = CIFS_OPARMS(cifs_sb, tcon, name, FILE_WRITE_ATTRIBUTES,
|
|
|
|
FILE_CREATE, CREATE_NOT_FILE, ACL_NO_MODE);
|
2018-09-03 11:33:48 +08:00
|
|
|
tmprc = smb2_compound_op(xid, tcon, cifs_sb, name,
|
2024-01-26 06:21:48 +08:00
|
|
|
&oparms, &in_iov,
|
2023-11-26 10:55:02 +08:00
|
|
|
&(int){SMB2_OP_SET_INFO}, 1,
|
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>
2024-03-06 11:43:51 +08:00
|
|
|
cfile, NULL, NULL, NULL);
|
2011-07-19 16:56:37 +08:00
|
|
|
if (tmprc == 0)
|
|
|
|
cifs_i->cifsAttrs = dosattrs;
|
|
|
|
}
|
2012-07-10 20:14:38 +08:00
|
|
|
|
|
|
|
int
|
|
|
|
smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
|
|
|
|
struct cifs_sb_info *cifs_sb)
|
|
|
|
{
|
2024-01-26 06:21:48 +08:00
|
|
|
struct cifs_open_parms oparms;
|
|
|
|
|
2022-10-18 15:39:10 +08:00
|
|
|
drop_cached_dir_by_name(xid, tcon, name, cifs_sb);
|
2024-01-26 06:21:48 +08:00
|
|
|
oparms = CIFS_OPARMS(cifs_sb, tcon, name, DELETE,
|
|
|
|
FILE_OPEN, CREATE_NOT_FILE, ACL_NO_MODE);
|
|
|
|
return smb2_compound_op(xid, tcon, cifs_sb,
|
|
|
|
name, &oparms, NULL,
|
2024-01-19 12:08:27 +08:00
|
|
|
&(int){SMB2_OP_RMDIR}, 1,
|
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>
2024-03-06 11:43:51 +08:00
|
|
|
NULL, NULL, NULL, NULL);
|
2012-07-10 20:14:38 +08:00
|
|
|
}
|
2012-09-19 07:20:25 +08:00
|
|
|
|
|
|
|
int
|
|
|
|
smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
|
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>
2024-03-06 11:43:51 +08:00
|
|
|
struct cifs_sb_info *cifs_sb, struct dentry *dentry)
|
2012-09-19 07:20:25 +08:00
|
|
|
{
|
2024-01-26 06:21:48 +08:00
|
|
|
struct cifs_open_parms oparms;
|
|
|
|
|
|
|
|
oparms = CIFS_OPARMS(cifs_sb, tcon, name,
|
|
|
|
DELETE, FILE_OPEN,
|
|
|
|
CREATE_DELETE_ON_CLOSE | OPEN_REPARSE_POINT,
|
|
|
|
ACL_NO_MODE);
|
|
|
|
int rc = smb2_compound_op(xid, tcon, cifs_sb, name, &oparms,
|
|
|
|
NULL, &(int){SMB2_OP_DELETE}, 1,
|
|
|
|
NULL, NULL, NULL, dentry);
|
2024-03-06 11:43:53 +08:00
|
|
|
if (rc == -EINVAL) {
|
|
|
|
cifs_dbg(FYI, "invalid lease key, resending request without lease");
|
2024-01-26 06:21:48 +08:00
|
|
|
rc = smb2_compound_op(xid, tcon, cifs_sb, name, &oparms,
|
|
|
|
NULL, &(int){SMB2_OP_DELETE}, 1,
|
|
|
|
NULL, NULL, NULL, NULL);
|
2024-03-06 11:43:53 +08:00
|
|
|
}
|
|
|
|
return rc;
|
2012-09-19 07:20:25 +08:00
|
|
|
}
|
2012-09-19 07:20:31 +08:00
|
|
|
|
2023-11-26 10:55:06 +08:00
|
|
|
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,
|
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>
2024-03-06 11:43:51 +08:00
|
|
|
int command, struct cifsFileInfo *cfile,
|
|
|
|
struct dentry *dentry)
|
2012-09-19 07:20:31 +08:00
|
|
|
{
|
2024-01-26 06:21:48 +08:00
|
|
|
struct cifs_open_parms oparms;
|
2023-11-26 10:55:02 +08:00
|
|
|
struct kvec in_iov;
|
2012-09-19 07:20:31 +08:00
|
|
|
__le16 *smb2_to_name = NULL;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
smb2_to_name = cifs_convert_path_to_utf16(to_name, cifs_sb);
|
|
|
|
if (smb2_to_name == NULL) {
|
|
|
|
rc = -ENOMEM;
|
|
|
|
goto smb2_rename_path;
|
|
|
|
}
|
2023-11-26 10:55:02 +08:00
|
|
|
in_iov.iov_base = smb2_to_name;
|
|
|
|
in_iov.iov_len = 2 * UniStrnlen((wchar_t *)smb2_to_name, PATH_MAX);
|
2024-01-26 06:21:48 +08:00
|
|
|
oparms = CIFS_OPARMS(cifs_sb, tcon, from_name, access, FILE_OPEN,
|
|
|
|
create_options, ACL_NO_MODE);
|
|
|
|
rc = smb2_compound_op(xid, tcon, cifs_sb, from_name,
|
|
|
|
&oparms, &in_iov, &command, 1,
|
|
|
|
cfile, NULL, NULL, dentry);
|
2012-09-19 07:20:31 +08:00
|
|
|
smb2_rename_path:
|
|
|
|
kfree(smb2_to_name);
|
|
|
|
return rc;
|
|
|
|
}
|
2012-09-19 07:20:31 +08:00
|
|
|
|
2023-11-26 10:55:06 +08:00
|
|
|
int smb2_rename_path(const unsigned int xid,
|
|
|
|
struct cifs_tcon *tcon,
|
|
|
|
struct dentry *source_dentry,
|
|
|
|
const char *from_name, const char *to_name,
|
|
|
|
struct cifs_sb_info *cifs_sb)
|
2012-09-19 07:20:31 +08:00
|
|
|
{
|
2019-08-30 06:25:46 +08:00
|
|
|
struct cifsFileInfo *cfile;
|
2023-11-26 10:55:07 +08:00
|
|
|
__u32 co = file_create_options(source_dentry);
|
2019-08-30 06:25:46 +08:00
|
|
|
|
2022-10-18 15:39:10 +08:00
|
|
|
drop_cached_dir_by_name(xid, tcon, from_name, cifs_sb);
|
cifs: fix rename() by ensuring source handle opened with DELETE bit
To rename a file in SMB2 we open it with the DELETE access and do a
special SetInfo on it. If the handle is missing the DELETE bit the
server will fail the SetInfo with STATUS_ACCESS_DENIED.
We currently try to reuse any existing opened handle we have with
cifs_get_writable_path(). That function looks for handles with WRITE
access but doesn't check for DELETE, making rename() fail if it finds
a handle to reuse. Simple reproducer below.
To select handles with the DELETE bit, this patch adds a flag argument
to cifs_get_writable_path() and find_writable_file() and the existing
'bool fsuid_only' argument is converted to a flag.
The cifsFileInfo struct only stores the UNIX open mode but not the
original SMB access flags. Since the DELETE bit is not mapped in that
mode, this patch stores the access mask in cifs_fid on file open,
which is accessible from cifsFileInfo.
Simple reproducer:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define E(s) perror(s), exit(1)
int main(int argc, char *argv[])
{
int fd, ret;
if (argc != 3) {
fprintf(stderr, "Usage: %s A B\n"
"create&open A in write mode, "
"rename A to B, close A\n", argv[0]);
return 0;
}
fd = openat(AT_FDCWD, argv[1], O_WRONLY|O_CREAT|O_SYNC, 0666);
if (fd == -1) E("openat()");
ret = rename(argv[1], argv[2]);
if (ret) E("rename()");
ret = close(fd);
if (ret) E("close()");
return ret;
}
$ gcc -o bugrename bugrename.c
$ ./bugrename /mnt/a /mnt/b
rename(): Permission denied
Fixes: 8de9e86c67ba ("cifs: create a helper to find a writeable handle by path name")
CC: Stable <stable@vger.kernel.org>
Signed-off-by: Aurelien Aptel <aaptel@suse.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com>
Reviewed-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
2020-02-21 18:19:06 +08:00
|
|
|
cifs_get_writable_path(tcon, from_name, FIND_WR_WITH_DELETE, &cfile);
|
2019-08-30 06:25:46 +08:00
|
|
|
|
2024-03-06 11:43:53 +08:00
|
|
|
int rc = smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
|
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>
2024-03-06 11:43:51 +08:00
|
|
|
co, DELETE, SMB2_OP_RENAME, cfile, source_dentry);
|
2024-03-06 11:43:53 +08:00
|
|
|
if (rc == -EINVAL) {
|
|
|
|
cifs_dbg(FYI, "invalid lease key, resending request without lease");
|
|
|
|
rc = smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
|
|
|
|
co, DELETE, SMB2_OP_RENAME, cfile, NULL);
|
|
|
|
}
|
|
|
|
return rc;
|
2012-09-19 07:20:31 +08:00
|
|
|
}
|
|
|
|
|
2023-11-26 10:55:07 +08:00
|
|
|
int smb2_create_hardlink(const unsigned int xid,
|
|
|
|
struct cifs_tcon *tcon,
|
|
|
|
struct dentry *source_dentry,
|
|
|
|
const char *from_name, const char *to_name,
|
|
|
|
struct cifs_sb_info *cifs_sb)
|
2012-09-19 07:20:31 +08:00
|
|
|
{
|
2023-11-26 10:55:07 +08:00
|
|
|
__u32 co = file_create_options(source_dentry);
|
|
|
|
|
2023-11-26 10:55:06 +08:00
|
|
|
return smb2_set_path_attr(xid, tcon, from_name, to_name,
|
2023-11-26 10:55:07 +08:00
|
|
|
cifs_sb, co, FILE_READ_ATTRIBUTES,
|
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>
2024-03-06 11:43:51 +08:00
|
|
|
SMB2_OP_HARDLINK, NULL, NULL);
|
2012-09-19 07:20:31 +08:00
|
|
|
}
|
2012-09-19 07:20:32 +08:00
|
|
|
|
|
|
|
int
|
|
|
|
smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
|
const char *full_path, __u64 size,
|
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>
2024-03-06 11:43:51 +08:00
|
|
|
struct cifs_sb_info *cifs_sb, bool set_alloc,
|
|
|
|
struct dentry *dentry)
|
2012-09-19 07:20:32 +08:00
|
|
|
{
|
2024-01-26 06:21:48 +08:00
|
|
|
struct cifs_open_parms oparms;
|
2021-07-30 14:43:09 +08:00
|
|
|
struct cifsFileInfo *cfile;
|
2023-11-26 10:55:02 +08:00
|
|
|
struct kvec in_iov;
|
|
|
|
__le64 eof = cpu_to_le64(size);
|
2024-01-26 06:21:48 +08:00
|
|
|
int rc;
|
2018-09-03 11:33:46 +08:00
|
|
|
|
2023-11-26 10:55:02 +08:00
|
|
|
in_iov.iov_base = &eof;
|
|
|
|
in_iov.iov_len = sizeof(eof);
|
2021-07-30 14:43:09 +08:00
|
|
|
cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
|
2024-01-26 06:21:48 +08:00
|
|
|
|
|
|
|
oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, FILE_WRITE_DATA,
|
|
|
|
FILE_OPEN, 0, ACL_NO_MODE);
|
|
|
|
rc = smb2_compound_op(xid, tcon, cifs_sb,
|
|
|
|
full_path, &oparms, &in_iov,
|
|
|
|
&(int){SMB2_OP_SET_EOF}, 1,
|
|
|
|
cfile, NULL, NULL, dentry);
|
2024-03-06 11:43:53 +08:00
|
|
|
if (rc == -EINVAL) {
|
|
|
|
cifs_dbg(FYI, "invalid lease key, resending request without lease");
|
2024-01-26 06:21:48 +08:00
|
|
|
rc = smb2_compound_op(xid, tcon, cifs_sb,
|
|
|
|
full_path, &oparms, &in_iov,
|
|
|
|
&(int){SMB2_OP_SET_EOF}, 1,
|
|
|
|
cfile, NULL, NULL, NULL);
|
2024-03-06 11:43:53 +08:00
|
|
|
}
|
|
|
|
return rc;
|
2012-09-19 07:20:32 +08:00
|
|
|
}
|
2012-09-19 07:20:32 +08:00
|
|
|
|
|
|
|
int
|
|
|
|
smb2_set_file_info(struct inode *inode, const char *full_path,
|
|
|
|
FILE_BASIC_INFO *buf, const unsigned int xid)
|
|
|
|
{
|
2024-01-26 06:21:48 +08:00
|
|
|
struct cifs_open_parms oparms;
|
2012-09-19 07:20:32 +08:00
|
|
|
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
|
|
|
|
struct tcon_link *tlink;
|
2021-07-30 14:43:09 +08:00
|
|
|
struct cifs_tcon *tcon;
|
|
|
|
struct cifsFileInfo *cfile;
|
2023-11-26 10:55:02 +08:00
|
|
|
struct kvec in_iov = { .iov_base = buf, .iov_len = sizeof(*buf), };
|
2012-09-19 07:20:32 +08:00
|
|
|
int rc;
|
|
|
|
|
2016-09-27 03:23:08 +08:00
|
|
|
if ((buf->CreationTime == 0) && (buf->LastAccessTime == 0) &&
|
2018-08-03 09:28:18 +08:00
|
|
|
(buf->LastWriteTime == 0) && (buf->ChangeTime == 0) &&
|
2016-09-27 03:23:08 +08:00
|
|
|
(buf->Attributes == 0))
|
|
|
|
return 0; /* would be a no op, no sense sending this */
|
|
|
|
|
2012-09-19 07:20:32 +08:00
|
|
|
tlink = cifs_sb_tlink(cifs_sb);
|
|
|
|
if (IS_ERR(tlink))
|
|
|
|
return PTR_ERR(tlink);
|
2021-07-30 14:43:09 +08:00
|
|
|
tcon = tlink_tcon(tlink);
|
2016-09-27 03:23:08 +08:00
|
|
|
|
2021-07-30 14:43:09 +08:00
|
|
|
cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
|
2024-01-26 06:21:48 +08:00
|
|
|
oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, FILE_WRITE_ATTRIBUTES,
|
|
|
|
FILE_OPEN, 0, ACL_NO_MODE);
|
|
|
|
rc = smb2_compound_op(xid, tcon, cifs_sb,
|
|
|
|
full_path, &oparms, &in_iov,
|
2024-01-19 12:08:27 +08:00
|
|
|
&(int){SMB2_OP_SET_INFO}, 1,
|
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>
2024-03-06 11:43:51 +08:00
|
|
|
cfile, NULL, NULL, NULL);
|
2012-09-19 07:20:32 +08:00
|
|
|
cifs_put_tlink(tlink);
|
|
|
|
return rc;
|
|
|
|
}
|
2023-11-26 10:55:03 +08:00
|
|
|
|
|
|
|
struct inode *smb2_get_reparse_inode(struct cifs_open_info_data *data,
|
|
|
|
struct super_block *sb,
|
|
|
|
const unsigned int xid,
|
|
|
|
struct cifs_tcon *tcon,
|
|
|
|
const char *full_path,
|
2024-01-27 06:26:06 +08:00
|
|
|
struct kvec *reparse_iov,
|
|
|
|
struct kvec *xattr_iov)
|
2023-11-26 10:55:03 +08:00
|
|
|
{
|
2024-01-26 06:21:48 +08:00
|
|
|
struct cifs_open_parms oparms;
|
2023-11-26 10:55:03 +08:00
|
|
|
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
|
|
|
|
struct cifsFileInfo *cfile;
|
|
|
|
struct inode *new = NULL;
|
|
|
|
struct kvec in_iov[2];
|
|
|
|
int cmds[2];
|
|
|
|
int rc;
|
|
|
|
|
2024-01-26 06:21:48 +08:00
|
|
|
oparms = CIFS_OPARMS(cifs_sb, tcon, full_path,
|
|
|
|
SYNCHRONIZE | DELETE |
|
|
|
|
FILE_READ_ATTRIBUTES |
|
|
|
|
FILE_WRITE_ATTRIBUTES,
|
|
|
|
FILE_CREATE,
|
|
|
|
CREATE_NOT_DIR | OPEN_REPARSE_POINT,
|
|
|
|
ACL_NO_MODE);
|
2024-01-27 06:26:06 +08:00
|
|
|
if (xattr_iov)
|
|
|
|
oparms.ea_cctx = xattr_iov;
|
|
|
|
|
2023-11-26 10:55:03 +08:00
|
|
|
cmds[0] = SMB2_OP_SET_REPARSE;
|
2024-01-27 06:26:06 +08:00
|
|
|
in_iov[0] = *reparse_iov;
|
2023-11-26 10:55:03 +08:00
|
|
|
in_iov[1].iov_base = data;
|
|
|
|
in_iov[1].iov_len = sizeof(*data);
|
|
|
|
|
|
|
|
if (tcon->posix_extensions) {
|
|
|
|
cmds[1] = SMB2_OP_POSIX_QUERY_INFO;
|
|
|
|
cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
|
2024-01-26 06:21:48 +08:00
|
|
|
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms,
|
|
|
|
in_iov, cmds, 2, cfile, NULL, NULL, NULL);
|
2023-11-26 10:55:03 +08:00
|
|
|
if (!rc) {
|
|
|
|
rc = smb311_posix_get_inode_info(&new, full_path,
|
|
|
|
data, sb, xid);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
cmds[1] = SMB2_OP_QUERY_INFO;
|
|
|
|
cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
|
2024-01-26 06:21:48 +08:00
|
|
|
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms,
|
|
|
|
in_iov, cmds, 2, cfile, NULL, NULL, NULL);
|
2023-11-26 10:55:03 +08:00
|
|
|
if (!rc) {
|
|
|
|
rc = cifs_get_inode_info(&new, full_path,
|
|
|
|
data, sb, xid, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return rc ? ERR_PTR(rc) : new;
|
|
|
|
}
|
2023-11-26 10:55:08 +08:00
|
|
|
|
|
|
|
int smb2_query_reparse_point(const unsigned int xid,
|
|
|
|
struct cifs_tcon *tcon,
|
|
|
|
struct cifs_sb_info *cifs_sb,
|
|
|
|
const char *full_path,
|
|
|
|
u32 *tag, struct kvec *rsp,
|
|
|
|
int *rsp_buftype)
|
|
|
|
{
|
2024-01-26 06:21:48 +08:00
|
|
|
struct cifs_open_parms oparms;
|
2023-11-26 10:55:08 +08:00
|
|
|
struct cifs_open_info_data data = {};
|
|
|
|
struct cifsFileInfo *cfile;
|
|
|
|
struct kvec in_iov = { .iov_base = &data, .iov_len = sizeof(data), };
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path);
|
|
|
|
|
|
|
|
cifs_get_readable_path(tcon, full_path, &cfile);
|
2024-01-26 06:21:48 +08:00
|
|
|
oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, FILE_READ_ATTRIBUTES,
|
|
|
|
FILE_OPEN, OPEN_REPARSE_POINT, ACL_NO_MODE);
|
|
|
|
rc = smb2_compound_op(xid, tcon, cifs_sb,
|
|
|
|
full_path, &oparms, &in_iov,
|
2024-01-19 12:08:27 +08:00
|
|
|
&(int){SMB2_OP_GET_REPARSE}, 1,
|
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>
2024-03-06 11:43:51 +08:00
|
|
|
cfile, NULL, NULL, NULL);
|
2023-11-26 10:55:08 +08:00
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
*tag = data.reparse.tag;
|
|
|
|
*rsp = data.reparse.io.iov;
|
|
|
|
*rsp_buftype = data.reparse.io.buftype;
|
|
|
|
memset(&data.reparse.io.iov, 0, sizeof(data.reparse.io.iov));
|
|
|
|
data.reparse.io.buftype = CIFS_NO_BUFFER;
|
|
|
|
out:
|
|
|
|
cifs_free_open_info(&data);
|
|
|
|
return rc;
|
|
|
|
}
|