History

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

Linus Torvalds committed 3 years ago

Commit 37faf072 parents f707e40 33b235a10 files · +151 −45Browse files

Unified · Split

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

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t