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

+72 -5
+67
fs/smb/client/cached_dir.c
··· 568 568 kfree(cfid); 569 569 } 570 570 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 + 571 618 struct cached_fids *init_cached_dirs(void) 572 619 { 573 620 struct cached_fids *cfids; ··· 624 577 return NULL; 625 578 spin_lock_init(&cfids->cfid_list_lock); 626 579 INIT_LIST_HEAD(&cfids->entries); 580 + 581 + /* 582 + * since we're in a cifs function already, we know that 583 + * this will succeed. No need for try_module_get(). 584 + */ 585 + __module_get(THIS_MODULE); 586 + cfids->laundromat = kthread_run(cifs_cfids_laundromat_thread, 587 + cfids, "cifsd-cfid-laundromat"); 588 + if (IS_ERR(cfids->laundromat)) { 589 + cifs_dbg(VFS, "Failed to start cfids laundromat thread.\n"); 590 + kfree(cfids); 591 + module_put(THIS_MODULE); 592 + return NULL; 593 + } 627 594 return cfids; 628 595 } 629 596 ··· 649 588 { 650 589 struct cached_fid *cfid, *q; 651 590 LIST_HEAD(entry); 591 + 592 + if (cfids->laundromat) { 593 + kthread_stop(cfids->laundromat); 594 + cfids->laundromat = NULL; 595 + module_put(THIS_MODULE); 596 + } 652 597 653 598 spin_lock(&cfids->cfid_list_lock); 654 599 list_for_each_entry_safe(cfid, q, &cfids->entries, entry) {
+1
fs/smb/client/cached_dir.h
··· 57 57 spinlock_t cfid_list_lock; 58 58 int num_entries; 59 59 struct list_head entries; 60 + struct task_struct *laundromat; 60 61 }; 61 62 62 63 extern struct cached_fids *init_cached_dirs(void);
+4 -3
fs/smb/client/connect.c
··· 1967 1967 spin_unlock(&cifs_tcp_ses_lock); 1968 1968 return; 1969 1969 } 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); 1970 1974 spin_unlock(&cifs_tcp_ses_lock); 1971 1975 1972 1976 /* ses_count can never go negative */ 1973 1977 WARN_ON(ses->ses_count < 0); 1974 1978 1975 1979 spin_lock(&ses->ses_lock); 1976 - if (ses->ses_status == SES_GOOD) 1977 - ses->ses_status = SES_EXITING; 1978 - 1979 1980 if (ses->ses_status == SES_EXITING && server->ops->logoff) { 1980 1981 spin_unlock(&ses->ses_lock); 1981 1982 cifs_free_ipc(ses);
-2
fs/smb/client/dfs.c
··· 143 143 struct smb3_fs_context *ctx = mnt_ctx->fs_ctx; 144 144 char *ref_path = NULL, *full_path = NULL; 145 145 struct dfs_cache_tgt_iterator *tit; 146 - struct TCP_Server_Info *server; 147 146 struct cifs_tcon *tcon; 148 147 char *origin_fullpath = NULL; 149 148 char sep = CIFS_DIR_SEP(cifs_sb); ··· 213 214 } while (rc == -EREMOTE); 214 215 215 216 if (!rc) { 216 - server = mnt_ctx->server; 217 217 tcon = mnt_ctx->tcon; 218 218 219 219 spin_lock(&tcon->tc_lock);