Merge tag '6.6-rc4-ksmbd-server-fixes' of git://git.samba.org/ksmbd

Pull smb server fixes from Steve French:
"Six SMB3 server fixes for various races found by RO0T Lab of Huawei:

- Fix oops when racing between oplock break ack and freeing file

- Simultaneous request fixes for parallel logoffs, and for parallel
lock requests

- Fixes for tree disconnect race, session expire race, and close/open
race"

* tag '6.6-rc4-ksmbd-server-fixes' of git://git.samba.org/ksmbd:
ksmbd: fix race condition between tree conn lookup and disconnect
ksmbd: fix race condition from parallel smb2 lock requests
ksmbd: fix race condition from parallel smb2 logoff requests
ksmbd: fix uaf in smb20_oplock_break_ack
ksmbd: fix race condition with fp
ksmbd: fix race condition between session lookup and expire

+152 -46
+2
fs/smb/server/connection.c
··· 84 spin_lock_init(&conn->llist_lock); 85 INIT_LIST_HEAD(&conn->lock_list); 86 87 down_write(&conn_list_lock); 88 list_add(&conn->conns_list, &conn_list); 89 up_write(&conn_list_lock);
··· 84 spin_lock_init(&conn->llist_lock); 85 INIT_LIST_HEAD(&conn->lock_list); 86 87 + init_rwsem(&conn->session_lock); 88 + 89 down_write(&conn_list_lock); 90 list_add(&conn->conns_list, &conn_list); 91 up_write(&conn_list_lock);
+1
fs/smb/server/connection.h
··· 50 struct nls_table *local_nls; 51 struct unicode_map *um; 52 struct list_head conns_list; 53 /* smb session 1 per user */ 54 struct xarray sessions; 55 unsigned long last_active;
··· 50 struct nls_table *local_nls; 51 struct unicode_map *um; 52 struct list_head conns_list; 53 + struct rw_semaphore session_lock; 54 /* smb session 1 per user */ 55 struct xarray sessions; 56 unsigned long last_active;
+39 -3
fs/smb/server/mgmt/tree_connect.c
··· 73 74 tree_conn->user = sess->user; 75 tree_conn->share_conf = sc; 76 status.tree_conn = tree_conn; 77 78 ret = xa_err(xa_store(&sess->tree_conns, tree_conn->id, tree_conn, 79 GFP_KERNEL)); ··· 96 return status; 97 } 98 99 int ksmbd_tree_conn_disconnect(struct ksmbd_session *sess, 100 struct ksmbd_tree_connect *tree_conn) 101 { 102 int ret; 103 104 ret = ksmbd_ipc_tree_disconnect_request(sess->id, tree_conn->id); 105 ksmbd_release_tree_conn_id(sess, tree_conn->id); 106 - xa_erase(&sess->tree_conns, tree_conn->id); 107 ksmbd_share_config_put(tree_conn->share_conf); 108 kfree(tree_conn); 109 return ret; ··· 133 { 134 struct ksmbd_tree_connect *tcon; 135 136 tcon = xa_load(&sess->tree_conns, id); 137 if (tcon) { 138 - if (test_bit(TREE_CONN_EXPIRE, &tcon->status)) 139 tcon = NULL; 140 } 141 142 return tcon; 143 } ··· 155 if (!sess) 156 return -EINVAL; 157 158 - xa_for_each(&sess->tree_conns, id, tc) 159 ret |= ksmbd_tree_conn_disconnect(sess, tc); 160 xa_destroy(&sess->tree_conns); 161 return ret; 162 }
··· 73 74 tree_conn->user = sess->user; 75 tree_conn->share_conf = sc; 76 + tree_conn->t_state = TREE_NEW; 77 status.tree_conn = tree_conn; 78 + atomic_set(&tree_conn->refcount, 1); 79 + init_waitqueue_head(&tree_conn->refcount_q); 80 81 ret = xa_err(xa_store(&sess->tree_conns, tree_conn->id, tree_conn, 82 GFP_KERNEL)); ··· 93 return status; 94 } 95 96 + void ksmbd_tree_connect_put(struct ksmbd_tree_connect *tcon) 97 + { 98 + /* 99 + * Checking waitqueue to releasing tree connect on 100 + * tree disconnect. waitqueue_active is safe because it 101 + * uses atomic operation for condition. 102 + */ 103 + if (!atomic_dec_return(&tcon->refcount) && 104 + waitqueue_active(&tcon->refcount_q)) 105 + wake_up(&tcon->refcount_q); 106 + } 107 + 108 int ksmbd_tree_conn_disconnect(struct ksmbd_session *sess, 109 struct ksmbd_tree_connect *tree_conn) 110 { 111 int ret; 112 113 + write_lock(&sess->tree_conns_lock); 114 + xa_erase(&sess->tree_conns, tree_conn->id); 115 + write_unlock(&sess->tree_conns_lock); 116 + 117 + if (!atomic_dec_and_test(&tree_conn->refcount)) 118 + wait_event(tree_conn->refcount_q, 119 + atomic_read(&tree_conn->refcount) == 0); 120 + 121 ret = ksmbd_ipc_tree_disconnect_request(sess->id, tree_conn->id); 122 ksmbd_release_tree_conn_id(sess, tree_conn->id); 123 ksmbd_share_config_put(tree_conn->share_conf); 124 kfree(tree_conn); 125 return ret; ··· 111 { 112 struct ksmbd_tree_connect *tcon; 113 114 + read_lock(&sess->tree_conns_lock); 115 tcon = xa_load(&sess->tree_conns, id); 116 if (tcon) { 117 + if (tcon->t_state != TREE_CONNECTED) 118 + tcon = NULL; 119 + else if (!atomic_inc_not_zero(&tcon->refcount)) 120 tcon = NULL; 121 } 122 + read_unlock(&sess->tree_conns_lock); 123 124 return tcon; 125 } ··· 129 if (!sess) 130 return -EINVAL; 131 132 + xa_for_each(&sess->tree_conns, id, tc) { 133 + write_lock(&sess->tree_conns_lock); 134 + if (tc->t_state == TREE_DISCONNECTED) { 135 + write_unlock(&sess->tree_conns_lock); 136 + ret = -ENOENT; 137 + continue; 138 + } 139 + tc->t_state = TREE_DISCONNECTED; 140 + write_unlock(&sess->tree_conns_lock); 141 + 142 ret |= ksmbd_tree_conn_disconnect(sess, tc); 143 + } 144 xa_destroy(&sess->tree_conns); 145 return ret; 146 }
+9 -2
fs/smb/server/mgmt/tree_connect.h
··· 14 struct ksmbd_user; 15 struct ksmbd_conn; 16 17 - #define TREE_CONN_EXPIRE 1 18 19 struct ksmbd_tree_connect { 20 int id; ··· 31 32 int maximal_access; 33 bool posix_extensions; 34 - unsigned long status; 35 }; 36 37 struct ksmbd_tree_conn_status { ··· 52 struct ksmbd_tree_conn_status 53 ksmbd_tree_conn_connect(struct ksmbd_conn *conn, struct ksmbd_session *sess, 54 const char *share_name); 55 56 int ksmbd_tree_conn_disconnect(struct ksmbd_session *sess, 57 struct ksmbd_tree_connect *tree_conn);
··· 14 struct ksmbd_user; 15 struct ksmbd_conn; 16 17 + enum { 18 + TREE_NEW = 0, 19 + TREE_CONNECTED, 20 + TREE_DISCONNECTED 21 + }; 22 23 struct ksmbd_tree_connect { 24 int id; ··· 27 28 int maximal_access; 29 bool posix_extensions; 30 + atomic_t refcount; 31 + wait_queue_head_t refcount_q; 32 + unsigned int t_state; 33 }; 34 35 struct ksmbd_tree_conn_status { ··· 46 struct ksmbd_tree_conn_status 47 ksmbd_tree_conn_connect(struct ksmbd_conn *conn, struct ksmbd_session *sess, 48 const char *share_name); 49 + void ksmbd_tree_connect_put(struct ksmbd_tree_connect *tcon); 50 51 int ksmbd_tree_conn_disconnect(struct ksmbd_session *sess, 52 struct ksmbd_tree_connect *tree_conn);
+8 -3
fs/smb/server/mgmt/user_session.c
··· 174 unsigned long id; 175 struct ksmbd_session *sess; 176 177 - down_write(&sessions_table_lock); 178 xa_for_each(&conn->sessions, id, sess) { 179 if (sess->state != SMB2_SESSION_VALID || 180 time_after(jiffies, ··· 185 continue; 186 } 187 } 188 - up_write(&sessions_table_lock); 189 } 190 191 int ksmbd_session_register(struct ksmbd_conn *conn, ··· 227 } 228 } 229 } 230 231 xa_for_each(&conn->sessions, id, sess) { 232 unsigned long chann_id; 233 struct channel *chann; ··· 246 ksmbd_session_destroy(sess); 247 } 248 } 249 - up_write(&sessions_table_lock); 250 } 251 252 struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn, ··· 254 { 255 struct ksmbd_session *sess; 256 257 sess = xa_load(&conn->sessions, id); 258 if (sess) 259 sess->last_active = jiffies; 260 return sess; 261 } 262 ··· 355 xa_init(&sess->ksmbd_chann_list); 356 xa_init(&sess->rpc_handle_list); 357 sess->sequence_number = 1; 358 359 ret = __init_smb2_session(sess); 360 if (ret)
··· 174 unsigned long id; 175 struct ksmbd_session *sess; 176 177 + down_write(&conn->session_lock); 178 xa_for_each(&conn->sessions, id, sess) { 179 if (sess->state != SMB2_SESSION_VALID || 180 time_after(jiffies, ··· 185 continue; 186 } 187 } 188 + up_write(&conn->session_lock); 189 } 190 191 int ksmbd_session_register(struct ksmbd_conn *conn, ··· 227 } 228 } 229 } 230 + up_write(&sessions_table_lock); 231 232 + down_write(&conn->session_lock); 233 xa_for_each(&conn->sessions, id, sess) { 234 unsigned long chann_id; 235 struct channel *chann; ··· 244 ksmbd_session_destroy(sess); 245 } 246 } 247 + up_write(&conn->session_lock); 248 } 249 250 struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn, ··· 252 { 253 struct ksmbd_session *sess; 254 255 + down_read(&conn->session_lock); 256 sess = xa_load(&conn->sessions, id); 257 if (sess) 258 sess->last_active = jiffies; 259 + up_read(&conn->session_lock); 260 return sess; 261 } 262 ··· 351 xa_init(&sess->ksmbd_chann_list); 352 xa_init(&sess->rpc_handle_list); 353 sess->sequence_number = 1; 354 + rwlock_init(&sess->tree_conns_lock); 355 356 ret = __init_smb2_session(sess); 357 if (ret)
+1
fs/smb/server/mgmt/user_session.h
··· 60 61 struct ksmbd_file_table file_table; 62 unsigned long last_active; 63 }; 64 65 static inline int test_session_flag(struct ksmbd_session *sess, int bit)
··· 60 61 struct ksmbd_file_table file_table; 62 unsigned long last_active; 63 + rwlock_t tree_conns_lock; 64 }; 65 66 static inline int test_session_flag(struct ksmbd_session *sess, int bit)
+2
fs/smb/server/server.c
··· 241 } while (is_chained == true); 242 243 send: 244 smb3_preauth_hash_rsp(work); 245 if (work->sess && work->sess->enc && work->encrypted && 246 conn->ops->encrypt_resp) {
··· 241 } while (is_chained == true); 242 243 send: 244 + if (work->tcon) 245 + ksmbd_tree_connect_put(work->tcon); 246 smb3_preauth_hash_rsp(work); 247 if (work->sess && work->sess->enc && work->encrypted && 248 conn->ops->encrypt_resp) {
+61 -35
fs/smb/server/smb2pdu.c
··· 1993 if (conn->posix_ext_supported) 1994 status.tree_conn->posix_extensions = true; 1995 1996 rsp->StructureSize = cpu_to_le16(16); 1997 out_err1: 1998 rsp->Capabilities = 0; ··· 2125 2126 ksmbd_debug(SMB, "request\n"); 2127 2128 rsp->StructureSize = cpu_to_le16(4); 2129 err = ksmbd_iov_pin_rsp(work, rsp, 2130 sizeof(struct smb2_tree_disconnect_rsp)); 2131 if (err) { 2132 rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES; 2133 - smb2_set_err_rsp(work); 2134 - return err; 2135 } 2136 2137 - if (!tcon || test_and_set_bit(TREE_CONN_EXPIRE, &tcon->status)) { 2138 - ksmbd_debug(SMB, "Invalid tid %d\n", req->hdr.Id.SyncId.TreeId); 2139 - 2140 - rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED; 2141 - smb2_set_err_rsp(work); 2142 - return -ENOENT; 2143 - } 2144 - 2145 - ksmbd_close_tree_conn_fds(work); 2146 - ksmbd_tree_conn_disconnect(sess, tcon); 2147 - work->tcon = NULL; 2148 return 0; 2149 } 2150 2151 /** ··· 2190 2191 ksmbd_debug(SMB, "request\n"); 2192 2193 - sess_id = le64_to_cpu(req->hdr.SessionId); 2194 - 2195 - rsp->StructureSize = cpu_to_le16(4); 2196 - err = ksmbd_iov_pin_rsp(work, rsp, sizeof(struct smb2_logoff_rsp)); 2197 - if (err) { 2198 - rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES; 2199 smb2_set_err_rsp(work); 2200 - return err; 2201 } 2202 - 2203 ksmbd_all_conn_set_status(sess_id, KSMBD_SESS_NEED_RECONNECT); 2204 ksmbd_close_session_fds(work); 2205 ksmbd_conn_wait_idle(conn, sess_id); 2206 ··· 2222 ksmbd_free_user(sess->user); 2223 sess->user = NULL; 2224 ksmbd_all_conn_set_status(sess_id, KSMBD_SESS_NEED_NEGOTIATE); 2225 return 0; 2226 } 2227 ··· 3404 } 3405 ksmbd_revert_fsids(work); 3406 err_out1: 3407 - if (!rc) 3408 rc = ksmbd_iov_pin_rsp(work, (void *)rsp, iov_len); 3409 if (rc) { 3410 if (rc == -EINVAL) 3411 rsp->hdr.Status = STATUS_INVALID_PARAMETER; ··· 7064 7065 ksmbd_debug(SMB, 7066 "would have to wait for getting lock\n"); 7067 - spin_lock(&work->conn->llist_lock); 7068 - list_add_tail(&smb_lock->clist, 7069 - &work->conn->lock_list); 7070 - spin_unlock(&work->conn->llist_lock); 7071 list_add(&smb_lock->llist, &rollback_list); 7072 7073 argv = kmalloc(sizeof(void *), GFP_KERNEL); ··· 7094 7095 if (work->state != KSMBD_WORK_ACTIVE) { 7096 list_del(&smb_lock->llist); 7097 - spin_lock(&work->conn->llist_lock); 7098 - list_del(&smb_lock->clist); 7099 - spin_unlock(&work->conn->llist_lock); 7100 locks_free_lock(flock); 7101 7102 if (work->state == KSMBD_WORK_CANCELLED) { ··· 7113 } 7114 7115 list_del(&smb_lock->llist); 7116 - spin_lock(&work->conn->llist_lock); 7117 - list_del(&smb_lock->clist); 7118 - spin_unlock(&work->conn->llist_lock); 7119 release_async_work(work); 7120 goto retry; 7121 } else if (!rc) { 7122 spin_lock(&work->conn->llist_lock); 7123 list_add_tail(&smb_lock->clist, 7124 &work->conn->lock_list); 7125 list_add_tail(&smb_lock->flist, 7126 &fp->lock_list); 7127 spin_unlock(&work->conn->llist_lock); 7128 - list_add(&smb_lock->llist, &rollback_list); 7129 ksmbd_debug(SMB, "successful in taking lock\n"); 7130 } else { 7131 goto out; ··· 8062 goto err_out; 8063 } 8064 8065 - opinfo_put(opinfo); 8066 - ksmbd_fd_put(work, fp); 8067 opinfo->op_state = OPLOCK_STATE_NONE; 8068 wake_up_interruptible_all(&opinfo->oplock_q); 8069 8070 rsp->StructureSize = cpu_to_le16(24); 8071 rsp->OplockLevel = rsp_oplevel;
··· 1993 if (conn->posix_ext_supported) 1994 status.tree_conn->posix_extensions = true; 1995 1996 + write_lock(&sess->tree_conns_lock); 1997 + status.tree_conn->t_state = TREE_CONNECTED; 1998 + write_unlock(&sess->tree_conns_lock); 1999 rsp->StructureSize = cpu_to_le16(16); 2000 out_err1: 2001 rsp->Capabilities = 0; ··· 2122 2123 ksmbd_debug(SMB, "request\n"); 2124 2125 + if (!tcon) { 2126 + ksmbd_debug(SMB, "Invalid tid %d\n", req->hdr.Id.SyncId.TreeId); 2127 + 2128 + rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED; 2129 + err = -ENOENT; 2130 + goto err_out; 2131 + } 2132 + 2133 + ksmbd_close_tree_conn_fds(work); 2134 + 2135 + write_lock(&sess->tree_conns_lock); 2136 + if (tcon->t_state == TREE_DISCONNECTED) { 2137 + write_unlock(&sess->tree_conns_lock); 2138 + rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED; 2139 + err = -ENOENT; 2140 + goto err_out; 2141 + } 2142 + 2143 + WARN_ON_ONCE(atomic_dec_and_test(&tcon->refcount)); 2144 + tcon->t_state = TREE_DISCONNECTED; 2145 + write_unlock(&sess->tree_conns_lock); 2146 + 2147 + err = ksmbd_tree_conn_disconnect(sess, tcon); 2148 + if (err) { 2149 + rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED; 2150 + goto err_out; 2151 + } 2152 + 2153 + work->tcon = NULL; 2154 + 2155 rsp->StructureSize = cpu_to_le16(4); 2156 err = ksmbd_iov_pin_rsp(work, rsp, 2157 sizeof(struct smb2_tree_disconnect_rsp)); 2158 if (err) { 2159 rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES; 2160 + goto err_out; 2161 } 2162 2163 return 0; 2164 + 2165 + err_out: 2166 + smb2_set_err_rsp(work); 2167 + return err; 2168 + 2169 } 2170 2171 /** ··· 2164 2165 ksmbd_debug(SMB, "request\n"); 2166 2167 + ksmbd_conn_lock(conn); 2168 + if (!ksmbd_conn_good(conn)) { 2169 + ksmbd_conn_unlock(conn); 2170 + rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED; 2171 smb2_set_err_rsp(work); 2172 + return -ENOENT; 2173 } 2174 + sess_id = le64_to_cpu(req->hdr.SessionId); 2175 ksmbd_all_conn_set_status(sess_id, KSMBD_SESS_NEED_RECONNECT); 2176 + ksmbd_conn_unlock(conn); 2177 + 2178 ksmbd_close_session_fds(work); 2179 ksmbd_conn_wait_idle(conn, sess_id); 2180 ··· 2196 ksmbd_free_user(sess->user); 2197 sess->user = NULL; 2198 ksmbd_all_conn_set_status(sess_id, KSMBD_SESS_NEED_NEGOTIATE); 2199 + 2200 + rsp->StructureSize = cpu_to_le16(4); 2201 + err = ksmbd_iov_pin_rsp(work, rsp, sizeof(struct smb2_logoff_rsp)); 2202 + if (err) { 2203 + rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES; 2204 + smb2_set_err_rsp(work); 2205 + return err; 2206 + } 2207 return 0; 2208 } 2209 ··· 3370 } 3371 ksmbd_revert_fsids(work); 3372 err_out1: 3373 + if (!rc) { 3374 + ksmbd_update_fstate(&work->sess->file_table, fp, FP_INITED); 3375 rc = ksmbd_iov_pin_rsp(work, (void *)rsp, iov_len); 3376 + } 3377 if (rc) { 3378 if (rc == -EINVAL) 3379 rsp->hdr.Status = STATUS_INVALID_PARAMETER; ··· 7028 7029 ksmbd_debug(SMB, 7030 "would have to wait for getting lock\n"); 7031 list_add(&smb_lock->llist, &rollback_list); 7032 7033 argv = kmalloc(sizeof(void *), GFP_KERNEL); ··· 7062 7063 if (work->state != KSMBD_WORK_ACTIVE) { 7064 list_del(&smb_lock->llist); 7065 locks_free_lock(flock); 7066 7067 if (work->state == KSMBD_WORK_CANCELLED) { ··· 7084 } 7085 7086 list_del(&smb_lock->llist); 7087 release_async_work(work); 7088 goto retry; 7089 } else if (!rc) { 7090 + list_add(&smb_lock->llist, &rollback_list); 7091 spin_lock(&work->conn->llist_lock); 7092 list_add_tail(&smb_lock->clist, 7093 &work->conn->lock_list); 7094 list_add_tail(&smb_lock->flist, 7095 &fp->lock_list); 7096 spin_unlock(&work->conn->llist_lock); 7097 ksmbd_debug(SMB, "successful in taking lock\n"); 7098 } else { 7099 goto out; ··· 8036 goto err_out; 8037 } 8038 8039 opinfo->op_state = OPLOCK_STATE_NONE; 8040 wake_up_interruptible_all(&opinfo->oplock_q); 8041 + opinfo_put(opinfo); 8042 + ksmbd_fd_put(work, fp); 8043 8044 rsp->StructureSize = cpu_to_le16(24); 8045 rsp->OplockLevel = rsp_oplevel;
+20 -3
fs/smb/server/vfs_cache.c
··· 333 334 static struct ksmbd_file *ksmbd_fp_get(struct ksmbd_file *fp) 335 { 336 if (!atomic_inc_not_zero(&fp->refcount)) 337 return NULL; 338 return fp; ··· 385 return 0; 386 387 ft = &work->sess->file_table; 388 - read_lock(&ft->lock); 389 fp = idr_find(ft->idr, id); 390 if (fp) { 391 set_close_state_blocked_works(fp); 392 393 - if (!atomic_dec_and_test(&fp->refcount)) 394 fp = NULL; 395 } 396 - read_unlock(&ft->lock); 397 398 if (!fp) 399 return -EINVAL; ··· 578 fp->tcon = work->tcon; 579 fp->volatile_id = KSMBD_NO_FID; 580 fp->persistent_id = KSMBD_NO_FID; 581 fp->f_ci = ksmbd_inode_get(fp); 582 583 if (!fp->f_ci) { ··· 598 err_out: 599 kmem_cache_free(filp_cache, fp); 600 return ERR_PTR(ret); 601 } 602 603 static int
··· 333 334 static struct ksmbd_file *ksmbd_fp_get(struct ksmbd_file *fp) 335 { 336 + if (fp->f_state != FP_INITED) 337 + return NULL; 338 + 339 if (!atomic_inc_not_zero(&fp->refcount)) 340 return NULL; 341 return fp; ··· 382 return 0; 383 384 ft = &work->sess->file_table; 385 + write_lock(&ft->lock); 386 fp = idr_find(ft->idr, id); 387 if (fp) { 388 set_close_state_blocked_works(fp); 389 390 + if (fp->f_state != FP_INITED) 391 fp = NULL; 392 + else { 393 + fp->f_state = FP_CLOSED; 394 + if (!atomic_dec_and_test(&fp->refcount)) 395 + fp = NULL; 396 + } 397 } 398 + write_unlock(&ft->lock); 399 400 if (!fp) 401 return -EINVAL; ··· 570 fp->tcon = work->tcon; 571 fp->volatile_id = KSMBD_NO_FID; 572 fp->persistent_id = KSMBD_NO_FID; 573 + fp->f_state = FP_NEW; 574 fp->f_ci = ksmbd_inode_get(fp); 575 576 if (!fp->f_ci) { ··· 589 err_out: 590 kmem_cache_free(filp_cache, fp); 591 return ERR_PTR(ret); 592 + } 593 + 594 + void ksmbd_update_fstate(struct ksmbd_file_table *ft, struct ksmbd_file *fp, 595 + unsigned int state) 596 + { 597 + write_lock(&ft->lock); 598 + fp->f_state = state; 599 + write_unlock(&ft->lock); 600 } 601 602 static int
+9
fs/smb/server/vfs_cache.h
··· 60 __le32 m_fattr; 61 }; 62 63 struct ksmbd_file { 64 struct file *filp; 65 u64 persistent_id; ··· 104 /* if ls is happening on directory, below is valid*/ 105 struct ksmbd_readdir_data readdir_data; 106 int dot_dotdot[2]; 107 }; 108 109 static inline void set_ctx_actor(struct dir_context *ctx, ··· 149 int ksmbd_init_global_file_table(void); 150 void ksmbd_free_global_file_table(void); 151 void ksmbd_set_fd_limit(unsigned long limit); 152 153 /* 154 * INODE hash
··· 60 __le32 m_fattr; 61 }; 62 63 + enum { 64 + FP_NEW = 0, 65 + FP_INITED, 66 + FP_CLOSED 67 + }; 68 + 69 struct ksmbd_file { 70 struct file *filp; 71 u64 persistent_id; ··· 98 /* if ls is happening on directory, below is valid*/ 99 struct ksmbd_readdir_data readdir_data; 100 int dot_dotdot[2]; 101 + unsigned int f_state; 102 }; 103 104 static inline void set_ctx_actor(struct dir_context *ctx, ··· 142 int ksmbd_init_global_file_table(void); 143 void ksmbd_free_global_file_table(void); 144 void ksmbd_set_fd_limit(unsigned long limit); 145 + void ksmbd_update_fstate(struct ksmbd_file_table *ft, struct ksmbd_file *fp, 146 + unsigned int state); 147 148 /* 149 * INODE hash