7 ksmbd server fixes
-----BEGIN PGP SIGNATURE----- iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAmVDA3MACgkQiiy9cAdy T1GCoQv/UcMfvtHMCy3qU5LQQH/b2TVKay+0Ki6HFNIui5519YZzqidOT5PEnsiA wV0EFi1Xw6CvNu6j6rSqlFH9HG+ROk/j1CxiO4OCOuXFtV+0/mVHHR5TAfiHq6bE zHKoPULXnNB8vl6X9f1iRBL5IPU3iDUqdV7n1ujPwKMjf9XeoNROQW6Rya/JTTZK Yv/ykUW+OhOn8iL9cQH5nqjhV2NVbC+oRk+dQb/2wyiWmeU+7j5+kCCAmHIEnD/Z ffiU4IN2+amEk+Jlic3tsgkOUGFk5IZOWW4N6YEpKuyA3TFfbfKD2tlii2VtAiG3 bNVSZLDKDhn0lsAn9f2ye1xsRg3STO7sYW8zgiLok4CrQq3HL4nODUutrHy7+oLA r7ZDTzOQmDlc3f5vVBliDluFvL9wTzeSjaGTGikVj74C1+P0slnqHho3jzXvxH+V FTRdYMPj26Yl67fQEG65SvXYR/V3q1h+cLd+bBcNbGpSqgNqu5Ni3rKLSOAVHE7Q 408EbRC1 =gYgr -----END PGP SIGNATURE----- Merge tag '6.7-rc-ksmbd-server-fixes' of git://git.samba.org/ksmbd Pull smb server updates from Steve French: "Seven ksmbd server fixes: - logoff improvement for multichannel bound connections - unicode fix for surrogate pairs - RDMA (smbdirect) fix for IB devices - fix locking deadlock in kern_path_create during rename - iov memory allocation fix - two minor cleanup patches (doc cleanup, and unused variable)" * tag '6.7-rc-ksmbd-server-fixes' of git://git.samba.org/ksmbd: ksmbd: no need to wait for binded connection termination at logoff ksmbd: add support for surrogate pair conversion ksmbd: fix missing RDMA-capable flag for IPoIB device in ksmbd_rdma_capable_netdev() ksmbd: fix recursive locking in vfs helpers ksmbd: fix kernel-doc comment of ksmbd_vfs_setxattr() ksmbd: reorganize ksmbd_iov_pin_rsp() ksmbd: Remove unused field in ksmbd_user struct
This commit is contained in:
commit
4652b8e4f3
@ -167,23 +167,7 @@ void ksmbd_all_conn_set_status(u64 sess_id, u32 status)
|
||||
|
||||
void ksmbd_conn_wait_idle(struct ksmbd_conn *conn, u64 sess_id)
|
||||
{
|
||||
struct ksmbd_conn *bind_conn;
|
||||
|
||||
wait_event(conn->req_running_q, atomic_read(&conn->req_running) < 2);
|
||||
|
||||
down_read(&conn_list_lock);
|
||||
list_for_each_entry(bind_conn, &conn_list, conns_list) {
|
||||
if (bind_conn == conn)
|
||||
continue;
|
||||
|
||||
if ((bind_conn->binding || xa_load(&bind_conn->sessions, sess_id)) &&
|
||||
!ksmbd_conn_releasing(bind_conn) &&
|
||||
atomic_read(&bind_conn->req_running)) {
|
||||
wait_event(bind_conn->req_running_q,
|
||||
atomic_read(&bind_conn->req_running) == 0);
|
||||
}
|
||||
}
|
||||
up_read(&conn_list_lock);
|
||||
}
|
||||
|
||||
int ksmbd_conn_write(struct ksmbd_work *work)
|
||||
|
@ -95,11 +95,28 @@ bool ksmbd_queue_work(struct ksmbd_work *work)
|
||||
return queue_work(ksmbd_wq, &work->work);
|
||||
}
|
||||
|
||||
static int ksmbd_realloc_iov_pin(struct ksmbd_work *work, void *ib,
|
||||
unsigned int ib_len)
|
||||
static inline void __ksmbd_iov_pin(struct ksmbd_work *work, void *ib,
|
||||
unsigned int ib_len)
|
||||
{
|
||||
work->iov[++work->iov_idx].iov_base = ib;
|
||||
work->iov[work->iov_idx].iov_len = ib_len;
|
||||
work->iov_cnt++;
|
||||
}
|
||||
|
||||
if (work->iov_alloc_cnt <= work->iov_cnt) {
|
||||
static int __ksmbd_iov_pin_rsp(struct ksmbd_work *work, void *ib, int len,
|
||||
void *aux_buf, unsigned int aux_size)
|
||||
{
|
||||
struct aux_read *ar;
|
||||
int need_iov_cnt = 1;
|
||||
|
||||
if (aux_size) {
|
||||
need_iov_cnt++;
|
||||
ar = kmalloc(sizeof(struct aux_read), GFP_KERNEL);
|
||||
if (!ar)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (work->iov_alloc_cnt < work->iov_cnt + need_iov_cnt) {
|
||||
struct kvec *new;
|
||||
|
||||
work->iov_alloc_cnt += 4;
|
||||
@ -111,16 +128,6 @@ static int ksmbd_realloc_iov_pin(struct ksmbd_work *work, void *ib,
|
||||
work->iov = new;
|
||||
}
|
||||
|
||||
work->iov[++work->iov_idx].iov_base = ib;
|
||||
work->iov[work->iov_idx].iov_len = ib_len;
|
||||
work->iov_cnt++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __ksmbd_iov_pin_rsp(struct ksmbd_work *work, void *ib, int len,
|
||||
void *aux_buf, unsigned int aux_size)
|
||||
{
|
||||
/* Plus rfc_length size on first iov */
|
||||
if (!work->iov_idx) {
|
||||
work->iov[work->iov_idx].iov_base = work->response_buf;
|
||||
@ -129,19 +136,13 @@ static int __ksmbd_iov_pin_rsp(struct ksmbd_work *work, void *ib, int len,
|
||||
work->iov_cnt++;
|
||||
}
|
||||
|
||||
ksmbd_realloc_iov_pin(work, ib, len);
|
||||
__ksmbd_iov_pin(work, ib, len);
|
||||
inc_rfc1001_len(work->iov[0].iov_base, len);
|
||||
|
||||
if (aux_size) {
|
||||
struct aux_read *ar;
|
||||
|
||||
ksmbd_realloc_iov_pin(work, aux_buf, aux_size);
|
||||
__ksmbd_iov_pin(work, aux_buf, aux_size);
|
||||
inc_rfc1001_len(work->iov[0].iov_base, aux_size);
|
||||
|
||||
ar = kmalloc(sizeof(struct aux_read), GFP_KERNEL);
|
||||
if (!ar)
|
||||
return -ENOMEM;
|
||||
|
||||
ar->buf = aux_buf;
|
||||
list_add(&ar->entry, &work->aux_read_list);
|
||||
}
|
||||
|
@ -18,7 +18,6 @@ struct ksmbd_user {
|
||||
|
||||
size_t passkey_sz;
|
||||
char *passkey;
|
||||
unsigned int failed_login_count;
|
||||
};
|
||||
|
||||
static inline bool user_guest(struct ksmbd_user *user)
|
||||
|
@ -2140,8 +2140,7 @@ static int smb_direct_ib_client_add(struct ib_device *ib_dev)
|
||||
if (ib_dev->node_type != RDMA_NODE_IB_CA)
|
||||
smb_direct_port = SMB_DIRECT_PORT_IWARP;
|
||||
|
||||
if (!ib_dev->ops.get_netdev ||
|
||||
!rdma_frwr_is_supported(&ib_dev->attrs))
|
||||
if (!rdma_frwr_is_supported(&ib_dev->attrs))
|
||||
return 0;
|
||||
|
||||
smb_dev = kzalloc(sizeof(*smb_dev), GFP_KERNEL);
|
||||
@ -2241,17 +2240,38 @@ bool ksmbd_rdma_capable_netdev(struct net_device *netdev)
|
||||
for (i = 0; i < smb_dev->ib_dev->phys_port_cnt; i++) {
|
||||
struct net_device *ndev;
|
||||
|
||||
ndev = smb_dev->ib_dev->ops.get_netdev(smb_dev->ib_dev,
|
||||
i + 1);
|
||||
if (!ndev)
|
||||
continue;
|
||||
if (smb_dev->ib_dev->ops.get_netdev) {
|
||||
ndev = smb_dev->ib_dev->ops.get_netdev(
|
||||
smb_dev->ib_dev, i + 1);
|
||||
if (!ndev)
|
||||
continue;
|
||||
|
||||
if (ndev == netdev) {
|
||||
if (ndev == netdev) {
|
||||
dev_put(ndev);
|
||||
rdma_capable = true;
|
||||
goto out;
|
||||
}
|
||||
dev_put(ndev);
|
||||
rdma_capable = true;
|
||||
goto out;
|
||||
/* if ib_dev does not implement ops.get_netdev
|
||||
* check for matching infiniband GUID in hw_addr
|
||||
*/
|
||||
} else if (netdev->type == ARPHRD_INFINIBAND) {
|
||||
struct netdev_hw_addr *ha;
|
||||
union ib_gid gid;
|
||||
u32 port_num;
|
||||
int ret;
|
||||
|
||||
netdev_hw_addr_list_for_each(
|
||||
ha, &netdev->dev_addrs) {
|
||||
memcpy(&gid, ha->addr + 4, sizeof(gid));
|
||||
ret = ib_find_gid(smb_dev->ib_dev, &gid,
|
||||
&port_num, NULL);
|
||||
if (!ret) {
|
||||
rdma_capable = true;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
dev_put(ndev);
|
||||
}
|
||||
}
|
||||
out:
|
||||
|
@ -13,46 +13,10 @@
|
||||
#include "unicode.h"
|
||||
#include "smb_common.h"
|
||||
|
||||
/*
|
||||
* smb_utf16_bytes() - how long will a string be after conversion?
|
||||
* @from: pointer to input string
|
||||
* @maxbytes: don't go past this many bytes of input string
|
||||
* @codepage: destination codepage
|
||||
*
|
||||
* Walk a utf16le string and return the number of bytes that the string will
|
||||
* be after being converted to the given charset, not including any null
|
||||
* termination required. Don't walk past maxbytes in the source buffer.
|
||||
*
|
||||
* Return: string length after conversion
|
||||
*/
|
||||
static int smb_utf16_bytes(const __le16 *from, int maxbytes,
|
||||
const struct nls_table *codepage)
|
||||
{
|
||||
int i;
|
||||
int charlen, outlen = 0;
|
||||
int maxwords = maxbytes / 2;
|
||||
char tmp[NLS_MAX_CHARSET_SIZE];
|
||||
__u16 ftmp;
|
||||
|
||||
for (i = 0; i < maxwords; i++) {
|
||||
ftmp = get_unaligned_le16(&from[i]);
|
||||
if (ftmp == 0)
|
||||
break;
|
||||
|
||||
charlen = codepage->uni2char(ftmp, tmp, NLS_MAX_CHARSET_SIZE);
|
||||
if (charlen > 0)
|
||||
outlen += charlen;
|
||||
else
|
||||
outlen++;
|
||||
}
|
||||
|
||||
return outlen;
|
||||
}
|
||||
|
||||
/*
|
||||
* cifs_mapchar() - convert a host-endian char to proper char in codepage
|
||||
* @target: where converted character should be copied
|
||||
* @src_char: 2 byte host-endian source character
|
||||
* @from: host-endian source string
|
||||
* @cp: codepage to which character should be converted
|
||||
* @mapchar: should character be mapped according to mapchars mount option?
|
||||
*
|
||||
@ -63,10 +27,13 @@ static int smb_utf16_bytes(const __le16 *from, int maxbytes,
|
||||
* Return: string length after conversion
|
||||
*/
|
||||
static int
|
||||
cifs_mapchar(char *target, const __u16 src_char, const struct nls_table *cp,
|
||||
cifs_mapchar(char *target, const __u16 *from, const struct nls_table *cp,
|
||||
bool mapchar)
|
||||
{
|
||||
int len = 1;
|
||||
__u16 src_char;
|
||||
|
||||
src_char = *from;
|
||||
|
||||
if (!mapchar)
|
||||
goto cp_convert;
|
||||
@ -104,12 +71,66 @@ out:
|
||||
|
||||
cp_convert:
|
||||
len = cp->uni2char(src_char, target, NLS_MAX_CHARSET_SIZE);
|
||||
if (len <= 0) {
|
||||
*target = '?';
|
||||
len = 1;
|
||||
}
|
||||
if (len <= 0)
|
||||
goto surrogate_pair;
|
||||
|
||||
goto out;
|
||||
|
||||
surrogate_pair:
|
||||
/* convert SURROGATE_PAIR and IVS */
|
||||
if (strcmp(cp->charset, "utf8"))
|
||||
goto unknown;
|
||||
len = utf16s_to_utf8s(from, 3, UTF16_LITTLE_ENDIAN, target, 6);
|
||||
if (len <= 0)
|
||||
goto unknown;
|
||||
return len;
|
||||
|
||||
unknown:
|
||||
*target = '?';
|
||||
len = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* smb_utf16_bytes() - compute converted string length
|
||||
* @from: pointer to input string
|
||||
* @maxbytes: input string length
|
||||
* @codepage: destination codepage
|
||||
*
|
||||
* Walk a utf16le string and return the number of bytes that the string will
|
||||
* be after being converted to the given charset, not including any null
|
||||
* termination required. Don't walk past maxbytes in the source buffer.
|
||||
*
|
||||
* Return: string length after conversion
|
||||
*/
|
||||
static int smb_utf16_bytes(const __le16 *from, int maxbytes,
|
||||
const struct nls_table *codepage)
|
||||
{
|
||||
int i, j;
|
||||
int charlen, outlen = 0;
|
||||
int maxwords = maxbytes / 2;
|
||||
char tmp[NLS_MAX_CHARSET_SIZE];
|
||||
__u16 ftmp[3];
|
||||
|
||||
for (i = 0; i < maxwords; i++) {
|
||||
ftmp[0] = get_unaligned_le16(&from[i]);
|
||||
if (ftmp[0] == 0)
|
||||
break;
|
||||
for (j = 1; j <= 2; j++) {
|
||||
if (i + j < maxwords)
|
||||
ftmp[j] = get_unaligned_le16(&from[i + j]);
|
||||
else
|
||||
ftmp[j] = 0;
|
||||
}
|
||||
|
||||
charlen = cifs_mapchar(tmp, ftmp, codepage, 0);
|
||||
if (charlen > 0)
|
||||
outlen += charlen;
|
||||
else
|
||||
outlen++;
|
||||
}
|
||||
|
||||
return outlen;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -139,12 +160,12 @@ cp_convert:
|
||||
static int smb_from_utf16(char *to, const __le16 *from, int tolen, int fromlen,
|
||||
const struct nls_table *codepage, bool mapchar)
|
||||
{
|
||||
int i, charlen, safelen;
|
||||
int i, j, charlen, safelen;
|
||||
int outlen = 0;
|
||||
int nullsize = nls_nullsize(codepage);
|
||||
int fromwords = fromlen / 2;
|
||||
char tmp[NLS_MAX_CHARSET_SIZE];
|
||||
__u16 ftmp;
|
||||
__u16 ftmp[3]; /* ftmp[3] = 3array x 2bytes = 6bytes UTF-16 */
|
||||
|
||||
/*
|
||||
* because the chars can be of varying widths, we need to take care
|
||||
@ -155,9 +176,15 @@ static int smb_from_utf16(char *to, const __le16 *from, int tolen, int fromlen,
|
||||
safelen = tolen - (NLS_MAX_CHARSET_SIZE + nullsize);
|
||||
|
||||
for (i = 0; i < fromwords; i++) {
|
||||
ftmp = get_unaligned_le16(&from[i]);
|
||||
if (ftmp == 0)
|
||||
ftmp[0] = get_unaligned_le16(&from[i]);
|
||||
if (ftmp[0] == 0)
|
||||
break;
|
||||
for (j = 1; j <= 2; j++) {
|
||||
if (i + j < fromwords)
|
||||
ftmp[j] = get_unaligned_le16(&from[i + j]);
|
||||
else
|
||||
ftmp[j] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* check to see if converting this character might make the
|
||||
@ -172,6 +199,19 @@ static int smb_from_utf16(char *to, const __le16 *from, int tolen, int fromlen,
|
||||
/* put converted char into 'to' buffer */
|
||||
charlen = cifs_mapchar(&to[outlen], ftmp, codepage, mapchar);
|
||||
outlen += charlen;
|
||||
|
||||
/*
|
||||
* charlen (=bytes of UTF-8 for 1 character)
|
||||
* 4bytes UTF-8(surrogate pair) is charlen=4
|
||||
* (4bytes UTF-16 code)
|
||||
* 7-8bytes UTF-8(IVS) is charlen=3+4 or 4+4
|
||||
* (2 UTF-8 pairs divided to 2 UTF-16 pairs)
|
||||
*/
|
||||
if (charlen == 4)
|
||||
i++;
|
||||
else if (charlen >= 5)
|
||||
/* 5-6bytes UTF-8 */
|
||||
i += 2;
|
||||
}
|
||||
|
||||
/* properly null-terminate string */
|
||||
@ -306,6 +346,9 @@ int smbConvertToUTF16(__le16 *target, const char *source, int srclen,
|
||||
char src_char;
|
||||
__le16 dst_char;
|
||||
wchar_t tmp;
|
||||
wchar_t wchar_to[6]; /* UTF-16 */
|
||||
int ret;
|
||||
unicode_t u;
|
||||
|
||||
if (!mapchars)
|
||||
return smb_strtoUTF16(target, source, srclen, cp);
|
||||
@ -348,11 +391,57 @@ int smbConvertToUTF16(__le16 *target, const char *source, int srclen,
|
||||
* if no match, use question mark, which at least in
|
||||
* some cases serves as wild card
|
||||
*/
|
||||
if (charlen < 1) {
|
||||
dst_char = cpu_to_le16(0x003f);
|
||||
charlen = 1;
|
||||
if (charlen > 0)
|
||||
goto ctoUTF16;
|
||||
|
||||
/* convert SURROGATE_PAIR */
|
||||
if (strcmp(cp->charset, "utf8"))
|
||||
goto unknown;
|
||||
if (*(source + i) & 0x80) {
|
||||
charlen = utf8_to_utf32(source + i, 6, &u);
|
||||
if (charlen < 0)
|
||||
goto unknown;
|
||||
} else
|
||||
goto unknown;
|
||||
ret = utf8s_to_utf16s(source + i, charlen,
|
||||
UTF16_LITTLE_ENDIAN,
|
||||
wchar_to, 6);
|
||||
if (ret < 0)
|
||||
goto unknown;
|
||||
|
||||
i += charlen;
|
||||
dst_char = cpu_to_le16(*wchar_to);
|
||||
if (charlen <= 3)
|
||||
/* 1-3bytes UTF-8 to 2bytes UTF-16 */
|
||||
put_unaligned(dst_char, &target[j]);
|
||||
else if (charlen == 4) {
|
||||
/*
|
||||
* 4bytes UTF-8(surrogate pair) to 4bytes UTF-16
|
||||
* 7-8bytes UTF-8(IVS) divided to 2 UTF-16
|
||||
* (charlen=3+4 or 4+4)
|
||||
*/
|
||||
put_unaligned(dst_char, &target[j]);
|
||||
dst_char = cpu_to_le16(*(wchar_to + 1));
|
||||
j++;
|
||||
put_unaligned(dst_char, &target[j]);
|
||||
} else if (charlen >= 5) {
|
||||
/* 5-6bytes UTF-8 to 6bytes UTF-16 */
|
||||
put_unaligned(dst_char, &target[j]);
|
||||
dst_char = cpu_to_le16(*(wchar_to + 1));
|
||||
j++;
|
||||
put_unaligned(dst_char, &target[j]);
|
||||
dst_char = cpu_to_le16(*(wchar_to + 2));
|
||||
j++;
|
||||
put_unaligned(dst_char, &target[j]);
|
||||
}
|
||||
continue;
|
||||
|
||||
unknown:
|
||||
dst_char = cpu_to_le16(0x003f);
|
||||
charlen = 1;
|
||||
}
|
||||
|
||||
ctoUTF16:
|
||||
/*
|
||||
* character may take more than one byte in the source string,
|
||||
* but will take exactly two bytes in the target string
|
||||
|
@ -173,10 +173,6 @@ int ksmbd_vfs_create(struct ksmbd_work *work, const char *name, umode_t mode)
|
||||
return err;
|
||||
}
|
||||
|
||||
err = mnt_want_write(path.mnt);
|
||||
if (err)
|
||||
goto out_err;
|
||||
|
||||
mode |= S_IFREG;
|
||||
err = vfs_create(mnt_idmap(path.mnt), d_inode(path.dentry),
|
||||
dentry, mode, true);
|
||||
@ -186,9 +182,7 @@ int ksmbd_vfs_create(struct ksmbd_work *work, const char *name, umode_t mode)
|
||||
} else {
|
||||
pr_err("File(%s): creation failed (err:%d)\n", name, err);
|
||||
}
|
||||
mnt_drop_write(path.mnt);
|
||||
|
||||
out_err:
|
||||
done_path_create(&path, dentry);
|
||||
return err;
|
||||
}
|
||||
@ -219,10 +213,6 @@ int ksmbd_vfs_mkdir(struct ksmbd_work *work, const char *name, umode_t mode)
|
||||
return err;
|
||||
}
|
||||
|
||||
err = mnt_want_write(path.mnt);
|
||||
if (err)
|
||||
goto out_err2;
|
||||
|
||||
idmap = mnt_idmap(path.mnt);
|
||||
mode |= S_IFDIR;
|
||||
err = vfs_mkdir(idmap, d_inode(path.dentry), dentry, mode);
|
||||
@ -233,21 +223,19 @@ int ksmbd_vfs_mkdir(struct ksmbd_work *work, const char *name, umode_t mode)
|
||||
dentry->d_name.len);
|
||||
if (IS_ERR(d)) {
|
||||
err = PTR_ERR(d);
|
||||
goto out_err1;
|
||||
goto out_err;
|
||||
}
|
||||
if (unlikely(d_is_negative(d))) {
|
||||
dput(d);
|
||||
err = -ENOENT;
|
||||
goto out_err1;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
ksmbd_vfs_inherit_owner(work, d_inode(path.dentry), d_inode(d));
|
||||
dput(d);
|
||||
}
|
||||
|
||||
out_err1:
|
||||
mnt_drop_write(path.mnt);
|
||||
out_err2:
|
||||
out_err:
|
||||
done_path_create(&path, dentry);
|
||||
if (err)
|
||||
pr_err("mkdir(%s): creation failed (err:%d)\n", name, err);
|
||||
@ -665,16 +653,11 @@ int ksmbd_vfs_link(struct ksmbd_work *work, const char *oldname,
|
||||
goto out3;
|
||||
}
|
||||
|
||||
err = mnt_want_write(newpath.mnt);
|
||||
if (err)
|
||||
goto out3;
|
||||
|
||||
err = vfs_link(oldpath.dentry, mnt_idmap(newpath.mnt),
|
||||
d_inode(newpath.dentry),
|
||||
dentry, NULL);
|
||||
if (err)
|
||||
ksmbd_debug(VFS, "vfs_link failed err %d\n", err);
|
||||
mnt_drop_write(newpath.mnt);
|
||||
|
||||
out3:
|
||||
done_path_create(&newpath, dentry);
|
||||
@ -919,7 +902,7 @@ ssize_t ksmbd_vfs_getxattr(struct mnt_idmap *idmap,
|
||||
/**
|
||||
* ksmbd_vfs_setxattr() - vfs helper for smb set extended attributes value
|
||||
* @idmap: idmap of the relevant mount
|
||||
* @dentry: dentry to set XATTR at
|
||||
* @path: path of dentry to set XATTR at
|
||||
* @attr_name: xattr name for setxattr
|
||||
* @attr_value: xattr value to set
|
||||
* @attr_size: size of xattr value
|
||||
|
Loading…
x
Reference in New Issue
Block a user