Skip to content

Commit 9330697

Browse files
committed
Merge tag '6.11-rc-smb3-server-fixes' of git://git.samba.org/ksmbd
Pull smb server fixes from Steve French: - two durable handle improvements - two small cleanup patches * tag '6.11-rc-smb3-server-fixes' of git://git.samba.org/ksmbd: ksmbd: add durable scavenger timer ksmbd: avoid reclaiming expired durable opens by the client ksmbd: Constify struct ksmbd_transport_ops ksmbd: remove duplicate SMB2 Oplock levels definitions
2 parents 527eff2 + d484d62 commit 9330697

File tree

11 files changed

+183
-20
lines changed

11 files changed

+183
-20
lines changed

fs/smb/server/connection.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,8 @@ struct ksmbd_transport_ops {
133133
};
134134

135135
struct ksmbd_transport {
136-
struct ksmbd_conn *conn;
137-
struct ksmbd_transport_ops *ops;
136+
struct ksmbd_conn *conn;
137+
const struct ksmbd_transport_ops *ops;
138138
};
139139

140140
#define KSMBD_TCP_RECV_TIMEOUT (7 * HZ)

fs/smb/server/mgmt/user_session.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ void ksmbd_session_destroy(struct ksmbd_session *sess)
149149

150150
ksmbd_tree_conn_session_logoff(sess);
151151
ksmbd_destroy_file_table(&sess->file_table);
152+
ksmbd_launch_ksmbd_durable_scavenger();
152153
ksmbd_session_rpc_clear_list(sess);
153154
free_channel_list(sess);
154155
kfree(sess->Preauth_HashValue);
@@ -326,6 +327,7 @@ void destroy_previous_session(struct ksmbd_conn *conn,
326327

327328
ksmbd_destroy_file_table(&prev_sess->file_table);
328329
prev_sess->state = SMB2_SESSION_EXPIRED;
330+
ksmbd_launch_ksmbd_durable_scavenger();
329331
out:
330332
up_write(&conn->session_lock);
331333
up_write(&sessions_table_lock);

fs/smb/server/oplock.h

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,6 @@
1111

1212
#define OPLOCK_WAIT_TIME (35 * HZ)
1313

14-
/* SMB2 Oplock levels */
15-
#define SMB2_OPLOCK_LEVEL_NONE 0x00
16-
#define SMB2_OPLOCK_LEVEL_II 0x01
17-
#define SMB2_OPLOCK_LEVEL_EXCLUSIVE 0x08
18-
#define SMB2_OPLOCK_LEVEL_BATCH 0x09
19-
#define SMB2_OPLOCK_LEVEL_LEASE 0xFF
20-
2114
/* Oplock states */
2215
#define OPLOCK_STATE_NONE 0x00
2316
#define OPLOCK_ACK_WAIT 0x01

fs/smb/server/server.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,7 @@ static void server_ctrl_handle_reset(struct server_ctrl_struct *ctrl)
377377
{
378378
ksmbd_ipc_soft_reset();
379379
ksmbd_conn_transport_destroy();
380+
ksmbd_stop_durable_scavenger();
380381
server_conf_free();
381382
server_conf_init();
382383
WRITE_ONCE(server_conf.state, SERVER_STATE_STARTING_UP);

fs/smb/server/server.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ struct ksmbd_server_config {
4444
unsigned int max_connections;
4545

4646
char *conf[SERVER_CONF_WORK_GROUP + 1];
47+
struct task_struct *dh_task;
4748
};
4849

4950
extern struct ksmbd_server_config server_conf;

fs/smb/server/smb2pdu.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3526,7 +3526,7 @@ int smb2_open(struct ksmbd_work *work)
35263526
SMB2_CREATE_GUID_SIZE);
35273527
if (dh_info.timeout)
35283528
fp->durable_timeout = min(dh_info.timeout,
3529-
300000);
3529+
DURABLE_HANDLE_MAX_TIMEOUT);
35303530
else
35313531
fp->durable_timeout = 60;
35323532
}

fs/smb/server/smb2pdu.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ struct create_durable_req_v2 {
7272
__u8 CreateGuid[16];
7373
} __packed;
7474

75+
#define DURABLE_HANDLE_MAX_TIMEOUT 300000
76+
7577
struct create_durable_reconn_req {
7678
struct create_context_hdr ccontext;
7779
__u8 Name[8];

fs/smb/server/transport_rdma.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ enum {
164164
SMB_DIRECT_MSG_DATA_TRANSFER
165165
};
166166

167-
static struct ksmbd_transport_ops ksmbd_smb_direct_transport_ops;
167+
static const struct ksmbd_transport_ops ksmbd_smb_direct_transport_ops;
168168

169169
struct smb_direct_send_ctx {
170170
struct list_head msg_list;
@@ -2292,7 +2292,7 @@ bool ksmbd_rdma_capable_netdev(struct net_device *netdev)
22922292
return rdma_capable;
22932293
}
22942294

2295-
static struct ksmbd_transport_ops ksmbd_smb_direct_transport_ops = {
2295+
static const struct ksmbd_transport_ops ksmbd_smb_direct_transport_ops = {
22962296
.prepare = smb_direct_prepare,
22972297
.disconnect = smb_direct_disconnect,
22982298
.shutdown = smb_direct_shutdown,

fs/smb/server/transport_tcp.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ struct tcp_transport {
3737
unsigned int nr_iov;
3838
};
3939

40-
static struct ksmbd_transport_ops ksmbd_tcp_transport_ops;
40+
static const struct ksmbd_transport_ops ksmbd_tcp_transport_ops;
4141

4242
static void tcp_stop_kthread(struct task_struct *kthread);
4343
static struct interface *alloc_iface(char *ifname);
@@ -649,7 +649,7 @@ int ksmbd_tcp_set_interfaces(char *ifc_list, int ifc_list_sz)
649649
return 0;
650650
}
651651

652-
static struct ksmbd_transport_ops ksmbd_tcp_transport_ops = {
652+
static const struct ksmbd_transport_ops ksmbd_tcp_transport_ops = {
653653
.read = ksmbd_tcp_read,
654654
.writev = ksmbd_tcp_writev,
655655
.disconnect = ksmbd_tcp_disconnect,

fs/smb/server/vfs_cache.c

Lines changed: 167 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
#include <linux/filelock.h>
99
#include <linux/slab.h>
1010
#include <linux/vmalloc.h>
11+
#include <linux/kthread.h>
12+
#include <linux/freezer.h>
1113

1214
#include "glob.h"
1315
#include "vfs_cache.h"
@@ -17,6 +19,7 @@
1719
#include "mgmt/tree_connect.h"
1820
#include "mgmt/user_session.h"
1921
#include "smb_common.h"
22+
#include "server.h"
2023

2124
#define S_DEL_PENDING 1
2225
#define S_DEL_ON_CLS 2
@@ -31,6 +34,10 @@ static struct ksmbd_file_table global_ft;
3134
static atomic_long_t fd_limit;
3235
static struct kmem_cache *filp_cache;
3336

37+
static bool durable_scavenger_running;
38+
static DEFINE_MUTEX(durable_scavenger_lock);
39+
static wait_queue_head_t dh_wq;
40+
3441
void ksmbd_set_fd_limit(unsigned long limit)
3542
{
3643
limit = min(limit, get_max_files());
@@ -280,9 +287,16 @@ static void __ksmbd_remove_durable_fd(struct ksmbd_file *fp)
280287
if (!has_file_id(fp->persistent_id))
281288
return;
282289

283-
write_lock(&global_ft.lock);
284290
idr_remove(global_ft.idr, fp->persistent_id);
291+
}
292+
293+
static void ksmbd_remove_durable_fd(struct ksmbd_file *fp)
294+
{
295+
write_lock(&global_ft.lock);
296+
__ksmbd_remove_durable_fd(fp);
285297
write_unlock(&global_ft.lock);
298+
if (waitqueue_active(&dh_wq))
299+
wake_up(&dh_wq);
286300
}
287301

288302
static void __ksmbd_remove_fd(struct ksmbd_file_table *ft, struct ksmbd_file *fp)
@@ -305,7 +319,7 @@ static void __ksmbd_close_fd(struct ksmbd_file_table *ft, struct ksmbd_file *fp)
305319
struct ksmbd_lock *smb_lock, *tmp_lock;
306320

307321
fd_limit_close();
308-
__ksmbd_remove_durable_fd(fp);
322+
ksmbd_remove_durable_fd(fp);
309323
if (ft)
310324
__ksmbd_remove_fd(ft, fp);
311325

@@ -477,7 +491,10 @@ struct ksmbd_file *ksmbd_lookup_durable_fd(unsigned long long id)
477491
struct ksmbd_file *fp;
478492

479493
fp = __ksmbd_lookup_fd(&global_ft, id);
480-
if (fp && fp->conn) {
494+
if (fp && (fp->conn ||
495+
(fp->durable_scavenger_timeout &&
496+
(fp->durable_scavenger_timeout <
497+
jiffies_to_msecs(jiffies))))) {
481498
ksmbd_put_durable_fd(fp);
482499
fp = NULL;
483500
}
@@ -694,6 +711,142 @@ static bool tree_conn_fd_check(struct ksmbd_tree_connect *tcon,
694711
return fp->tcon != tcon;
695712
}
696713

714+
static bool ksmbd_durable_scavenger_alive(void)
715+
{
716+
mutex_lock(&durable_scavenger_lock);
717+
if (!durable_scavenger_running) {
718+
mutex_unlock(&durable_scavenger_lock);
719+
return false;
720+
}
721+
mutex_unlock(&durable_scavenger_lock);
722+
723+
if (kthread_should_stop())
724+
return false;
725+
726+
if (idr_is_empty(global_ft.idr))
727+
return false;
728+
729+
return true;
730+
}
731+
732+
static void ksmbd_scavenger_dispose_dh(struct list_head *head)
733+
{
734+
while (!list_empty(head)) {
735+
struct ksmbd_file *fp;
736+
737+
fp = list_first_entry(head, struct ksmbd_file, node);
738+
list_del_init(&fp->node);
739+
__ksmbd_close_fd(NULL, fp);
740+
}
741+
}
742+
743+
static int ksmbd_durable_scavenger(void *dummy)
744+
{
745+
struct ksmbd_file *fp = NULL;
746+
unsigned int id;
747+
unsigned int min_timeout = 1;
748+
bool found_fp_timeout;
749+
LIST_HEAD(scavenger_list);
750+
unsigned long remaining_jiffies;
751+
752+
__module_get(THIS_MODULE);
753+
754+
set_freezable();
755+
while (ksmbd_durable_scavenger_alive()) {
756+
if (try_to_freeze())
757+
continue;
758+
759+
found_fp_timeout = false;
760+
761+
remaining_jiffies = wait_event_timeout(dh_wq,
762+
ksmbd_durable_scavenger_alive() == false,
763+
__msecs_to_jiffies(min_timeout));
764+
if (remaining_jiffies)
765+
min_timeout = jiffies_to_msecs(remaining_jiffies);
766+
else
767+
min_timeout = DURABLE_HANDLE_MAX_TIMEOUT;
768+
769+
write_lock(&global_ft.lock);
770+
idr_for_each_entry(global_ft.idr, fp, id) {
771+
if (!fp->durable_timeout)
772+
continue;
773+
774+
if (atomic_read(&fp->refcount) > 1 ||
775+
fp->conn)
776+
continue;
777+
778+
found_fp_timeout = true;
779+
if (fp->durable_scavenger_timeout <=
780+
jiffies_to_msecs(jiffies)) {
781+
__ksmbd_remove_durable_fd(fp);
782+
list_add(&fp->node, &scavenger_list);
783+
} else {
784+
unsigned long durable_timeout;
785+
786+
durable_timeout =
787+
fp->durable_scavenger_timeout -
788+
jiffies_to_msecs(jiffies);
789+
790+
if (min_timeout > durable_timeout)
791+
min_timeout = durable_timeout;
792+
}
793+
}
794+
write_unlock(&global_ft.lock);
795+
796+
ksmbd_scavenger_dispose_dh(&scavenger_list);
797+
798+
if (found_fp_timeout == false)
799+
break;
800+
}
801+
802+
mutex_lock(&durable_scavenger_lock);
803+
durable_scavenger_running = false;
804+
mutex_unlock(&durable_scavenger_lock);
805+
806+
module_put(THIS_MODULE);
807+
808+
return 0;
809+
}
810+
811+
void ksmbd_launch_ksmbd_durable_scavenger(void)
812+
{
813+
if (!(server_conf.flags & KSMBD_GLOBAL_FLAG_DURABLE_HANDLE))
814+
return;
815+
816+
mutex_lock(&durable_scavenger_lock);
817+
if (durable_scavenger_running == true) {
818+
mutex_unlock(&durable_scavenger_lock);
819+
return;
820+
}
821+
822+
durable_scavenger_running = true;
823+
824+
server_conf.dh_task = kthread_run(ksmbd_durable_scavenger,
825+
(void *)NULL, "ksmbd-durable-scavenger");
826+
if (IS_ERR(server_conf.dh_task))
827+
pr_err("cannot start conn thread, err : %ld\n",
828+
PTR_ERR(server_conf.dh_task));
829+
mutex_unlock(&durable_scavenger_lock);
830+
}
831+
832+
void ksmbd_stop_durable_scavenger(void)
833+
{
834+
if (!(server_conf.flags & KSMBD_GLOBAL_FLAG_DURABLE_HANDLE))
835+
return;
836+
837+
mutex_lock(&durable_scavenger_lock);
838+
if (!durable_scavenger_running) {
839+
mutex_unlock(&durable_scavenger_lock);
840+
return;
841+
}
842+
843+
durable_scavenger_running = false;
844+
if (waitqueue_active(&dh_wq))
845+
wake_up(&dh_wq);
846+
mutex_unlock(&durable_scavenger_lock);
847+
kthread_stop(server_conf.dh_task);
848+
}
849+
697850
static bool session_fd_check(struct ksmbd_tree_connect *tcon,
698851
struct ksmbd_file *fp)
699852
{
@@ -718,6 +871,10 @@ static bool session_fd_check(struct ksmbd_tree_connect *tcon,
718871
fp->tcon = NULL;
719872
fp->volatile_id = KSMBD_NO_FID;
720873

874+
if (fp->durable_timeout)
875+
fp->durable_scavenger_timeout =
876+
jiffies_to_msecs(jiffies) + fp->durable_timeout;
877+
721878
return true;
722879
}
723880

@@ -750,11 +907,12 @@ void ksmbd_free_global_file_table(void)
750907
unsigned int id;
751908

752909
idr_for_each_entry(global_ft.idr, fp, id) {
753-
__ksmbd_remove_durable_fd(fp);
754-
kmem_cache_free(filp_cache, fp);
910+
ksmbd_remove_durable_fd(fp);
911+
__ksmbd_close_fd(NULL, fp);
755912
}
756913

757-
ksmbd_destroy_file_table(&global_ft);
914+
idr_destroy(global_ft.idr);
915+
kfree(global_ft.idr);
758916
}
759917

760918
int ksmbd_validate_name_reconnect(struct ksmbd_share_config *share,
@@ -810,6 +968,7 @@ int ksmbd_reopen_durable_fd(struct ksmbd_work *work, struct ksmbd_file *fp)
810968
}
811969
up_write(&ci->m_lock);
812970

971+
fp->f_state = FP_NEW;
813972
__open_id(&work->sess->file_table, fp, OPEN_ID_TYPE_VOLATILE_ID);
814973
if (!has_file_id(fp->volatile_id)) {
815974
fp->conn = NULL;
@@ -849,6 +1008,8 @@ int ksmbd_init_file_cache(void)
8491008
if (!filp_cache)
8501009
goto out;
8511010

1011+
init_waitqueue_head(&dh_wq);
1012+
8521013
return 0;
8531014

8541015
out:

0 commit comments

Comments
 (0)