Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag '6.9-rc2-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6

Pull smb client fixes from Steve French:

- fix to retry close to avoid potential handle leaks when server
returns EBUSY

- DFS fixes including a fix for potential use after free

- fscache fix

- minor strncpy cleanup

- reconnect race fix

- deal with various possible UAF race conditions tearing sessions down

* tag '6.9-rc2-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6:
smb: client: fix potential UAF in cifs_signal_cifsd_for_reconnect()
smb: client: fix potential UAF in smb2_is_network_name_deleted()
smb: client: fix potential UAF in is_valid_oplock_break()
smb: client: fix potential UAF in smb2_is_valid_oplock_break()
smb: client: fix potential UAF in smb2_is_valid_lease_break()
smb: client: fix potential UAF in cifs_stats_proc_show()
smb: client: fix potential UAF in cifs_stats_proc_write()
smb: client: fix potential UAF in cifs_dump_full_key()
smb: client: fix potential UAF in cifs_debug_files_proc_show()
smb3: retrying on failed server close
smb: client: serialise cifs_construct_tcon() with cifs_mount_mutex
smb: client: handle DFS tcons in cifs_construct_tcon()
smb: client: refresh referral without acquiring refpath_lock
smb: client: guarantee refcounted children from parent session
cifs: Fix caching to try to do open O_WRONLY as rdwr on server
smb: client: fix UAF in smb2_reconnect_server()
smb: client: replace deprecated strncpy with strscpy

+371 -180
+4 -2
fs/smb/client/cached_dir.c
··· 417 417 { 418 418 struct cached_fid *cfid = container_of(ref, struct cached_fid, 419 419 refcount); 420 + int rc; 420 421 421 422 spin_lock(&cfid->cfids->cfid_list_lock); 422 423 if (cfid->on_list) { ··· 431 430 cfid->dentry = NULL; 432 431 433 432 if (cfid->is_open) { 434 - SMB2_close(0, cfid->tcon, cfid->fid.persistent_fid, 433 + rc = SMB2_close(0, cfid->tcon, cfid->fid.persistent_fid, 435 434 cfid->fid.volatile_fid); 436 - atomic_dec(&cfid->tcon->num_remote_opens); 435 + if (rc != -EBUSY && rc != -EAGAIN) 436 + atomic_dec(&cfid->tcon->num_remote_opens); 437 437 } 438 438 439 439 free_cached_dir(cfid);
+6
fs/smb/client/cifs_debug.c
··· 250 250 spin_lock(&cifs_tcp_ses_lock); 251 251 list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) { 252 252 list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { 253 + if (cifs_ses_exiting(ses)) 254 + continue; 253 255 list_for_each_entry(tcon, &ses->tcon_list, tcon_list) { 254 256 spin_lock(&tcon->open_file_lock); 255 257 list_for_each_entry(cfile, &tcon->openFileList, tlist) { ··· 678 676 } 679 677 #endif /* CONFIG_CIFS_STATS2 */ 680 678 list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { 679 + if (cifs_ses_exiting(ses)) 680 + continue; 681 681 list_for_each_entry(tcon, &ses->tcon_list, tcon_list) { 682 682 atomic_set(&tcon->num_smbs_sent, 0); 683 683 spin_lock(&tcon->stat_lock); ··· 759 755 } 760 756 #endif /* STATS2 */ 761 757 list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { 758 + if (cifs_ses_exiting(ses)) 759 + continue; 762 760 list_for_each_entry(tcon, &ses->tcon_list, tcon_list) { 763 761 i++; 764 762 seq_printf(m, "\n%d) %s", i, tcon->tree_name);
+11
fs/smb/client/cifsfs.c
··· 156 156 struct workqueue_struct *fileinfo_put_wq; 157 157 struct workqueue_struct *cifsoplockd_wq; 158 158 struct workqueue_struct *deferredclose_wq; 159 + struct workqueue_struct *serverclose_wq; 159 160 __u32 cifs_lock_secret; 160 161 161 162 /* ··· 1889 1888 goto out_destroy_cifsoplockd_wq; 1890 1889 } 1891 1890 1891 + serverclose_wq = alloc_workqueue("serverclose", 1892 + WQ_FREEZABLE|WQ_MEM_RECLAIM, 0); 1893 + if (!serverclose_wq) { 1894 + rc = -ENOMEM; 1895 + goto out_destroy_serverclose_wq; 1896 + } 1897 + 1892 1898 rc = cifs_init_inodecache(); 1893 1899 if (rc) 1894 1900 goto out_destroy_deferredclose_wq; ··· 1970 1962 destroy_workqueue(decrypt_wq); 1971 1963 out_destroy_cifsiod_wq: 1972 1964 destroy_workqueue(cifsiod_wq); 1965 + out_destroy_serverclose_wq: 1966 + destroy_workqueue(serverclose_wq); 1973 1967 out_clean_proc: 1974 1968 cifs_proc_clean(); 1975 1969 return rc; ··· 2001 1991 destroy_workqueue(cifsoplockd_wq); 2002 1992 destroy_workqueue(decrypt_wq); 2003 1993 destroy_workqueue(fileinfo_put_wq); 1994 + destroy_workqueue(serverclose_wq); 2004 1995 destroy_workqueue(cifsiod_wq); 2005 1996 cifs_proc_clean(); 2006 1997 }
+15 -4
fs/smb/client/cifsglob.h
··· 442 442 /* set fid protocol-specific info */ 443 443 void (*set_fid)(struct cifsFileInfo *, struct cifs_fid *, __u32); 444 444 /* close a file */ 445 - void (*close)(const unsigned int, struct cifs_tcon *, 445 + int (*close)(const unsigned int, struct cifs_tcon *, 446 446 struct cifs_fid *); 447 447 /* close a file, returning file attributes and timestamps */ 448 - void (*close_getattr)(const unsigned int xid, struct cifs_tcon *tcon, 448 + int (*close_getattr)(const unsigned int xid, struct cifs_tcon *tcon, 449 449 struct cifsFileInfo *pfile_info); 450 450 /* send a flush request to the server */ 451 451 int (*flush)(const unsigned int, struct cifs_tcon *, struct cifs_fid *); ··· 1281 1281 struct cached_fids *cfids; 1282 1282 /* BB add field for back pointer to sb struct(s)? */ 1283 1283 #ifdef CONFIG_CIFS_DFS_UPCALL 1284 - struct list_head dfs_ses_list; 1285 1284 struct delayed_work dfs_cache_work; 1286 1285 #endif 1287 1286 struct delayed_work query_interfaces; /* query interfaces workqueue job */ ··· 1439 1440 bool swapfile:1; 1440 1441 bool oplock_break_cancelled:1; 1441 1442 bool status_file_deleted:1; /* file has been deleted */ 1443 + bool offload:1; /* offload final part of _put to a wq */ 1442 1444 unsigned int oplock_epoch; /* epoch from the lease break */ 1443 1445 __u32 oplock_level; /* oplock/lease level from the lease break */ 1444 1446 int count; ··· 1448 1448 struct cifs_search_info srch_inf; 1449 1449 struct work_struct oplock_break; /* work for oplock breaks */ 1450 1450 struct work_struct put; /* work for the final part of _put */ 1451 + struct work_struct serverclose; /* work for serverclose */ 1451 1452 struct delayed_work deferred; 1452 1453 bool deferred_close_scheduled; /* Flag to indicate close is scheduled */ 1453 1454 char *symlink_target; ··· 1805 1804 struct TCP_Server_Info *server; 1806 1805 struct cifs_ses *ses; 1807 1806 struct cifs_tcon *tcon; 1808 - struct list_head dfs_ses_list; 1809 1807 }; 1810 1808 1811 1809 static inline void __free_dfs_info_param(struct dfs_info3_param *param) ··· 2105 2105 extern struct workqueue_struct *fileinfo_put_wq; 2106 2106 extern struct workqueue_struct *cifsoplockd_wq; 2107 2107 extern struct workqueue_struct *deferredclose_wq; 2108 + extern struct workqueue_struct *serverclose_wq; 2108 2109 extern __u32 cifs_lock_secret; 2109 2110 2110 2111 extern mempool_t *cifs_sm_req_poolp; ··· 2324 2323 struct smb2_file_link_info link_info; 2325 2324 struct kvec ea_iov; 2326 2325 }; 2326 + 2327 + static inline bool cifs_ses_exiting(struct cifs_ses *ses) 2328 + { 2329 + bool ret; 2330 + 2331 + spin_lock(&ses->ses_lock); 2332 + ret = ses->ses_status == SES_EXITING; 2333 + spin_unlock(&ses->ses_lock); 2334 + return ret; 2335 + } 2327 2336 2328 2337 #endif /* _CIFS_GLOB_H */
+10 -10
fs/smb/client/cifsproto.h
··· 725 725 void cifs_put_tcon_super(struct super_block *sb); 726 726 int cifs_wait_for_server_reconnect(struct TCP_Server_Info *server, bool retry); 727 727 728 - /* Put references of @ses and @ses->dfs_root_ses */ 728 + /* Put references of @ses and its children */ 729 729 static inline void cifs_put_smb_ses(struct cifs_ses *ses) 730 730 { 731 - struct cifs_ses *rses = ses->dfs_root_ses; 731 + struct cifs_ses *next; 732 732 733 - __cifs_put_smb_ses(ses); 734 - if (rses) 735 - __cifs_put_smb_ses(rses); 733 + do { 734 + next = ses->dfs_root_ses; 735 + __cifs_put_smb_ses(ses); 736 + } while ((ses = next)); 736 737 } 737 738 738 - /* Get an active reference of @ses and @ses->dfs_root_ses. 739 + /* Get an active reference of @ses and its children. 739 740 * 740 741 * NOTE: make sure to call this function when incrementing reference count of 741 742 * @ses to ensure that any DFS root session attached to it (@ses->dfs_root_ses) 742 743 * will also get its reference count incremented. 743 744 * 744 - * cifs_put_smb_ses() will put both references, so call it when you're done. 745 + * cifs_put_smb_ses() will put all references, so call it when you're done. 745 746 */ 746 747 static inline void cifs_smb_ses_inc_refcount(struct cifs_ses *ses) 747 748 { 748 749 lockdep_assert_held(&cifs_tcp_ses_lock); 749 750 750 - ses->ses_count++; 751 - if (ses->dfs_root_ses) 752 - ses->dfs_root_ses->ses_count++; 751 + for (; ses; ses = ses->dfs_root_ses) 752 + ses->ses_count++; 753 753 } 754 754 755 755 static inline bool dfs_src_pathname_equal(const char *s1, const char *s2)
+2 -4
fs/smb/client/cifssmb.c
··· 5854 5854 parm_data->list.EA_flags = 0; 5855 5855 /* we checked above that name len is less than 255 */ 5856 5856 parm_data->list.name_len = (__u8)name_len; 5857 - /* EA names are always ASCII */ 5858 - if (ea_name) 5859 - strncpy(parm_data->list.name, ea_name, name_len); 5860 - parm_data->list.name[name_len] = '\0'; 5857 + /* EA names are always ASCII and NUL-terminated */ 5858 + strscpy(parm_data->list.name, ea_name ?: "", name_len + 1); 5861 5859 parm_data->list.value_len = cpu_to_le16(ea_value_len); 5862 5860 /* caller ensures that ea_value_len is less than 64K but 5863 5861 we need to ensure that it fits within the smb */
+100 -57
fs/smb/client/connect.c
··· 175 175 176 176 spin_lock(&cifs_tcp_ses_lock); 177 177 list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) { 178 + if (cifs_ses_exiting(ses)) 179 + continue; 178 180 spin_lock(&ses->chan_lock); 179 181 for (i = 0; i < ses->chan_count; i++) { 180 182 if (!ses->chans[i].server) ··· 234 232 235 233 spin_lock(&cifs_tcp_ses_lock); 236 234 list_for_each_entry_safe(ses, nses, &pserver->smb_ses_list, smb_ses_list) { 237 - /* check if iface is still active */ 235 + spin_lock(&ses->ses_lock); 236 + if (ses->ses_status == SES_EXITING) { 237 + spin_unlock(&ses->ses_lock); 238 + continue; 239 + } 240 + spin_unlock(&ses->ses_lock); 241 + 238 242 spin_lock(&ses->chan_lock); 239 243 if (cifs_ses_get_chan_index(ses, server) == 240 244 CIFS_INVAL_CHAN_INDEX) { ··· 1868 1860 ctx->sectype != ses->sectype) 1869 1861 return 0; 1870 1862 1863 + if (ctx->dfs_root_ses != ses->dfs_root_ses) 1864 + return 0; 1865 + 1871 1866 /* 1872 1867 * If an existing session is limited to less channels than 1873 1868 * requested, it should not be reused ··· 1974 1963 return rc; 1975 1964 } 1976 1965 1977 - /** 1978 - * cifs_free_ipc - helper to release the session IPC tcon 1979 - * @ses: smb session to unmount the IPC from 1980 - * 1981 - * Needs to be called everytime a session is destroyed. 1982 - * 1983 - * On session close, the IPC is closed and the server must release all tcons of the session. 1984 - * No need to send a tree disconnect here. 1985 - * 1986 - * Besides, it will make the server to not close durable and resilient files on session close, as 1987 - * specified in MS-SMB2 3.3.5.6 Receiving an SMB2 LOGOFF Request. 1988 - */ 1989 - static int 1990 - cifs_free_ipc(struct cifs_ses *ses) 1991 - { 1992 - struct cifs_tcon *tcon = ses->tcon_ipc; 1993 - 1994 - if (tcon == NULL) 1995 - return 0; 1996 - 1997 - tconInfoFree(tcon); 1998 - ses->tcon_ipc = NULL; 1999 - return 0; 2000 - } 2001 - 2002 1966 static struct cifs_ses * 2003 1967 cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx) 2004 1968 { ··· 2005 2019 void __cifs_put_smb_ses(struct cifs_ses *ses) 2006 2020 { 2007 2021 struct TCP_Server_Info *server = ses->server; 2022 + struct cifs_tcon *tcon; 2008 2023 unsigned int xid; 2009 2024 size_t i; 2025 + bool do_logoff; 2010 2026 int rc; 2011 2027 2012 - spin_lock(&ses->ses_lock); 2013 - if (ses->ses_status == SES_EXITING) { 2014 - spin_unlock(&ses->ses_lock); 2015 - return; 2016 - } 2017 - spin_unlock(&ses->ses_lock); 2018 - 2019 - cifs_dbg(FYI, "%s: ses_count=%d\n", __func__, ses->ses_count); 2020 - cifs_dbg(FYI, 2021 - "%s: ses ipc: %s\n", __func__, ses->tcon_ipc ? ses->tcon_ipc->tree_name : "NONE"); 2022 - 2023 2028 spin_lock(&cifs_tcp_ses_lock); 2024 - if (--ses->ses_count > 0) { 2029 + spin_lock(&ses->ses_lock); 2030 + cifs_dbg(FYI, "%s: id=0x%llx ses_count=%d ses_status=%u ipc=%s\n", 2031 + __func__, ses->Suid, ses->ses_count, ses->ses_status, 2032 + ses->tcon_ipc ? ses->tcon_ipc->tree_name : "none"); 2033 + if (ses->ses_status == SES_EXITING || --ses->ses_count > 0) { 2034 + spin_unlock(&ses->ses_lock); 2025 2035 spin_unlock(&cifs_tcp_ses_lock); 2026 2036 return; 2027 2037 } 2028 - spin_lock(&ses->ses_lock); 2029 - if (ses->ses_status == SES_GOOD) 2030 - ses->ses_status = SES_EXITING; 2031 - spin_unlock(&ses->ses_lock); 2032 - spin_unlock(&cifs_tcp_ses_lock); 2033 - 2034 2038 /* ses_count can never go negative */ 2035 2039 WARN_ON(ses->ses_count < 0); 2036 2040 2037 - spin_lock(&ses->ses_lock); 2038 - if (ses->ses_status == SES_EXITING && server->ops->logoff) { 2039 - spin_unlock(&ses->ses_lock); 2040 - cifs_free_ipc(ses); 2041 + spin_lock(&ses->chan_lock); 2042 + cifs_chan_clear_need_reconnect(ses, server); 2043 + spin_unlock(&ses->chan_lock); 2044 + 2045 + do_logoff = ses->ses_status == SES_GOOD && server->ops->logoff; 2046 + ses->ses_status = SES_EXITING; 2047 + tcon = ses->tcon_ipc; 2048 + ses->tcon_ipc = NULL; 2049 + spin_unlock(&ses->ses_lock); 2050 + spin_unlock(&cifs_tcp_ses_lock); 2051 + 2052 + /* 2053 + * On session close, the IPC is closed and the server must release all 2054 + * tcons of the session. No need to send a tree disconnect here. 2055 + * 2056 + * Besides, it will make the server to not close durable and resilient 2057 + * files on session close, as specified in MS-SMB2 3.3.5.6 Receiving an 2058 + * SMB2 LOGOFF Request. 2059 + */ 2060 + tconInfoFree(tcon); 2061 + if (do_logoff) { 2041 2062 xid = get_xid(); 2042 2063 rc = server->ops->logoff(xid, ses); 2043 2064 if (rc) 2044 2065 cifs_server_dbg(VFS, "%s: Session Logoff failure rc=%d\n", 2045 2066 __func__, rc); 2046 2067 _free_xid(xid); 2047 - } else { 2048 - spin_unlock(&ses->ses_lock); 2049 - cifs_free_ipc(ses); 2050 2068 } 2051 2069 2052 2070 spin_lock(&cifs_tcp_ses_lock); ··· 2363 2373 * need to lock before changing something in the session. 2364 2374 */ 2365 2375 spin_lock(&cifs_tcp_ses_lock); 2376 + if (ctx->dfs_root_ses) 2377 + cifs_smb_ses_inc_refcount(ctx->dfs_root_ses); 2366 2378 ses->dfs_root_ses = ctx->dfs_root_ses; 2367 - if (ses->dfs_root_ses) 2368 - ses->dfs_root_ses->ses_count++; 2369 2379 list_add(&ses->smb_ses_list, &server->smb_ses_list); 2370 2380 spin_unlock(&cifs_tcp_ses_lock); 2371 2381 ··· 3316 3326 cifs_put_smb_ses(mnt_ctx->ses); 3317 3327 else if (mnt_ctx->server) 3318 3328 cifs_put_tcp_session(mnt_ctx->server, 0); 3329 + mnt_ctx->ses = NULL; 3330 + mnt_ctx->tcon = NULL; 3331 + mnt_ctx->server = NULL; 3319 3332 mnt_ctx->cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_POSIX_PATHS; 3320 3333 free_xid(mnt_ctx->xid); 3321 3334 } ··· 3597 3604 bool isdfs; 3598 3605 int rc; 3599 3606 3600 - INIT_LIST_HEAD(&mnt_ctx.dfs_ses_list); 3601 - 3602 3607 rc = dfs_mount_share(&mnt_ctx, &isdfs); 3603 3608 if (rc) 3604 3609 goto error; ··· 3627 3636 return rc; 3628 3637 3629 3638 error: 3630 - dfs_put_root_smb_sessions(&mnt_ctx.dfs_ses_list); 3631 3639 cifs_mount_put_conns(&mnt_ctx); 3632 3640 return rc; 3633 3641 } ··· 3641 3651 goto error; 3642 3652 3643 3653 rc = cifs_mount_get_tcon(&mnt_ctx); 3654 + if (!rc) { 3655 + /* 3656 + * Prevent superblock from being created with any missing 3657 + * connections. 3658 + */ 3659 + if (WARN_ON(!mnt_ctx.server)) 3660 + rc = -EHOSTDOWN; 3661 + else if (WARN_ON(!mnt_ctx.ses)) 3662 + rc = -EACCES; 3663 + else if (WARN_ON(!mnt_ctx.tcon)) 3664 + rc = -ENOENT; 3665 + } 3644 3666 if (rc) 3645 3667 goto error; 3646 3668 ··· 3990 3988 } 3991 3989 3992 3990 static struct cifs_tcon * 3993 - cifs_construct_tcon(struct cifs_sb_info *cifs_sb, kuid_t fsuid) 3991 + __cifs_construct_tcon(struct cifs_sb_info *cifs_sb, kuid_t fsuid) 3994 3992 { 3995 3993 int rc; 3996 3994 struct cifs_tcon *master_tcon = cifs_sb_master_tcon(cifs_sb); 3997 3995 struct cifs_ses *ses; 3998 3996 struct cifs_tcon *tcon = NULL; 3999 3997 struct smb3_fs_context *ctx; 3998 + char *origin_fullpath = NULL; 4000 3999 4001 4000 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 4002 4001 if (ctx == NULL) ··· 4021 4018 ctx->sign = master_tcon->ses->sign; 4022 4019 ctx->seal = master_tcon->seal; 4023 4020 ctx->witness = master_tcon->use_witness; 4021 + ctx->dfs_root_ses = master_tcon->ses->dfs_root_ses; 4024 4022 4025 4023 rc = cifs_set_vol_auth(ctx, master_tcon->ses); 4026 4024 if (rc) { ··· 4041 4037 goto out; 4042 4038 } 4043 4039 4040 + #ifdef CONFIG_CIFS_DFS_UPCALL 4041 + spin_lock(&master_tcon->tc_lock); 4042 + if (master_tcon->origin_fullpath) { 4043 + spin_unlock(&master_tcon->tc_lock); 4044 + origin_fullpath = dfs_get_path(cifs_sb, cifs_sb->ctx->source); 4045 + if (IS_ERR(origin_fullpath)) { 4046 + tcon = ERR_CAST(origin_fullpath); 4047 + origin_fullpath = NULL; 4048 + cifs_put_smb_ses(ses); 4049 + goto out; 4050 + } 4051 + } else { 4052 + spin_unlock(&master_tcon->tc_lock); 4053 + } 4054 + #endif 4055 + 4044 4056 tcon = cifs_get_tcon(ses, ctx); 4045 4057 if (IS_ERR(tcon)) { 4046 4058 cifs_put_smb_ses(ses); 4047 4059 goto out; 4048 4060 } 4061 + 4062 + #ifdef CONFIG_CIFS_DFS_UPCALL 4063 + if (origin_fullpath) { 4064 + spin_lock(&tcon->tc_lock); 4065 + tcon->origin_fullpath = origin_fullpath; 4066 + spin_unlock(&tcon->tc_lock); 4067 + origin_fullpath = NULL; 4068 + queue_delayed_work(dfscache_wq, &tcon->dfs_cache_work, 4069 + dfs_cache_get_ttl() * HZ); 4070 + } 4071 + #endif 4049 4072 4050 4073 #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 4051 4074 if (cap_unix(ses)) ··· 4082 4051 out: 4083 4052 kfree(ctx->username); 4084 4053 kfree_sensitive(ctx->password); 4054 + kfree(origin_fullpath); 4085 4055 kfree(ctx); 4086 4056 4087 4057 return tcon; 4058 + } 4059 + 4060 + static struct cifs_tcon * 4061 + cifs_construct_tcon(struct cifs_sb_info *cifs_sb, kuid_t fsuid) 4062 + { 4063 + struct cifs_tcon *ret; 4064 + 4065 + cifs_mount_lock(); 4066 + ret = __cifs_construct_tcon(cifs_sb, fsuid); 4067 + cifs_mount_unlock(); 4068 + return ret; 4088 4069 } 4089 4070 4090 4071 struct cifs_tcon *
+24 -27
fs/smb/client/dfs.c
··· 66 66 } 67 67 68 68 /* 69 - * Track individual DFS referral servers used by new DFS mount. 70 - * 71 - * On success, their lifetime will be shared by final tcon (dfs_ses_list). 72 - * Otherwise, they will be put by dfs_put_root_smb_sessions() in cifs_mount(). 69 + * Get an active reference of @ses so that next call to cifs_put_tcon() won't 70 + * release it as any new DFS referrals must go through its IPC tcon. 73 71 */ 74 - static int add_root_smb_session(struct cifs_mount_ctx *mnt_ctx) 72 + static void add_root_smb_session(struct cifs_mount_ctx *mnt_ctx) 75 73 { 76 74 struct smb3_fs_context *ctx = mnt_ctx->fs_ctx; 77 - struct dfs_root_ses *root_ses; 78 75 struct cifs_ses *ses = mnt_ctx->ses; 79 76 80 77 if (ses) { 81 - root_ses = kmalloc(sizeof(*root_ses), GFP_KERNEL); 82 - if (!root_ses) 83 - return -ENOMEM; 84 - 85 - INIT_LIST_HEAD(&root_ses->list); 86 - 87 78 spin_lock(&cifs_tcp_ses_lock); 88 79 cifs_smb_ses_inc_refcount(ses); 89 80 spin_unlock(&cifs_tcp_ses_lock); 90 - root_ses->ses = ses; 91 - list_add_tail(&root_ses->list, &mnt_ctx->dfs_ses_list); 92 81 } 93 - /* Select new DFS referral server so that new referrals go through it */ 94 82 ctx->dfs_root_ses = ses; 95 - return 0; 96 83 } 97 84 98 85 static inline int parse_dfs_target(struct smb3_fs_context *ctx, ··· 172 185 continue; 173 186 } 174 187 175 - if (is_refsrv) { 176 - rc = add_root_smb_session(mnt_ctx); 177 - if (rc) 178 - goto out; 179 - } 188 + if (is_refsrv) 189 + add_root_smb_session(mnt_ctx); 180 190 181 191 rc = ref_walk_advance(rw); 182 192 if (!rc) { ··· 216 232 struct smb3_fs_context *ctx = mnt_ctx->fs_ctx; 217 233 struct cifs_tcon *tcon; 218 234 char *origin_fullpath; 235 + bool new_tcon = true; 219 236 int rc; 220 237 221 238 origin_fullpath = dfs_get_path(cifs_sb, ctx->source); ··· 224 239 return PTR_ERR(origin_fullpath); 225 240 226 241 rc = dfs_referral_walk(mnt_ctx); 242 + if (!rc) { 243 + /* 244 + * Prevent superblock from being created with any missing 245 + * connections. 246 + */ 247 + if (WARN_ON(!mnt_ctx->server)) 248 + rc = -EHOSTDOWN; 249 + else if (WARN_ON(!mnt_ctx->ses)) 250 + rc = -EACCES; 251 + else if (WARN_ON(!mnt_ctx->tcon)) 252 + rc = -ENOENT; 253 + } 227 254 if (rc) 228 255 goto out; 229 256 ··· 244 247 if (!tcon->origin_fullpath) { 245 248 tcon->origin_fullpath = origin_fullpath; 246 249 origin_fullpath = NULL; 250 + } else { 251 + new_tcon = false; 247 252 } 248 253 spin_unlock(&tcon->tc_lock); 249 254 250 - if (list_empty(&tcon->dfs_ses_list)) { 251 - list_replace_init(&mnt_ctx->dfs_ses_list, &tcon->dfs_ses_list); 255 + if (new_tcon) { 252 256 queue_delayed_work(dfscache_wq, &tcon->dfs_cache_work, 253 257 dfs_cache_get_ttl() * HZ); 254 - } else { 255 - dfs_put_root_smb_sessions(&mnt_ctx->dfs_ses_list); 256 258 } 257 259 258 260 out: ··· 294 298 if (rc) 295 299 return rc; 296 300 297 - ctx->dfs_root_ses = mnt_ctx->ses; 298 301 /* 299 302 * If called with 'nodfs' mount option, then skip DFS resolving. Otherwise unconditionally 300 303 * try to get an DFS referral (even cached) to determine whether it is an DFS mount. ··· 319 324 320 325 *isdfs = true; 321 326 add_root_smb_session(mnt_ctx); 322 - return __dfs_mount_share(mnt_ctx); 327 + rc = __dfs_mount_share(mnt_ctx); 328 + dfs_put_root_smb_sessions(mnt_ctx); 329 + return rc; 323 330 } 324 331 325 332 /* Update dfs referral path of superblock */
+21 -12
fs/smb/client/dfs.h
··· 7 7 #define _CIFS_DFS_H 8 8 9 9 #include "cifsglob.h" 10 + #include "cifsproto.h" 10 11 #include "fs_context.h" 12 + #include "dfs_cache.h" 11 13 #include "cifs_unicode.h" 12 14 #include <linux/namei.h> 13 15 ··· 116 114 ref_walk_tit(rw)); 117 115 } 118 116 119 - struct dfs_root_ses { 120 - struct list_head list; 121 - struct cifs_ses *ses; 122 - }; 123 - 124 117 int dfs_parse_target_referral(const char *full_path, const struct dfs_info3_param *ref, 125 118 struct smb3_fs_context *ctx); 126 119 int dfs_mount_share(struct cifs_mount_ctx *mnt_ctx, bool *isdfs); ··· 130 133 { 131 134 struct smb3_fs_context *ctx = mnt_ctx->fs_ctx; 132 135 struct cifs_sb_info *cifs_sb = mnt_ctx->cifs_sb; 136 + struct cifs_ses *rses = ctx->dfs_root_ses ?: mnt_ctx->ses; 133 137 134 - return dfs_cache_find(mnt_ctx->xid, ctx->dfs_root_ses, cifs_sb->local_nls, 138 + return dfs_cache_find(mnt_ctx->xid, rses, cifs_sb->local_nls, 135 139 cifs_remap(cifs_sb), path, ref, tl); 136 140 } 137 141 138 - static inline void dfs_put_root_smb_sessions(struct list_head *head) 142 + /* 143 + * cifs_get_smb_ses() already guarantees an active reference of 144 + * @ses->dfs_root_ses when a new session is created, so we need to put extra 145 + * references of all DFS root sessions that were used across the mount process 146 + * in dfs_mount_share(). 147 + */ 148 + static inline void dfs_put_root_smb_sessions(struct cifs_mount_ctx *mnt_ctx) 139 149 { 140 - struct dfs_root_ses *root, *tmp; 150 + const struct smb3_fs_context *ctx = mnt_ctx->fs_ctx; 151 + struct cifs_ses *ses = ctx->dfs_root_ses; 152 + struct cifs_ses *cur; 141 153 142 - list_for_each_entry_safe(root, tmp, head, list) { 143 - list_del_init(&root->list); 144 - cifs_put_smb_ses(root->ses); 145 - kfree(root); 154 + if (!ses) 155 + return; 156 + 157 + for (cur = ses; cur; cur = cur->dfs_root_ses) { 158 + if (cur->dfs_root_ses) 159 + cifs_put_smb_ses(cur->dfs_root_ses); 146 160 } 161 + cifs_put_smb_ses(ses); 147 162 } 148 163 149 164 #endif /* _CIFS_DFS_H */
+24 -29
fs/smb/client/dfs_cache.c
··· 1172 1172 return ret; 1173 1173 } 1174 1174 1175 - /* Refresh dfs referral of tcon and mark it for reconnect if needed */ 1176 - static int __refresh_tcon(const char *path, struct cifs_ses *ses, bool force_refresh) 1175 + /* Refresh dfs referral of @ses and mark it for reconnect if needed */ 1176 + static void __refresh_ses_referral(struct cifs_ses *ses, bool force_refresh) 1177 1177 { 1178 1178 struct TCP_Server_Info *server = ses->server; 1179 1179 DFS_CACHE_TGT_LIST(old_tl); ··· 1181 1181 bool needs_refresh = false; 1182 1182 struct cache_entry *ce; 1183 1183 unsigned int xid; 1184 + char *path = NULL; 1184 1185 int rc = 0; 1185 1186 1186 1187 xid = get_xid(); 1188 + 1189 + mutex_lock(&server->refpath_lock); 1190 + if (server->leaf_fullpath) { 1191 + path = kstrdup(server->leaf_fullpath + 1, GFP_ATOMIC); 1192 + if (!path) 1193 + rc = -ENOMEM; 1194 + } 1195 + mutex_unlock(&server->refpath_lock); 1196 + if (!path) 1197 + goto out; 1187 1198 1188 1199 down_read(&htable_rw_lock); 1189 1200 ce = lookup_cache_entry(path); ··· 1229 1218 free_xid(xid); 1230 1219 dfs_cache_free_tgts(&old_tl); 1231 1220 dfs_cache_free_tgts(&new_tl); 1232 - return rc; 1221 + kfree(path); 1233 1222 } 1234 1223 1235 - static int refresh_tcon(struct cifs_tcon *tcon, bool force_refresh) 1224 + static inline void refresh_ses_referral(struct cifs_ses *ses) 1236 1225 { 1237 - struct TCP_Server_Info *server = tcon->ses->server; 1238 - struct cifs_ses *ses = tcon->ses; 1226 + __refresh_ses_referral(ses, false); 1227 + } 1239 1228 1240 - mutex_lock(&server->refpath_lock); 1241 - if (server->leaf_fullpath) 1242 - __refresh_tcon(server->leaf_fullpath + 1, ses, force_refresh); 1243 - mutex_unlock(&server->refpath_lock); 1244 - return 0; 1229 + static inline void force_refresh_ses_referral(struct cifs_ses *ses) 1230 + { 1231 + __refresh_ses_referral(ses, true); 1245 1232 } 1246 1233 1247 1234 /** ··· 1280 1271 */ 1281 1272 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH; 1282 1273 1283 - return refresh_tcon(tcon, true); 1274 + force_refresh_ses_referral(tcon->ses); 1275 + return 0; 1284 1276 } 1285 1277 1286 1278 /* Refresh all DFS referrals related to DFS tcon */ 1287 1279 void dfs_cache_refresh(struct work_struct *work) 1288 1280 { 1289 - struct TCP_Server_Info *server; 1290 - struct dfs_root_ses *rses; 1291 1281 struct cifs_tcon *tcon; 1292 1282 struct cifs_ses *ses; 1293 1283 1294 1284 tcon = container_of(work, struct cifs_tcon, dfs_cache_work.work); 1295 - ses = tcon->ses; 1296 - server = ses->server; 1297 1285 1298 - mutex_lock(&server->refpath_lock); 1299 - if (server->leaf_fullpath) 1300 - __refresh_tcon(server->leaf_fullpath + 1, ses, false); 1301 - mutex_unlock(&server->refpath_lock); 1302 - 1303 - list_for_each_entry(rses, &tcon->dfs_ses_list, list) { 1304 - ses = rses->ses; 1305 - server = ses->server; 1306 - mutex_lock(&server->refpath_lock); 1307 - if (server->leaf_fullpath) 1308 - __refresh_tcon(server->leaf_fullpath + 1, ses, false); 1309 - mutex_unlock(&server->refpath_lock); 1310 - } 1286 + for (ses = tcon->ses; ses; ses = ses->dfs_root_ses) 1287 + refresh_ses_referral(ses); 1311 1288 1312 1289 queue_delayed_work(dfscache_wq, &tcon->dfs_cache_work, 1313 1290 atomic_read(&dfs_cache_ttl) * HZ);
+15
fs/smb/client/dir.c
··· 189 189 int disposition; 190 190 struct TCP_Server_Info *server = tcon->ses->server; 191 191 struct cifs_open_parms oparms; 192 + int rdwr_for_fscache = 0; 192 193 193 194 *oplock = 0; 194 195 if (tcon->ses->server->oplocks) ··· 200 199 free_dentry_path(page); 201 200 return PTR_ERR(full_path); 202 201 } 202 + 203 + /* If we're caching, we need to be able to fill in around partial writes. */ 204 + if (cifs_fscache_enabled(inode) && (oflags & O_ACCMODE) == O_WRONLY) 205 + rdwr_for_fscache = 1; 203 206 204 207 #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 205 208 if (tcon->unix_ext && cap_unix(tcon->ses) && !tcon->broken_posix_open && ··· 281 276 desired_access |= GENERIC_READ; /* is this too little? */ 282 277 if (OPEN_FMODE(oflags) & FMODE_WRITE) 283 278 desired_access |= GENERIC_WRITE; 279 + if (rdwr_for_fscache == 1) 280 + desired_access |= GENERIC_READ; 284 281 285 282 disposition = FILE_OVERWRITE_IF; 286 283 if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) ··· 311 304 if (!tcon->unix_ext && (mode & S_IWUGO) == 0) 312 305 create_options |= CREATE_OPTION_READONLY; 313 306 307 + retry_open: 314 308 oparms = (struct cifs_open_parms) { 315 309 .tcon = tcon, 316 310 .cifs_sb = cifs_sb, ··· 325 317 rc = server->ops->open(xid, &oparms, oplock, buf); 326 318 if (rc) { 327 319 cifs_dbg(FYI, "cifs_create returned 0x%x\n", rc); 320 + if (rc == -EACCES && rdwr_for_fscache == 1) { 321 + desired_access &= ~GENERIC_READ; 322 + rdwr_for_fscache = 2; 323 + goto retry_open; 324 + } 328 325 goto out; 329 326 } 327 + if (rdwr_for_fscache == 2) 328 + cifs_invalidate_cache(inode, FSCACHE_INVAL_DIO_WRITE); 330 329 331 330 #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 332 331 /*
+95 -16
fs/smb/client/file.c
··· 206 206 */ 207 207 } 208 208 209 - static inline int cifs_convert_flags(unsigned int flags) 209 + static inline int cifs_convert_flags(unsigned int flags, int rdwr_for_fscache) 210 210 { 211 211 if ((flags & O_ACCMODE) == O_RDONLY) 212 212 return GENERIC_READ; 213 213 else if ((flags & O_ACCMODE) == O_WRONLY) 214 - return GENERIC_WRITE; 214 + return rdwr_for_fscache == 1 ? (GENERIC_READ | GENERIC_WRITE) : GENERIC_WRITE; 215 215 else if ((flags & O_ACCMODE) == O_RDWR) { 216 216 /* GENERIC_ALL is too much permission to request 217 217 can cause unnecessary access denied on create */ ··· 348 348 int create_options = CREATE_NOT_DIR; 349 349 struct TCP_Server_Info *server = tcon->ses->server; 350 350 struct cifs_open_parms oparms; 351 + int rdwr_for_fscache = 0; 351 352 352 353 if (!server->ops->open) 353 354 return -ENOSYS; 354 355 355 - desired_access = cifs_convert_flags(f_flags); 356 + /* If we're caching, we need to be able to fill in around partial writes. */ 357 + if (cifs_fscache_enabled(inode) && (f_flags & O_ACCMODE) == O_WRONLY) 358 + rdwr_for_fscache = 1; 359 + 360 + desired_access = cifs_convert_flags(f_flags, rdwr_for_fscache); 356 361 357 362 /********************************************************************* 358 363 * open flag mapping table: ··· 394 389 if (f_flags & O_DIRECT) 395 390 create_options |= CREATE_NO_BUFFER; 396 391 392 + retry_open: 397 393 oparms = (struct cifs_open_parms) { 398 394 .tcon = tcon, 399 395 .cifs_sb = cifs_sb, ··· 406 400 }; 407 401 408 402 rc = server->ops->open(xid, &oparms, oplock, buf); 409 - if (rc) 403 + if (rc) { 404 + if (rc == -EACCES && rdwr_for_fscache == 1) { 405 + desired_access = cifs_convert_flags(f_flags, 0); 406 + rdwr_for_fscache = 2; 407 + goto retry_open; 408 + } 410 409 return rc; 410 + } 411 + if (rdwr_for_fscache == 2) 412 + cifs_invalidate_cache(inode, FSCACHE_INVAL_DIO_WRITE); 411 413 412 414 /* TODO: Add support for calling posix query info but with passing in fid */ 413 415 if (tcon->unix_ext) ··· 459 445 } 460 446 461 447 static void cifsFileInfo_put_work(struct work_struct *work); 448 + void serverclose_work(struct work_struct *work); 462 449 463 450 struct cifsFileInfo *cifs_new_fileinfo(struct cifs_fid *fid, struct file *file, 464 451 struct tcon_link *tlink, __u32 oplock, ··· 506 491 cfile->tlink = cifs_get_tlink(tlink); 507 492 INIT_WORK(&cfile->oplock_break, cifs_oplock_break); 508 493 INIT_WORK(&cfile->put, cifsFileInfo_put_work); 494 + INIT_WORK(&cfile->serverclose, serverclose_work); 509 495 INIT_DELAYED_WORK(&cfile->deferred, smb2_deferred_work_close); 510 496 mutex_init(&cfile->fh_mutex); 511 497 spin_lock_init(&cfile->file_info_lock); ··· 598 582 cifsFileInfo_put_final(cifs_file); 599 583 } 600 584 585 + void serverclose_work(struct work_struct *work) 586 + { 587 + struct cifsFileInfo *cifs_file = container_of(work, 588 + struct cifsFileInfo, serverclose); 589 + 590 + struct cifs_tcon *tcon = tlink_tcon(cifs_file->tlink); 591 + 592 + struct TCP_Server_Info *server = tcon->ses->server; 593 + int rc = 0; 594 + int retries = 0; 595 + int MAX_RETRIES = 4; 596 + 597 + do { 598 + if (server->ops->close_getattr) 599 + rc = server->ops->close_getattr(0, tcon, cifs_file); 600 + else if (server->ops->close) 601 + rc = server->ops->close(0, tcon, &cifs_file->fid); 602 + 603 + if (rc == -EBUSY || rc == -EAGAIN) { 604 + retries++; 605 + msleep(250); 606 + } 607 + } while ((rc == -EBUSY || rc == -EAGAIN) && (retries < MAX_RETRIES) 608 + ); 609 + 610 + if (retries == MAX_RETRIES) 611 + pr_warn("Serverclose failed %d times, giving up\n", MAX_RETRIES); 612 + 613 + if (cifs_file->offload) 614 + queue_work(fileinfo_put_wq, &cifs_file->put); 615 + else 616 + cifsFileInfo_put_final(cifs_file); 617 + } 618 + 601 619 /** 602 620 * cifsFileInfo_put - release a reference of file priv data 603 621 * ··· 672 622 struct cifs_fid fid = {}; 673 623 struct cifs_pending_open open; 674 624 bool oplock_break_cancelled; 625 + bool serverclose_offloaded = false; 675 626 676 627 spin_lock(&tcon->open_file_lock); 677 628 spin_lock(&cifsi->open_file_lock); 678 629 spin_lock(&cifs_file->file_info_lock); 630 + 631 + cifs_file->offload = offload; 679 632 if (--cifs_file->count > 0) { 680 633 spin_unlock(&cifs_file->file_info_lock); 681 634 spin_unlock(&cifsi->open_file_lock); ··· 720 667 if (!tcon->need_reconnect && !cifs_file->invalidHandle) { 721 668 struct TCP_Server_Info *server = tcon->ses->server; 722 669 unsigned int xid; 670 + int rc = 0; 723 671 724 672 xid = get_xid(); 725 673 if (server->ops->close_getattr) 726 - server->ops->close_getattr(xid, tcon, cifs_file); 674 + rc = server->ops->close_getattr(xid, tcon, cifs_file); 727 675 else if (server->ops->close) 728 - server->ops->close(xid, tcon, &cifs_file->fid); 676 + rc = server->ops->close(xid, tcon, &cifs_file->fid); 729 677 _free_xid(xid); 678 + 679 + if (rc == -EBUSY || rc == -EAGAIN) { 680 + // Server close failed, hence offloading it as an async op 681 + queue_work(serverclose_wq, &cifs_file->serverclose); 682 + serverclose_offloaded = true; 683 + } 730 684 } 731 685 732 686 if (oplock_break_cancelled) ··· 741 681 742 682 cifs_del_pending_open(&open); 743 683 744 - if (offload) 745 - queue_work(fileinfo_put_wq, &cifs_file->put); 746 - else 747 - cifsFileInfo_put_final(cifs_file); 684 + // if serverclose has been offloaded to wq (on failure), it will 685 + // handle offloading put as well. If serverclose not offloaded, 686 + // we need to handle offloading put here. 687 + if (!serverclose_offloaded) { 688 + if (offload) 689 + queue_work(fileinfo_put_wq, &cifs_file->put); 690 + else 691 + cifsFileInfo_put_final(cifs_file); 692 + } 748 693 } 749 694 750 695 int cifs_open(struct inode *inode, struct file *file) ··· 899 834 use_cache: 900 835 fscache_use_cookie(cifs_inode_cookie(file_inode(file)), 901 836 file->f_mode & FMODE_WRITE); 902 - if (file->f_flags & O_DIRECT && 903 - (!((file->f_flags & O_ACCMODE) != O_RDONLY) || 904 - file->f_flags & O_APPEND)) 905 - cifs_invalidate_cache(file_inode(file), 906 - FSCACHE_INVAL_DIO_WRITE); 837 + if (!(file->f_flags & O_DIRECT)) 838 + goto out; 839 + if ((file->f_flags & (O_ACCMODE | O_APPEND)) == O_RDONLY) 840 + goto out; 841 + cifs_invalidate_cache(file_inode(file), FSCACHE_INVAL_DIO_WRITE); 907 842 908 843 out: 909 844 free_dentry_path(page); ··· 968 903 int disposition = FILE_OPEN; 969 904 int create_options = CREATE_NOT_DIR; 970 905 struct cifs_open_parms oparms; 906 + int rdwr_for_fscache = 0; 971 907 972 908 xid = get_xid(); 973 909 mutex_lock(&cfile->fh_mutex); ··· 1032 966 } 1033 967 #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 1034 968 1035 - desired_access = cifs_convert_flags(cfile->f_flags); 969 + /* If we're caching, we need to be able to fill in around partial writes. */ 970 + if (cifs_fscache_enabled(inode) && (cfile->f_flags & O_ACCMODE) == O_WRONLY) 971 + rdwr_for_fscache = 1; 972 + 973 + desired_access = cifs_convert_flags(cfile->f_flags, rdwr_for_fscache); 1036 974 1037 975 /* O_SYNC also has bit for O_DSYNC so following check picks up either */ 1038 976 if (cfile->f_flags & O_SYNC) ··· 1048 978 if (server->ops->get_lease_key) 1049 979 server->ops->get_lease_key(inode, &cfile->fid); 1050 980 981 + retry_open: 1051 982 oparms = (struct cifs_open_parms) { 1052 983 .tcon = tcon, 1053 984 .cifs_sb = cifs_sb, ··· 1074 1003 /* indicate that we need to relock the file */ 1075 1004 oparms.reconnect = true; 1076 1005 } 1006 + if (rc == -EACCES && rdwr_for_fscache == 1) { 1007 + desired_access = cifs_convert_flags(cfile->f_flags, 0); 1008 + rdwr_for_fscache = 2; 1009 + goto retry_open; 1010 + } 1077 1011 1078 1012 if (rc) { 1079 1013 mutex_unlock(&cfile->fh_mutex); ··· 1086 1010 cifs_dbg(FYI, "oplock: %d\n", oplock); 1087 1011 goto reopen_error_exit; 1088 1012 } 1013 + 1014 + if (rdwr_for_fscache == 2) 1015 + cifs_invalidate_cache(inode, FSCACHE_INVAL_DIO_WRITE); 1089 1016 1090 1017 #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 1091 1018 reopen_success:
+3 -3
fs/smb/client/fs_context.c
··· 37 37 #include "rfc1002pdu.h" 38 38 #include "fs_context.h" 39 39 40 - static DEFINE_MUTEX(cifs_mount_mutex); 40 + DEFINE_MUTEX(cifs_mount_mutex); 41 41 42 42 static const match_table_t cifs_smb_version_tokens = { 43 43 { Smb_1, SMB1_VERSION_STRING }, ··· 783 783 784 784 if (err) 785 785 return err; 786 - mutex_lock(&cifs_mount_mutex); 786 + cifs_mount_lock(); 787 787 ret = smb3_get_tree_common(fc); 788 - mutex_unlock(&cifs_mount_mutex); 788 + cifs_mount_unlock(); 789 789 return ret; 790 790 } 791 791
+12
fs/smb/client/fs_context.h
··· 304 304 #define MAX_CACHED_FIDS 16 305 305 extern char *cifs_sanitize_prepath(char *prepath, gfp_t gfp); 306 306 307 + extern struct mutex cifs_mount_mutex; 308 + 309 + static inline void cifs_mount_lock(void) 310 + { 311 + mutex_lock(&cifs_mount_mutex); 312 + } 313 + 314 + static inline void cifs_mount_unlock(void) 315 + { 316 + mutex_unlock(&cifs_mount_mutex); 317 + } 318 + 307 319 #endif
+6
fs/smb/client/fscache.h
··· 109 109 __cifs_readahead_to_fscache(inode, pos, len); 110 110 } 111 111 112 + static inline bool cifs_fscache_enabled(struct inode *inode) 113 + { 114 + return fscache_cookie_enabled(cifs_inode_cookie(inode)); 115 + } 116 + 112 117 #else /* CONFIG_CIFS_FSCACHE */ 113 118 static inline 114 119 void cifs_fscache_fill_coherency(struct inode *inode, ··· 129 124 static inline void cifs_fscache_unuse_inode_cookie(struct inode *inode, bool update) {} 130 125 static inline struct fscache_cookie *cifs_inode_cookie(struct inode *inode) { return NULL; } 131 126 static inline void cifs_invalidate_cache(struct inode *inode, unsigned int flags) {} 127 + static inline bool cifs_fscache_enabled(struct inode *inode) { return false; } 132 128 133 129 static inline int cifs_fscache_query_occupancy(struct inode *inode, 134 130 pgoff_t first, unsigned int nr_pages,
+5 -1
fs/smb/client/ioctl.c
··· 247 247 spin_lock(&cifs_tcp_ses_lock); 248 248 list_for_each_entry(server_it, &cifs_tcp_ses_list, tcp_ses_list) { 249 249 list_for_each_entry(ses_it, &server_it->smb_ses_list, smb_ses_list) { 250 - if (ses_it->Suid == out.session_id) { 250 + spin_lock(&ses_it->ses_lock); 251 + if (ses_it->ses_status != SES_EXITING && 252 + ses_it->Suid == out.session_id) { 251 253 ses = ses_it; 252 254 /* 253 255 * since we are using the session outside the crit ··· 257 255 * so increment its refcount 258 256 */ 259 257 cifs_smb_ses_inc_refcount(ses); 258 + spin_unlock(&ses_it->ses_lock); 260 259 found = true; 261 260 goto search_end; 262 261 } 262 + spin_unlock(&ses_it->ses_lock); 263 263 } 264 264 } 265 265 search_end:
+2 -6
fs/smb/client/misc.c
··· 138 138 atomic_set(&ret_buf->num_local_opens, 0); 139 139 atomic_set(&ret_buf->num_remote_opens, 0); 140 140 ret_buf->stats_from_time = ktime_get_real_seconds(); 141 - #ifdef CONFIG_CIFS_DFS_UPCALL 142 - INIT_LIST_HEAD(&ret_buf->dfs_ses_list); 143 - #endif 144 141 145 142 return ret_buf; 146 143 } ··· 153 156 atomic_dec(&tconInfoAllocCount); 154 157 kfree(tcon->nativeFileSystem); 155 158 kfree_sensitive(tcon->password); 156 - #ifdef CONFIG_CIFS_DFS_UPCALL 157 - dfs_put_root_smb_sessions(&tcon->dfs_ses_list); 158 - #endif 159 159 kfree(tcon->origin_fullpath); 160 160 kfree(tcon); 161 161 } ··· 481 487 /* look up tcon based on tid & uid */ 482 488 spin_lock(&cifs_tcp_ses_lock); 483 489 list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) { 490 + if (cifs_ses_exiting(ses)) 491 + continue; 484 492 list_for_each_entry(tcon, &ses->tcon_list, tcon_list) { 485 493 if (tcon->tid != buf->Tid) 486 494 continue;
+2 -2
fs/smb/client/smb1ops.c
··· 753 753 cinode->can_cache_brlcks = CIFS_CACHE_WRITE(cinode); 754 754 } 755 755 756 - static void 756 + static int 757 757 cifs_close_file(const unsigned int xid, struct cifs_tcon *tcon, 758 758 struct cifs_fid *fid) 759 759 { 760 - CIFSSMBClose(xid, tcon, fid->netfid); 760 + return CIFSSMBClose(xid, tcon, fid->netfid); 761 761 } 762 762 763 763 static int
+4
fs/smb/client/smb2misc.c
··· 622 622 /* look up tcon based on tid & uid */ 623 623 spin_lock(&cifs_tcp_ses_lock); 624 624 list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) { 625 + if (cifs_ses_exiting(ses)) 626 + continue; 625 627 list_for_each_entry(tcon, &ses->tcon_list, tcon_list) { 626 628 spin_lock(&tcon->open_file_lock); 627 629 cifs_stats_inc( ··· 699 697 /* look up tcon based on tid & uid */ 700 698 spin_lock(&cifs_tcp_ses_lock); 701 699 list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) { 700 + if (cifs_ses_exiting(ses)) 701 + continue; 702 702 list_for_each_entry(tcon, &ses->tcon_list, tcon_list) { 703 703 704 704 spin_lock(&tcon->open_file_lock);
+8 -5
fs/smb/client/smb2ops.c
··· 1412 1412 memcpy(cfile->fid.create_guid, fid->create_guid, 16); 1413 1413 } 1414 1414 1415 - static void 1415 + static int 1416 1416 smb2_close_file(const unsigned int xid, struct cifs_tcon *tcon, 1417 1417 struct cifs_fid *fid) 1418 1418 { 1419 - SMB2_close(xid, tcon, fid->persistent_fid, fid->volatile_fid); 1419 + return SMB2_close(xid, tcon, fid->persistent_fid, fid->volatile_fid); 1420 1420 } 1421 1421 1422 - static void 1422 + static int 1423 1423 smb2_close_getattr(const unsigned int xid, struct cifs_tcon *tcon, 1424 1424 struct cifsFileInfo *cfile) 1425 1425 { ··· 1430 1430 rc = __SMB2_close(xid, tcon, cfile->fid.persistent_fid, 1431 1431 cfile->fid.volatile_fid, &file_inf); 1432 1432 if (rc) 1433 - return; 1433 + return rc; 1434 1434 1435 1435 inode = d_inode(cfile->dentry); 1436 1436 ··· 1459 1459 1460 1460 /* End of file and Attributes should not have to be updated on close */ 1461 1461 spin_unlock(&inode->i_lock); 1462 + return rc; 1462 1463 } 1463 1464 1464 1465 static int ··· 2481 2480 2482 2481 spin_lock(&cifs_tcp_ses_lock); 2483 2482 list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) { 2483 + if (cifs_ses_exiting(ses)) 2484 + continue; 2484 2485 list_for_each_entry(tcon, &ses->tcon_list, tcon_list) { 2485 2486 if (tcon->tid == le32_to_cpu(shdr->Id.SyncId.TreeId)) { 2486 2487 spin_lock(&tcon->tc_lock); ··· 3916 3913 strcat(message, "W"); 3917 3914 } 3918 3915 if (!new_oplock) 3919 - strncpy(message, "None", sizeof(message)); 3916 + strscpy(message, "None"); 3920 3917 3921 3918 cinode->oplock = new_oplock; 3922 3919 cifs_dbg(FYI, "%s Lease granted on inode %p\n", message,
+1 -1
fs/smb/client/smb2pdu.c
··· 3628 3628 memcpy(&pbuf->network_open_info, 3629 3629 &rsp->network_open_info, 3630 3630 sizeof(pbuf->network_open_info)); 3631 + atomic_dec(&tcon->num_remote_opens); 3631 3632 } 3632 3633 3633 - atomic_dec(&tcon->num_remote_opens); 3634 3634 close_exit: 3635 3635 SMB2_close_free(&rqst); 3636 3636 free_rsp_buf(resp_buftype, rsp);
+1 -1
fs/smb/client/smb2transport.c
··· 659 659 } 660 660 spin_unlock(&server->srv_lock); 661 661 if (!is_binding && !server->session_estab) { 662 - strncpy(shdr->Signature, "BSRSPYL", 8); 662 + strscpy(shdr->Signature, "BSRSPYL"); 663 663 return 0; 664 664 } 665 665