Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

+194 -118
-16
fs/smb/server/connection.c
··· 167 167 168 168 void ksmbd_conn_wait_idle(struct ksmbd_conn *conn, u64 sess_id) 169 169 { 170 - struct ksmbd_conn *bind_conn; 171 - 172 170 wait_event(conn->req_running_q, atomic_read(&conn->req_running) < 2); 173 - 174 - down_read(&conn_list_lock); 175 - list_for_each_entry(bind_conn, &conn_list, conns_list) { 176 - if (bind_conn == conn) 177 - continue; 178 - 179 - if ((bind_conn->binding || xa_load(&bind_conn->sessions, sess_id)) && 180 - !ksmbd_conn_releasing(bind_conn) && 181 - atomic_read(&bind_conn->req_running)) { 182 - wait_event(bind_conn->req_running_q, 183 - atomic_read(&bind_conn->req_running) == 0); 184 - } 185 - } 186 - up_read(&conn_list_lock); 187 171 } 188 172 189 173 int ksmbd_conn_write(struct ksmbd_work *work)
+22 -21
fs/smb/server/ksmbd_work.c
··· 95 95 return queue_work(ksmbd_wq, &work->work); 96 96 } 97 97 98 - static int ksmbd_realloc_iov_pin(struct ksmbd_work *work, void *ib, 99 - unsigned int ib_len) 98 + static inline void __ksmbd_iov_pin(struct ksmbd_work *work, void *ib, 99 + unsigned int ib_len) 100 100 { 101 + work->iov[++work->iov_idx].iov_base = ib; 102 + work->iov[work->iov_idx].iov_len = ib_len; 103 + work->iov_cnt++; 104 + } 101 105 102 - if (work->iov_alloc_cnt <= work->iov_cnt) { 106 + static int __ksmbd_iov_pin_rsp(struct ksmbd_work *work, void *ib, int len, 107 + void *aux_buf, unsigned int aux_size) 108 + { 109 + struct aux_read *ar; 110 + int need_iov_cnt = 1; 111 + 112 + if (aux_size) { 113 + need_iov_cnt++; 114 + ar = kmalloc(sizeof(struct aux_read), GFP_KERNEL); 115 + if (!ar) 116 + return -ENOMEM; 117 + } 118 + 119 + if (work->iov_alloc_cnt < work->iov_cnt + need_iov_cnt) { 103 120 struct kvec *new; 104 121 105 122 work->iov_alloc_cnt += 4; ··· 128 111 work->iov = new; 129 112 } 130 113 131 - work->iov[++work->iov_idx].iov_base = ib; 132 - work->iov[work->iov_idx].iov_len = ib_len; 133 - work->iov_cnt++; 134 - 135 - return 0; 136 - } 137 - 138 - static int __ksmbd_iov_pin_rsp(struct ksmbd_work *work, void *ib, int len, 139 - void *aux_buf, unsigned int aux_size) 140 - { 141 114 /* Plus rfc_length size on first iov */ 142 115 if (!work->iov_idx) { 143 116 work->iov[work->iov_idx].iov_base = work->response_buf; ··· 136 129 work->iov_cnt++; 137 130 } 138 131 139 - ksmbd_realloc_iov_pin(work, ib, len); 132 + __ksmbd_iov_pin(work, ib, len); 140 133 inc_rfc1001_len(work->iov[0].iov_base, len); 141 134 142 135 if (aux_size) { 143 - struct aux_read *ar; 144 - 145 - ksmbd_realloc_iov_pin(work, aux_buf, aux_size); 136 + __ksmbd_iov_pin(work, aux_buf, aux_size); 146 137 inc_rfc1001_len(work->iov[0].iov_base, aux_size); 147 - 148 - ar = kmalloc(sizeof(struct aux_read), GFP_KERNEL); 149 - if (!ar) 150 - return -ENOMEM; 151 138 152 139 ar->buf = aux_buf; 153 140 list_add(&ar->entry, &work->aux_read_list);
-1
fs/smb/server/mgmt/user_config.h
··· 18 18 19 19 size_t passkey_sz; 20 20 char *passkey; 21 - unsigned int failed_login_count; 22 21 }; 23 22 24 23 static inline bool user_guest(struct ksmbd_user *user)
+30 -10
fs/smb/server/transport_rdma.c
··· 2140 2140 if (ib_dev->node_type != RDMA_NODE_IB_CA) 2141 2141 smb_direct_port = SMB_DIRECT_PORT_IWARP; 2142 2142 2143 - if (!ib_dev->ops.get_netdev || 2144 - !rdma_frwr_is_supported(&ib_dev->attrs)) 2143 + if (!rdma_frwr_is_supported(&ib_dev->attrs)) 2145 2144 return 0; 2146 2145 2147 2146 smb_dev = kzalloc(sizeof(*smb_dev), GFP_KERNEL); ··· 2240 2241 for (i = 0; i < smb_dev->ib_dev->phys_port_cnt; i++) { 2241 2242 struct net_device *ndev; 2242 2243 2243 - ndev = smb_dev->ib_dev->ops.get_netdev(smb_dev->ib_dev, 2244 - i + 1); 2245 - if (!ndev) 2246 - continue; 2244 + if (smb_dev->ib_dev->ops.get_netdev) { 2245 + ndev = smb_dev->ib_dev->ops.get_netdev( 2246 + smb_dev->ib_dev, i + 1); 2247 + if (!ndev) 2248 + continue; 2247 2249 2248 - if (ndev == netdev) { 2250 + if (ndev == netdev) { 2251 + dev_put(ndev); 2252 + rdma_capable = true; 2253 + goto out; 2254 + } 2249 2255 dev_put(ndev); 2250 - rdma_capable = true; 2251 - goto out; 2256 + /* if ib_dev does not implement ops.get_netdev 2257 + * check for matching infiniband GUID in hw_addr 2258 + */ 2259 + } else if (netdev->type == ARPHRD_INFINIBAND) { 2260 + struct netdev_hw_addr *ha; 2261 + union ib_gid gid; 2262 + u32 port_num; 2263 + int ret; 2264 + 2265 + netdev_hw_addr_list_for_each( 2266 + ha, &netdev->dev_addrs) { 2267 + memcpy(&gid, ha->addr + 4, sizeof(gid)); 2268 + ret = ib_find_gid(smb_dev->ib_dev, &gid, 2269 + &port_num, NULL); 2270 + if (!ret) { 2271 + rdma_capable = true; 2272 + goto out; 2273 + } 2274 + } 2252 2275 } 2253 - dev_put(ndev); 2254 2276 } 2255 2277 } 2256 2278 out:
+138 -49
fs/smb/server/unicode.c
··· 14 14 #include "smb_common.h" 15 15 16 16 /* 17 - * smb_utf16_bytes() - how long will a string be after conversion? 18 - * @from: pointer to input string 19 - * @maxbytes: don't go past this many bytes of input string 20 - * @codepage: destination codepage 21 - * 22 - * Walk a utf16le string and return the number of bytes that the string will 23 - * be after being converted to the given charset, not including any null 24 - * termination required. Don't walk past maxbytes in the source buffer. 25 - * 26 - * Return: string length after conversion 27 - */ 28 - static int smb_utf16_bytes(const __le16 *from, int maxbytes, 29 - const struct nls_table *codepage) 30 - { 31 - int i; 32 - int charlen, outlen = 0; 33 - int maxwords = maxbytes / 2; 34 - char tmp[NLS_MAX_CHARSET_SIZE]; 35 - __u16 ftmp; 36 - 37 - for (i = 0; i < maxwords; i++) { 38 - ftmp = get_unaligned_le16(&from[i]); 39 - if (ftmp == 0) 40 - break; 41 - 42 - charlen = codepage->uni2char(ftmp, tmp, NLS_MAX_CHARSET_SIZE); 43 - if (charlen > 0) 44 - outlen += charlen; 45 - else 46 - outlen++; 47 - } 48 - 49 - return outlen; 50 - } 51 - 52 - /* 53 17 * cifs_mapchar() - convert a host-endian char to proper char in codepage 54 18 * @target: where converted character should be copied 55 - * @src_char: 2 byte host-endian source character 19 + * @from: host-endian source string 56 20 * @cp: codepage to which character should be converted 57 21 * @mapchar: should character be mapped according to mapchars mount option? 58 22 * ··· 27 63 * Return: string length after conversion 28 64 */ 29 65 static int 30 - cifs_mapchar(char *target, const __u16 src_char, const struct nls_table *cp, 66 + cifs_mapchar(char *target, const __u16 *from, const struct nls_table *cp, 31 67 bool mapchar) 32 68 { 33 69 int len = 1; 70 + __u16 src_char; 71 + 72 + src_char = *from; 34 73 35 74 if (!mapchar) 36 75 goto cp_convert; ··· 71 104 72 105 cp_convert: 73 106 len = cp->uni2char(src_char, target, NLS_MAX_CHARSET_SIZE); 74 - if (len <= 0) { 75 - *target = '?'; 76 - len = 1; 77 - } 107 + if (len <= 0) 108 + goto surrogate_pair; 78 109 79 110 goto out; 111 + 112 + surrogate_pair: 113 + /* convert SURROGATE_PAIR and IVS */ 114 + if (strcmp(cp->charset, "utf8")) 115 + goto unknown; 116 + len = utf16s_to_utf8s(from, 3, UTF16_LITTLE_ENDIAN, target, 6); 117 + if (len <= 0) 118 + goto unknown; 119 + return len; 120 + 121 + unknown: 122 + *target = '?'; 123 + len = 1; 124 + goto out; 125 + } 126 + 127 + /* 128 + * smb_utf16_bytes() - compute converted string length 129 + * @from: pointer to input string 130 + * @maxbytes: input string length 131 + * @codepage: destination codepage 132 + * 133 + * Walk a utf16le string and return the number of bytes that the string will 134 + * be after being converted to the given charset, not including any null 135 + * termination required. Don't walk past maxbytes in the source buffer. 136 + * 137 + * Return: string length after conversion 138 + */ 139 + static int smb_utf16_bytes(const __le16 *from, int maxbytes, 140 + const struct nls_table *codepage) 141 + { 142 + int i, j; 143 + int charlen, outlen = 0; 144 + int maxwords = maxbytes / 2; 145 + char tmp[NLS_MAX_CHARSET_SIZE]; 146 + __u16 ftmp[3]; 147 + 148 + for (i = 0; i < maxwords; i++) { 149 + ftmp[0] = get_unaligned_le16(&from[i]); 150 + if (ftmp[0] == 0) 151 + break; 152 + for (j = 1; j <= 2; j++) { 153 + if (i + j < maxwords) 154 + ftmp[j] = get_unaligned_le16(&from[i + j]); 155 + else 156 + ftmp[j] = 0; 157 + } 158 + 159 + charlen = cifs_mapchar(tmp, ftmp, codepage, 0); 160 + if (charlen > 0) 161 + outlen += charlen; 162 + else 163 + outlen++; 164 + } 165 + 166 + return outlen; 80 167 } 81 168 82 169 /* ··· 160 139 static int smb_from_utf16(char *to, const __le16 *from, int tolen, int fromlen, 161 140 const struct nls_table *codepage, bool mapchar) 162 141 { 163 - int i, charlen, safelen; 142 + int i, j, charlen, safelen; 164 143 int outlen = 0; 165 144 int nullsize = nls_nullsize(codepage); 166 145 int fromwords = fromlen / 2; 167 146 char tmp[NLS_MAX_CHARSET_SIZE]; 168 - __u16 ftmp; 147 + __u16 ftmp[3]; /* ftmp[3] = 3array x 2bytes = 6bytes UTF-16 */ 169 148 170 149 /* 171 150 * because the chars can be of varying widths, we need to take care ··· 176 155 safelen = tolen - (NLS_MAX_CHARSET_SIZE + nullsize); 177 156 178 157 for (i = 0; i < fromwords; i++) { 179 - ftmp = get_unaligned_le16(&from[i]); 180 - if (ftmp == 0) 158 + ftmp[0] = get_unaligned_le16(&from[i]); 159 + if (ftmp[0] == 0) 181 160 break; 161 + for (j = 1; j <= 2; j++) { 162 + if (i + j < fromwords) 163 + ftmp[j] = get_unaligned_le16(&from[i + j]); 164 + else 165 + ftmp[j] = 0; 166 + } 182 167 183 168 /* 184 169 * check to see if converting this character might make the ··· 199 172 /* put converted char into 'to' buffer */ 200 173 charlen = cifs_mapchar(&to[outlen], ftmp, codepage, mapchar); 201 174 outlen += charlen; 175 + 176 + /* 177 + * charlen (=bytes of UTF-8 for 1 character) 178 + * 4bytes UTF-8(surrogate pair) is charlen=4 179 + * (4bytes UTF-16 code) 180 + * 7-8bytes UTF-8(IVS) is charlen=3+4 or 4+4 181 + * (2 UTF-8 pairs divided to 2 UTF-16 pairs) 182 + */ 183 + if (charlen == 4) 184 + i++; 185 + else if (charlen >= 5) 186 + /* 5-6bytes UTF-8 */ 187 + i += 2; 202 188 } 203 189 204 190 /* properly null-terminate string */ ··· 346 306 char src_char; 347 307 __le16 dst_char; 348 308 wchar_t tmp; 309 + wchar_t wchar_to[6]; /* UTF-16 */ 310 + int ret; 311 + unicode_t u; 349 312 350 313 if (!mapchars) 351 314 return smb_strtoUTF16(target, source, srclen, cp); ··· 391 348 * if no match, use question mark, which at least in 392 349 * some cases serves as wild card 393 350 */ 394 - if (charlen < 1) { 395 - dst_char = cpu_to_le16(0x003f); 396 - charlen = 1; 351 + if (charlen > 0) 352 + goto ctoUTF16; 353 + 354 + /* convert SURROGATE_PAIR */ 355 + if (strcmp(cp->charset, "utf8")) 356 + goto unknown; 357 + if (*(source + i) & 0x80) { 358 + charlen = utf8_to_utf32(source + i, 6, &u); 359 + if (charlen < 0) 360 + goto unknown; 361 + } else 362 + goto unknown; 363 + ret = utf8s_to_utf16s(source + i, charlen, 364 + UTF16_LITTLE_ENDIAN, 365 + wchar_to, 6); 366 + if (ret < 0) 367 + goto unknown; 368 + 369 + i += charlen; 370 + dst_char = cpu_to_le16(*wchar_to); 371 + if (charlen <= 3) 372 + /* 1-3bytes UTF-8 to 2bytes UTF-16 */ 373 + put_unaligned(dst_char, &target[j]); 374 + else if (charlen == 4) { 375 + /* 376 + * 4bytes UTF-8(surrogate pair) to 4bytes UTF-16 377 + * 7-8bytes UTF-8(IVS) divided to 2 UTF-16 378 + * (charlen=3+4 or 4+4) 379 + */ 380 + put_unaligned(dst_char, &target[j]); 381 + dst_char = cpu_to_le16(*(wchar_to + 1)); 382 + j++; 383 + put_unaligned(dst_char, &target[j]); 384 + } else if (charlen >= 5) { 385 + /* 5-6bytes UTF-8 to 6bytes UTF-16 */ 386 + put_unaligned(dst_char, &target[j]); 387 + dst_char = cpu_to_le16(*(wchar_to + 1)); 388 + j++; 389 + put_unaligned(dst_char, &target[j]); 390 + dst_char = cpu_to_le16(*(wchar_to + 2)); 391 + j++; 392 + put_unaligned(dst_char, &target[j]); 397 393 } 394 + continue; 395 + 396 + unknown: 397 + dst_char = cpu_to_le16(0x003f); 398 + charlen = 1; 398 399 } 400 + 401 + ctoUTF16: 399 402 /* 400 403 * character may take more than one byte in the source string, 401 404 * but will take exactly two bytes in the target string
+4 -21
fs/smb/server/vfs.c
··· 173 173 return err; 174 174 } 175 175 176 - err = mnt_want_write(path.mnt); 177 - if (err) 178 - goto out_err; 179 - 180 176 mode |= S_IFREG; 181 177 err = vfs_create(mnt_idmap(path.mnt), d_inode(path.dentry), 182 178 dentry, mode, true); ··· 182 186 } else { 183 187 pr_err("File(%s): creation failed (err:%d)\n", name, err); 184 188 } 185 - mnt_drop_write(path.mnt); 186 189 187 - out_err: 188 190 done_path_create(&path, dentry); 189 191 return err; 190 192 } ··· 213 219 return err; 214 220 } 215 221 216 - err = mnt_want_write(path.mnt); 217 - if (err) 218 - goto out_err2; 219 - 220 222 idmap = mnt_idmap(path.mnt); 221 223 mode |= S_IFDIR; 222 224 err = vfs_mkdir(idmap, d_inode(path.dentry), dentry, mode); ··· 223 233 dentry->d_name.len); 224 234 if (IS_ERR(d)) { 225 235 err = PTR_ERR(d); 226 - goto out_err1; 236 + goto out_err; 227 237 } 228 238 if (unlikely(d_is_negative(d))) { 229 239 dput(d); 230 240 err = -ENOENT; 231 - goto out_err1; 241 + goto out_err; 232 242 } 233 243 234 244 ksmbd_vfs_inherit_owner(work, d_inode(path.dentry), d_inode(d)); 235 245 dput(d); 236 246 } 237 247 238 - out_err1: 239 - mnt_drop_write(path.mnt); 240 - out_err2: 248 + out_err: 241 249 done_path_create(&path, dentry); 242 250 if (err) 243 251 pr_err("mkdir(%s): creation failed (err:%d)\n", name, err); ··· 653 665 goto out3; 654 666 } 655 667 656 - err = mnt_want_write(newpath.mnt); 657 - if (err) 658 - goto out3; 659 - 660 668 err = vfs_link(oldpath.dentry, mnt_idmap(newpath.mnt), 661 669 d_inode(newpath.dentry), 662 670 dentry, NULL); 663 671 if (err) 664 672 ksmbd_debug(VFS, "vfs_link failed err %d\n", err); 665 - mnt_drop_write(newpath.mnt); 666 673 667 674 out3: 668 675 done_path_create(&newpath, dentry); ··· 902 919 /** 903 920 * ksmbd_vfs_setxattr() - vfs helper for smb set extended attributes value 904 921 * @idmap: idmap of the relevant mount 905 - * @dentry: dentry to set XATTR at 922 + * @path: path of dentry to set XATTR at 906 923 * @attr_name: xattr name for setxattr 907 924 * @attr_value: xattr value to set 908 925 * @attr_size: size of xattr value