Skip to content

Commit 4770353

Browse files
committed
Merge tag '6.5-rc-smb3-client-fixes-part2' of git://git.samba.org/sfrench/cifs-2.6
Pull more smb client updates from Steve French: - fix potential use after free in unmount - minor cleanup - add worker to cleanup stale directory leases * tag '6.5-rc-smb3-client-fixes-part2' of git://git.samba.org/sfrench/cifs-2.6: cifs: Add a laundromat thread for cached directories smb: client: remove redundant pointer 'server' cifs: fix session state transition to avoid use-after-free issue
2 parents cff0687 + d14de80 commit 4770353

File tree

4 files changed

+72
-5
lines changed

4 files changed

+72
-5
lines changed

fs/smb/client/cached_dir.c

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,53 @@ static void free_cached_dir(struct cached_fid *cfid)
568568
kfree(cfid);
569569
}
570570

571+
static int
572+
cifs_cfids_laundromat_thread(void *p)
573+
{
574+
struct cached_fids *cfids = p;
575+
struct cached_fid *cfid, *q;
576+
struct list_head entry;
577+
578+
while (!kthread_should_stop()) {
579+
ssleep(1);
580+
INIT_LIST_HEAD(&entry);
581+
if (kthread_should_stop())
582+
return 0;
583+
spin_lock(&cfids->cfid_list_lock);
584+
list_for_each_entry_safe(cfid, q, &cfids->entries, entry) {
585+
if (time_after(jiffies, cfid->time + HZ * 30)) {
586+
list_del(&cfid->entry);
587+
list_add(&cfid->entry, &entry);
588+
cfids->num_entries--;
589+
}
590+
}
591+
spin_unlock(&cfids->cfid_list_lock);
592+
593+
list_for_each_entry_safe(cfid, q, &entry, entry) {
594+
cfid->on_list = false;
595+
list_del(&cfid->entry);
596+
/*
597+
* Cancel, and wait for the work to finish in
598+
* case we are racing with it.
599+
*/
600+
cancel_work_sync(&cfid->lease_break);
601+
if (cfid->has_lease) {
602+
/*
603+
* We lease has not yet been cancelled from
604+
* the server so we need to drop the reference.
605+
*/
606+
spin_lock(&cfids->cfid_list_lock);
607+
cfid->has_lease = false;
608+
spin_unlock(&cfids->cfid_list_lock);
609+
kref_put(&cfid->refcount, smb2_close_cached_fid);
610+
}
611+
}
612+
}
613+
614+
return 0;
615+
}
616+
617+
571618
struct cached_fids *init_cached_dirs(void)
572619
{
573620
struct cached_fids *cfids;
@@ -577,6 +624,20 @@ struct cached_fids *init_cached_dirs(void)
577624
return NULL;
578625
spin_lock_init(&cfids->cfid_list_lock);
579626
INIT_LIST_HEAD(&cfids->entries);
627+
628+
/*
629+
* since we're in a cifs function already, we know that
630+
* this will succeed. No need for try_module_get().
631+
*/
632+
__module_get(THIS_MODULE);
633+
cfids->laundromat = kthread_run(cifs_cfids_laundromat_thread,
634+
cfids, "cifsd-cfid-laundromat");
635+
if (IS_ERR(cfids->laundromat)) {
636+
cifs_dbg(VFS, "Failed to start cfids laundromat thread.\n");
637+
kfree(cfids);
638+
module_put(THIS_MODULE);
639+
return NULL;
640+
}
580641
return cfids;
581642
}
582643

@@ -589,6 +650,12 @@ void free_cached_dirs(struct cached_fids *cfids)
589650
struct cached_fid *cfid, *q;
590651
LIST_HEAD(entry);
591652

653+
if (cfids->laundromat) {
654+
kthread_stop(cfids->laundromat);
655+
cfids->laundromat = NULL;
656+
module_put(THIS_MODULE);
657+
}
658+
592659
spin_lock(&cfids->cfid_list_lock);
593660
list_for_each_entry_safe(cfid, q, &cfids->entries, entry) {
594661
cfid->on_list = false;

fs/smb/client/cached_dir.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ struct cached_fids {
5757
spinlock_t cfid_list_lock;
5858
int num_entries;
5959
struct list_head entries;
60+
struct task_struct *laundromat;
6061
};
6162

6263
extern struct cached_fids *init_cached_dirs(void);

fs/smb/client/connect.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1967,15 +1967,16 @@ void __cifs_put_smb_ses(struct cifs_ses *ses)
19671967
spin_unlock(&cifs_tcp_ses_lock);
19681968
return;
19691969
}
1970+
spin_lock(&ses->ses_lock);
1971+
if (ses->ses_status == SES_GOOD)
1972+
ses->ses_status = SES_EXITING;
1973+
spin_unlock(&ses->ses_lock);
19701974
spin_unlock(&cifs_tcp_ses_lock);
19711975

19721976
/* ses_count can never go negative */
19731977
WARN_ON(ses->ses_count < 0);
19741978

19751979
spin_lock(&ses->ses_lock);
1976-
if (ses->ses_status == SES_GOOD)
1977-
ses->ses_status = SES_EXITING;
1978-
19791980
if (ses->ses_status == SES_EXITING && server->ops->logoff) {
19801981
spin_unlock(&ses->ses_lock);
19811982
cifs_free_ipc(ses);

fs/smb/client/dfs.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,6 @@ static int __dfs_mount_share(struct cifs_mount_ctx *mnt_ctx)
143143
struct smb3_fs_context *ctx = mnt_ctx->fs_ctx;
144144
char *ref_path = NULL, *full_path = NULL;
145145
struct dfs_cache_tgt_iterator *tit;
146-
struct TCP_Server_Info *server;
147146
struct cifs_tcon *tcon;
148147
char *origin_fullpath = NULL;
149148
char sep = CIFS_DIR_SEP(cifs_sb);
@@ -214,7 +213,6 @@ static int __dfs_mount_share(struct cifs_mount_ctx *mnt_ctx)
214213
} while (rc == -EREMOTE);
215214

216215
if (!rc) {
217-
server = mnt_ctx->server;
218216
tcon = mnt_ctx->tcon;
219217

220218
spin_lock(&tcon->tc_lock);

0 commit comments

Comments
 (0)