162306a36Sopenharmony_ci// SPDX-License-Identifier: LGPL-2.1 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) International Business Machines Corp., 2002,2008 562306a36Sopenharmony_ci * Author(s): Steve French (sfrench@us.ibm.com) 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Common Internet FileSystem (CIFS) client 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci/* Note that BB means BUGBUG (ie something to fix eventually) */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/module.h> 1462306a36Sopenharmony_ci#include <linux/fs.h> 1562306a36Sopenharmony_ci#include <linux/filelock.h> 1662306a36Sopenharmony_ci#include <linux/mount.h> 1762306a36Sopenharmony_ci#include <linux/slab.h> 1862306a36Sopenharmony_ci#include <linux/init.h> 1962306a36Sopenharmony_ci#include <linux/list.h> 2062306a36Sopenharmony_ci#include <linux/seq_file.h> 2162306a36Sopenharmony_ci#include <linux/vfs.h> 2262306a36Sopenharmony_ci#include <linux/mempool.h> 2362306a36Sopenharmony_ci#include <linux/delay.h> 2462306a36Sopenharmony_ci#include <linux/kthread.h> 2562306a36Sopenharmony_ci#include <linux/freezer.h> 2662306a36Sopenharmony_ci#include <linux/namei.h> 2762306a36Sopenharmony_ci#include <linux/random.h> 2862306a36Sopenharmony_ci#include <linux/uuid.h> 2962306a36Sopenharmony_ci#include <linux/xattr.h> 3062306a36Sopenharmony_ci#include <uapi/linux/magic.h> 3162306a36Sopenharmony_ci#include <net/ipv6.h> 3262306a36Sopenharmony_ci#include "cifsfs.h" 3362306a36Sopenharmony_ci#include "cifspdu.h" 3462306a36Sopenharmony_ci#define DECLARE_GLOBALS_HERE 3562306a36Sopenharmony_ci#include "cifsglob.h" 3662306a36Sopenharmony_ci#include "cifsproto.h" 3762306a36Sopenharmony_ci#include "cifs_debug.h" 3862306a36Sopenharmony_ci#include "cifs_fs_sb.h" 3962306a36Sopenharmony_ci#include <linux/mm.h> 4062306a36Sopenharmony_ci#include <linux/key-type.h> 4162306a36Sopenharmony_ci#include "cifs_spnego.h" 4262306a36Sopenharmony_ci#include "fscache.h" 4362306a36Sopenharmony_ci#ifdef CONFIG_CIFS_DFS_UPCALL 4462306a36Sopenharmony_ci#include "dfs_cache.h" 4562306a36Sopenharmony_ci#endif 4662306a36Sopenharmony_ci#ifdef CONFIG_CIFS_SWN_UPCALL 4762306a36Sopenharmony_ci#include "netlink.h" 4862306a36Sopenharmony_ci#endif 4962306a36Sopenharmony_ci#include "fs_context.h" 5062306a36Sopenharmony_ci#include "cached_dir.h" 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci/* 5362306a36Sopenharmony_ci * DOS dates from 1980/1/1 through 2107/12/31 5462306a36Sopenharmony_ci * Protocol specifications indicate the range should be to 119, which 5562306a36Sopenharmony_ci * limits maximum year to 2099. But this range has not been checked. 5662306a36Sopenharmony_ci */ 5762306a36Sopenharmony_ci#define SMB_DATE_MAX (127<<9 | 12<<5 | 31) 5862306a36Sopenharmony_ci#define SMB_DATE_MIN (0<<9 | 1<<5 | 1) 5962306a36Sopenharmony_ci#define SMB_TIME_MAX (23<<11 | 59<<5 | 29) 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ciint cifsFYI = 0; 6262306a36Sopenharmony_cibool traceSMB; 6362306a36Sopenharmony_cibool enable_oplocks = true; 6462306a36Sopenharmony_cibool linuxExtEnabled = true; 6562306a36Sopenharmony_cibool lookupCacheEnabled = true; 6662306a36Sopenharmony_cibool disable_legacy_dialects; /* false by default */ 6762306a36Sopenharmony_cibool enable_gcm_256 = true; 6862306a36Sopenharmony_cibool require_gcm_256; /* false by default */ 6962306a36Sopenharmony_cibool enable_negotiate_signing; /* false by default */ 7062306a36Sopenharmony_ciunsigned int global_secflags = CIFSSEC_DEF; 7162306a36Sopenharmony_ci/* unsigned int ntlmv2_support = 0; */ 7262306a36Sopenharmony_ciunsigned int sign_CIFS_PDUs = 1; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci/* 7562306a36Sopenharmony_ci * Global transaction id (XID) information 7662306a36Sopenharmony_ci */ 7762306a36Sopenharmony_ciunsigned int GlobalCurrentXid; /* protected by GlobalMid_Sem */ 7862306a36Sopenharmony_ciunsigned int GlobalTotalActiveXid; /* prot by GlobalMid_Sem */ 7962306a36Sopenharmony_ciunsigned int GlobalMaxActiveXid; /* prot by GlobalMid_Sem */ 8062306a36Sopenharmony_cispinlock_t GlobalMid_Lock; /* protects above & list operations on midQ entries */ 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci/* 8362306a36Sopenharmony_ci * Global counters, updated atomically 8462306a36Sopenharmony_ci */ 8562306a36Sopenharmony_ciatomic_t sesInfoAllocCount; 8662306a36Sopenharmony_ciatomic_t tconInfoAllocCount; 8762306a36Sopenharmony_ciatomic_t tcpSesNextId; 8862306a36Sopenharmony_ciatomic_t tcpSesAllocCount; 8962306a36Sopenharmony_ciatomic_t tcpSesReconnectCount; 9062306a36Sopenharmony_ciatomic_t tconInfoReconnectCount; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ciatomic_t mid_count; 9362306a36Sopenharmony_ciatomic_t buf_alloc_count; 9462306a36Sopenharmony_ciatomic_t small_buf_alloc_count; 9562306a36Sopenharmony_ci#ifdef CONFIG_CIFS_STATS2 9662306a36Sopenharmony_ciatomic_t total_buf_alloc_count; 9762306a36Sopenharmony_ciatomic_t total_small_buf_alloc_count; 9862306a36Sopenharmony_ci#endif/* STATS2 */ 9962306a36Sopenharmony_cistruct list_head cifs_tcp_ses_list; 10062306a36Sopenharmony_cispinlock_t cifs_tcp_ses_lock; 10162306a36Sopenharmony_cistatic const struct super_operations cifs_super_ops; 10262306a36Sopenharmony_ciunsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE; 10362306a36Sopenharmony_cimodule_param(CIFSMaxBufSize, uint, 0444); 10462306a36Sopenharmony_ciMODULE_PARM_DESC(CIFSMaxBufSize, "Network buffer size (not including header) " 10562306a36Sopenharmony_ci "for CIFS requests. " 10662306a36Sopenharmony_ci "Default: 16384 Range: 8192 to 130048"); 10762306a36Sopenharmony_ciunsigned int cifs_min_rcv = CIFS_MIN_RCV_POOL; 10862306a36Sopenharmony_cimodule_param(cifs_min_rcv, uint, 0444); 10962306a36Sopenharmony_ciMODULE_PARM_DESC(cifs_min_rcv, "Network buffers in pool. Default: 4 Range: " 11062306a36Sopenharmony_ci "1 to 64"); 11162306a36Sopenharmony_ciunsigned int cifs_min_small = 30; 11262306a36Sopenharmony_cimodule_param(cifs_min_small, uint, 0444); 11362306a36Sopenharmony_ciMODULE_PARM_DESC(cifs_min_small, "Small network buffers in pool. Default: 30 " 11462306a36Sopenharmony_ci "Range: 2 to 256"); 11562306a36Sopenharmony_ciunsigned int cifs_max_pending = CIFS_MAX_REQ; 11662306a36Sopenharmony_cimodule_param(cifs_max_pending, uint, 0444); 11762306a36Sopenharmony_ciMODULE_PARM_DESC(cifs_max_pending, "Simultaneous requests to server for " 11862306a36Sopenharmony_ci "CIFS/SMB1 dialect (N/A for SMB3) " 11962306a36Sopenharmony_ci "Default: 32767 Range: 2 to 32767."); 12062306a36Sopenharmony_ciunsigned int dir_cache_timeout = 30; 12162306a36Sopenharmony_cimodule_param(dir_cache_timeout, uint, 0644); 12262306a36Sopenharmony_ciMODULE_PARM_DESC(dir_cache_timeout, "Number of seconds to cache directory contents for which we have a lease. Default: 30 " 12362306a36Sopenharmony_ci "Range: 1 to 65000 seconds, 0 to disable caching dir contents"); 12462306a36Sopenharmony_ci#ifdef CONFIG_CIFS_STATS2 12562306a36Sopenharmony_ciunsigned int slow_rsp_threshold = 1; 12662306a36Sopenharmony_cimodule_param(slow_rsp_threshold, uint, 0644); 12762306a36Sopenharmony_ciMODULE_PARM_DESC(slow_rsp_threshold, "Amount of time (in seconds) to wait " 12862306a36Sopenharmony_ci "before logging that a response is delayed. " 12962306a36Sopenharmony_ci "Default: 1 (if set to 0 disables msg)."); 13062306a36Sopenharmony_ci#endif /* STATS2 */ 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cimodule_param(enable_oplocks, bool, 0644); 13362306a36Sopenharmony_ciMODULE_PARM_DESC(enable_oplocks, "Enable or disable oplocks. Default: y/Y/1"); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cimodule_param(enable_gcm_256, bool, 0644); 13662306a36Sopenharmony_ciMODULE_PARM_DESC(enable_gcm_256, "Enable requesting strongest (256 bit) GCM encryption. Default: n/N/0"); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cimodule_param(require_gcm_256, bool, 0644); 13962306a36Sopenharmony_ciMODULE_PARM_DESC(require_gcm_256, "Require strongest (256 bit) GCM encryption. Default: n/N/0"); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cimodule_param(enable_negotiate_signing, bool, 0644); 14262306a36Sopenharmony_ciMODULE_PARM_DESC(enable_negotiate_signing, "Enable negotiating packet signing algorithm with server. Default: n/N/0"); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_cimodule_param(disable_legacy_dialects, bool, 0644); 14562306a36Sopenharmony_ciMODULE_PARM_DESC(disable_legacy_dialects, "To improve security it may be " 14662306a36Sopenharmony_ci "helpful to restrict the ability to " 14762306a36Sopenharmony_ci "override the default dialects (SMB2.1, " 14862306a36Sopenharmony_ci "SMB3 and SMB3.02) on mount with old " 14962306a36Sopenharmony_ci "dialects (CIFS/SMB1 and SMB2) since " 15062306a36Sopenharmony_ci "vers=1.0 (CIFS/SMB1) and vers=2.0 are weaker" 15162306a36Sopenharmony_ci " and less secure. Default: n/N/0"); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ciextern mempool_t *cifs_sm_req_poolp; 15462306a36Sopenharmony_ciextern mempool_t *cifs_req_poolp; 15562306a36Sopenharmony_ciextern mempool_t *cifs_mid_poolp; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cistruct workqueue_struct *cifsiod_wq; 15862306a36Sopenharmony_cistruct workqueue_struct *decrypt_wq; 15962306a36Sopenharmony_cistruct workqueue_struct *fileinfo_put_wq; 16062306a36Sopenharmony_cistruct workqueue_struct *cifsoplockd_wq; 16162306a36Sopenharmony_cistruct workqueue_struct *deferredclose_wq; 16262306a36Sopenharmony_ci__u32 cifs_lock_secret; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci/* 16562306a36Sopenharmony_ci * Bumps refcount for cifs super block. 16662306a36Sopenharmony_ci * Note that it should be only called if a referece to VFS super block is 16762306a36Sopenharmony_ci * already held, e.g. in open-type syscalls context. Otherwise it can race with 16862306a36Sopenharmony_ci * atomic_dec_and_test in deactivate_locked_super. 16962306a36Sopenharmony_ci */ 17062306a36Sopenharmony_civoid 17162306a36Sopenharmony_cicifs_sb_active(struct super_block *sb) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci struct cifs_sb_info *server = CIFS_SB(sb); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci if (atomic_inc_return(&server->active) == 1) 17662306a36Sopenharmony_ci atomic_inc(&sb->s_active); 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_civoid 18062306a36Sopenharmony_cicifs_sb_deactive(struct super_block *sb) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci struct cifs_sb_info *server = CIFS_SB(sb); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci if (atomic_dec_and_test(&server->active)) 18562306a36Sopenharmony_ci deactivate_super(sb); 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cistatic int 18962306a36Sopenharmony_cicifs_read_super(struct super_block *sb) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci struct inode *inode; 19262306a36Sopenharmony_ci struct cifs_sb_info *cifs_sb; 19362306a36Sopenharmony_ci struct cifs_tcon *tcon; 19462306a36Sopenharmony_ci struct timespec64 ts; 19562306a36Sopenharmony_ci int rc = 0; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci cifs_sb = CIFS_SB(sb); 19862306a36Sopenharmony_ci tcon = cifs_sb_master_tcon(cifs_sb); 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIXACL) 20162306a36Sopenharmony_ci sb->s_flags |= SB_POSIXACL; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci if (tcon->snapshot_time) 20462306a36Sopenharmony_ci sb->s_flags |= SB_RDONLY; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci if (tcon->ses->capabilities & tcon->ses->server->vals->cap_large_files) 20762306a36Sopenharmony_ci sb->s_maxbytes = MAX_LFS_FILESIZE; 20862306a36Sopenharmony_ci else 20962306a36Sopenharmony_ci sb->s_maxbytes = MAX_NON_LFS; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci /* 21262306a36Sopenharmony_ci * Some very old servers like DOS and OS/2 used 2 second granularity 21362306a36Sopenharmony_ci * (while all current servers use 100ns granularity - see MS-DTYP) 21462306a36Sopenharmony_ci * but 1 second is the maximum allowed granularity for the VFS 21562306a36Sopenharmony_ci * so for old servers set time granularity to 1 second while for 21662306a36Sopenharmony_ci * everything else (current servers) set it to 100ns. 21762306a36Sopenharmony_ci */ 21862306a36Sopenharmony_ci if ((tcon->ses->server->vals->protocol_id == SMB10_PROT_ID) && 21962306a36Sopenharmony_ci ((tcon->ses->capabilities & 22062306a36Sopenharmony_ci tcon->ses->server->vals->cap_nt_find) == 0) && 22162306a36Sopenharmony_ci !tcon->unix_ext) { 22262306a36Sopenharmony_ci sb->s_time_gran = 1000000000; /* 1 second is max allowed gran */ 22362306a36Sopenharmony_ci ts = cnvrtDosUnixTm(cpu_to_le16(SMB_DATE_MIN), 0, 0); 22462306a36Sopenharmony_ci sb->s_time_min = ts.tv_sec; 22562306a36Sopenharmony_ci ts = cnvrtDosUnixTm(cpu_to_le16(SMB_DATE_MAX), 22662306a36Sopenharmony_ci cpu_to_le16(SMB_TIME_MAX), 0); 22762306a36Sopenharmony_ci sb->s_time_max = ts.tv_sec; 22862306a36Sopenharmony_ci } else { 22962306a36Sopenharmony_ci /* 23062306a36Sopenharmony_ci * Almost every server, including all SMB2+, uses DCE TIME 23162306a36Sopenharmony_ci * ie 100 nanosecond units, since 1601. See MS-DTYP and MS-FSCC 23262306a36Sopenharmony_ci */ 23362306a36Sopenharmony_ci sb->s_time_gran = 100; 23462306a36Sopenharmony_ci ts = cifs_NTtimeToUnix(0); 23562306a36Sopenharmony_ci sb->s_time_min = ts.tv_sec; 23662306a36Sopenharmony_ci ts = cifs_NTtimeToUnix(cpu_to_le64(S64_MAX)); 23762306a36Sopenharmony_ci sb->s_time_max = ts.tv_sec; 23862306a36Sopenharmony_ci } 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci sb->s_magic = CIFS_SUPER_MAGIC; 24162306a36Sopenharmony_ci sb->s_op = &cifs_super_ops; 24262306a36Sopenharmony_ci sb->s_xattr = cifs_xattr_handlers; 24362306a36Sopenharmony_ci rc = super_setup_bdi(sb); 24462306a36Sopenharmony_ci if (rc) 24562306a36Sopenharmony_ci goto out_no_root; 24662306a36Sopenharmony_ci /* tune readahead according to rsize if readahead size not set on mount */ 24762306a36Sopenharmony_ci if (cifs_sb->ctx->rsize == 0) 24862306a36Sopenharmony_ci cifs_sb->ctx->rsize = 24962306a36Sopenharmony_ci tcon->ses->server->ops->negotiate_rsize(tcon, cifs_sb->ctx); 25062306a36Sopenharmony_ci if (cifs_sb->ctx->rasize) 25162306a36Sopenharmony_ci sb->s_bdi->ra_pages = cifs_sb->ctx->rasize / PAGE_SIZE; 25262306a36Sopenharmony_ci else 25362306a36Sopenharmony_ci sb->s_bdi->ra_pages = 2 * (cifs_sb->ctx->rsize / PAGE_SIZE); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci sb->s_blocksize = CIFS_MAX_MSGSIZE; 25662306a36Sopenharmony_ci sb->s_blocksize_bits = 14; /* default 2**14 = CIFS_MAX_MSGSIZE */ 25762306a36Sopenharmony_ci inode = cifs_root_iget(sb); 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci if (IS_ERR(inode)) { 26062306a36Sopenharmony_ci rc = PTR_ERR(inode); 26162306a36Sopenharmony_ci goto out_no_root; 26262306a36Sopenharmony_ci } 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci if (tcon->nocase) 26562306a36Sopenharmony_ci sb->s_d_op = &cifs_ci_dentry_ops; 26662306a36Sopenharmony_ci else 26762306a36Sopenharmony_ci sb->s_d_op = &cifs_dentry_ops; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci sb->s_root = d_make_root(inode); 27062306a36Sopenharmony_ci if (!sb->s_root) { 27162306a36Sopenharmony_ci rc = -ENOMEM; 27262306a36Sopenharmony_ci goto out_no_root; 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci#ifdef CONFIG_CIFS_NFSD_EXPORT 27662306a36Sopenharmony_ci if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { 27762306a36Sopenharmony_ci cifs_dbg(FYI, "export ops supported\n"); 27862306a36Sopenharmony_ci sb->s_export_op = &cifs_export_ops; 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci#endif /* CONFIG_CIFS_NFSD_EXPORT */ 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci return 0; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ciout_no_root: 28562306a36Sopenharmony_ci cifs_dbg(VFS, "%s: get root inode failed\n", __func__); 28662306a36Sopenharmony_ci return rc; 28762306a36Sopenharmony_ci} 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_cistatic void cifs_kill_sb(struct super_block *sb) 29062306a36Sopenharmony_ci{ 29162306a36Sopenharmony_ci struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci /* 29462306a36Sopenharmony_ci * We ned to release all dentries for the cached directories 29562306a36Sopenharmony_ci * before we kill the sb. 29662306a36Sopenharmony_ci */ 29762306a36Sopenharmony_ci if (cifs_sb->root) { 29862306a36Sopenharmony_ci close_all_cached_dirs(cifs_sb); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci /* finally release root dentry */ 30162306a36Sopenharmony_ci dput(cifs_sb->root); 30262306a36Sopenharmony_ci cifs_sb->root = NULL; 30362306a36Sopenharmony_ci } 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci kill_anon_super(sb); 30662306a36Sopenharmony_ci cifs_umount(cifs_sb); 30762306a36Sopenharmony_ci} 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_cistatic int 31062306a36Sopenharmony_cicifs_statfs(struct dentry *dentry, struct kstatfs *buf) 31162306a36Sopenharmony_ci{ 31262306a36Sopenharmony_ci struct super_block *sb = dentry->d_sb; 31362306a36Sopenharmony_ci struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 31462306a36Sopenharmony_ci struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); 31562306a36Sopenharmony_ci struct TCP_Server_Info *server = tcon->ses->server; 31662306a36Sopenharmony_ci unsigned int xid; 31762306a36Sopenharmony_ci int rc = 0; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci xid = get_xid(); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci if (le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength) > 0) 32262306a36Sopenharmony_ci buf->f_namelen = 32362306a36Sopenharmony_ci le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength); 32462306a36Sopenharmony_ci else 32562306a36Sopenharmony_ci buf->f_namelen = PATH_MAX; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci buf->f_fsid.val[0] = tcon->vol_serial_number; 32862306a36Sopenharmony_ci /* are using part of create time for more randomness, see man statfs */ 32962306a36Sopenharmony_ci buf->f_fsid.val[1] = (int)le64_to_cpu(tcon->vol_create_time); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci buf->f_files = 0; /* undefined */ 33262306a36Sopenharmony_ci buf->f_ffree = 0; /* unlimited */ 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci if (server->ops->queryfs) 33562306a36Sopenharmony_ci rc = server->ops->queryfs(xid, tcon, cifs_sb, buf); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci free_xid(xid); 33862306a36Sopenharmony_ci return rc; 33962306a36Sopenharmony_ci} 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_cistatic long cifs_fallocate(struct file *file, int mode, loff_t off, loff_t len) 34262306a36Sopenharmony_ci{ 34362306a36Sopenharmony_ci struct cifs_sb_info *cifs_sb = CIFS_FILE_SB(file); 34462306a36Sopenharmony_ci struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); 34562306a36Sopenharmony_ci struct TCP_Server_Info *server = tcon->ses->server; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci if (server->ops->fallocate) 34862306a36Sopenharmony_ci return server->ops->fallocate(file, tcon, mode, off, len); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci return -EOPNOTSUPP; 35162306a36Sopenharmony_ci} 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_cistatic int cifs_permission(struct mnt_idmap *idmap, 35462306a36Sopenharmony_ci struct inode *inode, int mask) 35562306a36Sopenharmony_ci{ 35662306a36Sopenharmony_ci struct cifs_sb_info *cifs_sb; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci cifs_sb = CIFS_SB(inode->i_sb); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) { 36162306a36Sopenharmony_ci if ((mask & MAY_EXEC) && !execute_ok(inode)) 36262306a36Sopenharmony_ci return -EACCES; 36362306a36Sopenharmony_ci else 36462306a36Sopenharmony_ci return 0; 36562306a36Sopenharmony_ci } else /* file mode might have been restricted at mount time 36662306a36Sopenharmony_ci on the client (above and beyond ACL on servers) for 36762306a36Sopenharmony_ci servers which do not support setting and viewing mode bits, 36862306a36Sopenharmony_ci so allowing client to check permissions is useful */ 36962306a36Sopenharmony_ci return generic_permission(&nop_mnt_idmap, inode, mask); 37062306a36Sopenharmony_ci} 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_cistatic struct kmem_cache *cifs_inode_cachep; 37362306a36Sopenharmony_cistatic struct kmem_cache *cifs_req_cachep; 37462306a36Sopenharmony_cistatic struct kmem_cache *cifs_mid_cachep; 37562306a36Sopenharmony_cistatic struct kmem_cache *cifs_sm_req_cachep; 37662306a36Sopenharmony_cimempool_t *cifs_sm_req_poolp; 37762306a36Sopenharmony_cimempool_t *cifs_req_poolp; 37862306a36Sopenharmony_cimempool_t *cifs_mid_poolp; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_cistatic struct inode * 38162306a36Sopenharmony_cicifs_alloc_inode(struct super_block *sb) 38262306a36Sopenharmony_ci{ 38362306a36Sopenharmony_ci struct cifsInodeInfo *cifs_inode; 38462306a36Sopenharmony_ci cifs_inode = alloc_inode_sb(sb, cifs_inode_cachep, GFP_KERNEL); 38562306a36Sopenharmony_ci if (!cifs_inode) 38662306a36Sopenharmony_ci return NULL; 38762306a36Sopenharmony_ci cifs_inode->cifsAttrs = 0x20; /* default */ 38862306a36Sopenharmony_ci cifs_inode->time = 0; 38962306a36Sopenharmony_ci /* 39062306a36Sopenharmony_ci * Until the file is open and we have gotten oplock info back from the 39162306a36Sopenharmony_ci * server, can not assume caching of file data or metadata. 39262306a36Sopenharmony_ci */ 39362306a36Sopenharmony_ci cifs_set_oplock_level(cifs_inode, 0); 39462306a36Sopenharmony_ci cifs_inode->flags = 0; 39562306a36Sopenharmony_ci spin_lock_init(&cifs_inode->writers_lock); 39662306a36Sopenharmony_ci cifs_inode->writers = 0; 39762306a36Sopenharmony_ci cifs_inode->netfs.inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ 39862306a36Sopenharmony_ci cifs_inode->server_eof = 0; 39962306a36Sopenharmony_ci cifs_inode->uniqueid = 0; 40062306a36Sopenharmony_ci cifs_inode->createtime = 0; 40162306a36Sopenharmony_ci cifs_inode->epoch = 0; 40262306a36Sopenharmony_ci spin_lock_init(&cifs_inode->open_file_lock); 40362306a36Sopenharmony_ci generate_random_uuid(cifs_inode->lease_key); 40462306a36Sopenharmony_ci cifs_inode->symlink_target = NULL; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci /* 40762306a36Sopenharmony_ci * Can not set i_flags here - they get immediately overwritten to zero 40862306a36Sopenharmony_ci * by the VFS. 40962306a36Sopenharmony_ci */ 41062306a36Sopenharmony_ci /* cifs_inode->netfs.inode.i_flags = S_NOATIME | S_NOCMTIME; */ 41162306a36Sopenharmony_ci INIT_LIST_HEAD(&cifs_inode->openFileList); 41262306a36Sopenharmony_ci INIT_LIST_HEAD(&cifs_inode->llist); 41362306a36Sopenharmony_ci INIT_LIST_HEAD(&cifs_inode->deferred_closes); 41462306a36Sopenharmony_ci spin_lock_init(&cifs_inode->deferred_lock); 41562306a36Sopenharmony_ci return &cifs_inode->netfs.inode; 41662306a36Sopenharmony_ci} 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_cistatic void 41962306a36Sopenharmony_cicifs_free_inode(struct inode *inode) 42062306a36Sopenharmony_ci{ 42162306a36Sopenharmony_ci struct cifsInodeInfo *cinode = CIFS_I(inode); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci if (S_ISLNK(inode->i_mode)) 42462306a36Sopenharmony_ci kfree(cinode->symlink_target); 42562306a36Sopenharmony_ci kmem_cache_free(cifs_inode_cachep, cinode); 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_cistatic void 42962306a36Sopenharmony_cicifs_evict_inode(struct inode *inode) 43062306a36Sopenharmony_ci{ 43162306a36Sopenharmony_ci truncate_inode_pages_final(&inode->i_data); 43262306a36Sopenharmony_ci if (inode->i_state & I_PINNING_FSCACHE_WB) 43362306a36Sopenharmony_ci cifs_fscache_unuse_inode_cookie(inode, true); 43462306a36Sopenharmony_ci cifs_fscache_release_inode_cookie(inode); 43562306a36Sopenharmony_ci clear_inode(inode); 43662306a36Sopenharmony_ci} 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_cistatic void 43962306a36Sopenharmony_cicifs_show_address(struct seq_file *s, struct TCP_Server_Info *server) 44062306a36Sopenharmony_ci{ 44162306a36Sopenharmony_ci struct sockaddr_in *sa = (struct sockaddr_in *) &server->dstaddr; 44262306a36Sopenharmony_ci struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) &server->dstaddr; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci seq_puts(s, ",addr="); 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci switch (server->dstaddr.ss_family) { 44762306a36Sopenharmony_ci case AF_INET: 44862306a36Sopenharmony_ci seq_printf(s, "%pI4", &sa->sin_addr.s_addr); 44962306a36Sopenharmony_ci break; 45062306a36Sopenharmony_ci case AF_INET6: 45162306a36Sopenharmony_ci seq_printf(s, "%pI6", &sa6->sin6_addr.s6_addr); 45262306a36Sopenharmony_ci if (sa6->sin6_scope_id) 45362306a36Sopenharmony_ci seq_printf(s, "%%%u", sa6->sin6_scope_id); 45462306a36Sopenharmony_ci break; 45562306a36Sopenharmony_ci default: 45662306a36Sopenharmony_ci seq_puts(s, "(unknown)"); 45762306a36Sopenharmony_ci } 45862306a36Sopenharmony_ci if (server->rdma) 45962306a36Sopenharmony_ci seq_puts(s, ",rdma"); 46062306a36Sopenharmony_ci} 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_cistatic void 46362306a36Sopenharmony_cicifs_show_security(struct seq_file *s, struct cifs_ses *ses) 46462306a36Sopenharmony_ci{ 46562306a36Sopenharmony_ci if (ses->sectype == Unspecified) { 46662306a36Sopenharmony_ci if (ses->user_name == NULL) 46762306a36Sopenharmony_ci seq_puts(s, ",sec=none"); 46862306a36Sopenharmony_ci return; 46962306a36Sopenharmony_ci } 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci seq_puts(s, ",sec="); 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci switch (ses->sectype) { 47462306a36Sopenharmony_ci case NTLMv2: 47562306a36Sopenharmony_ci seq_puts(s, "ntlmv2"); 47662306a36Sopenharmony_ci break; 47762306a36Sopenharmony_ci case Kerberos: 47862306a36Sopenharmony_ci seq_puts(s, "krb5"); 47962306a36Sopenharmony_ci break; 48062306a36Sopenharmony_ci case RawNTLMSSP: 48162306a36Sopenharmony_ci seq_puts(s, "ntlmssp"); 48262306a36Sopenharmony_ci break; 48362306a36Sopenharmony_ci default: 48462306a36Sopenharmony_ci /* shouldn't ever happen */ 48562306a36Sopenharmony_ci seq_puts(s, "unknown"); 48662306a36Sopenharmony_ci break; 48762306a36Sopenharmony_ci } 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci if (ses->sign) 49062306a36Sopenharmony_ci seq_puts(s, "i"); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci if (ses->sectype == Kerberos) 49362306a36Sopenharmony_ci seq_printf(s, ",cruid=%u", 49462306a36Sopenharmony_ci from_kuid_munged(&init_user_ns, ses->cred_uid)); 49562306a36Sopenharmony_ci} 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_cistatic void 49862306a36Sopenharmony_cicifs_show_cache_flavor(struct seq_file *s, struct cifs_sb_info *cifs_sb) 49962306a36Sopenharmony_ci{ 50062306a36Sopenharmony_ci seq_puts(s, ",cache="); 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO) 50362306a36Sopenharmony_ci seq_puts(s, "strict"); 50462306a36Sopenharmony_ci else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) 50562306a36Sopenharmony_ci seq_puts(s, "none"); 50662306a36Sopenharmony_ci else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RW_CACHE) 50762306a36Sopenharmony_ci seq_puts(s, "singleclient"); /* assume only one client access */ 50862306a36Sopenharmony_ci else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RO_CACHE) 50962306a36Sopenharmony_ci seq_puts(s, "ro"); /* read only caching assumed */ 51062306a36Sopenharmony_ci else 51162306a36Sopenharmony_ci seq_puts(s, "loose"); 51262306a36Sopenharmony_ci} 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci/* 51562306a36Sopenharmony_ci * cifs_show_devname() is used so we show the mount device name with correct 51662306a36Sopenharmony_ci * format (e.g. forward slashes vs. back slashes) in /proc/mounts 51762306a36Sopenharmony_ci */ 51862306a36Sopenharmony_cistatic int cifs_show_devname(struct seq_file *m, struct dentry *root) 51962306a36Sopenharmony_ci{ 52062306a36Sopenharmony_ci struct cifs_sb_info *cifs_sb = CIFS_SB(root->d_sb); 52162306a36Sopenharmony_ci char *devname = kstrdup(cifs_sb->ctx->source, GFP_KERNEL); 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci if (devname == NULL) 52462306a36Sopenharmony_ci seq_puts(m, "none"); 52562306a36Sopenharmony_ci else { 52662306a36Sopenharmony_ci convert_delimiter(devname, '/'); 52762306a36Sopenharmony_ci /* escape all spaces in share names */ 52862306a36Sopenharmony_ci seq_escape(m, devname, " \t"); 52962306a36Sopenharmony_ci kfree(devname); 53062306a36Sopenharmony_ci } 53162306a36Sopenharmony_ci return 0; 53262306a36Sopenharmony_ci} 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci/* 53562306a36Sopenharmony_ci * cifs_show_options() is for displaying mount options in /proc/mounts. 53662306a36Sopenharmony_ci * Not all settable options are displayed but most of the important 53762306a36Sopenharmony_ci * ones are. 53862306a36Sopenharmony_ci */ 53962306a36Sopenharmony_cistatic int 54062306a36Sopenharmony_cicifs_show_options(struct seq_file *s, struct dentry *root) 54162306a36Sopenharmony_ci{ 54262306a36Sopenharmony_ci struct cifs_sb_info *cifs_sb = CIFS_SB(root->d_sb); 54362306a36Sopenharmony_ci struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); 54462306a36Sopenharmony_ci struct sockaddr *srcaddr; 54562306a36Sopenharmony_ci srcaddr = (struct sockaddr *)&tcon->ses->server->srcaddr; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci seq_show_option(s, "vers", tcon->ses->server->vals->version_string); 54862306a36Sopenharmony_ci cifs_show_security(s, tcon->ses); 54962306a36Sopenharmony_ci cifs_show_cache_flavor(s, cifs_sb); 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci if (tcon->no_lease) 55262306a36Sopenharmony_ci seq_puts(s, ",nolease"); 55362306a36Sopenharmony_ci if (cifs_sb->ctx->multiuser) 55462306a36Sopenharmony_ci seq_puts(s, ",multiuser"); 55562306a36Sopenharmony_ci else if (tcon->ses->user_name) 55662306a36Sopenharmony_ci seq_show_option(s, "username", tcon->ses->user_name); 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci if (tcon->ses->domainName && tcon->ses->domainName[0] != 0) 55962306a36Sopenharmony_ci seq_show_option(s, "domain", tcon->ses->domainName); 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci if (srcaddr->sa_family != AF_UNSPEC) { 56262306a36Sopenharmony_ci struct sockaddr_in *saddr4; 56362306a36Sopenharmony_ci struct sockaddr_in6 *saddr6; 56462306a36Sopenharmony_ci saddr4 = (struct sockaddr_in *)srcaddr; 56562306a36Sopenharmony_ci saddr6 = (struct sockaddr_in6 *)srcaddr; 56662306a36Sopenharmony_ci if (srcaddr->sa_family == AF_INET6) 56762306a36Sopenharmony_ci seq_printf(s, ",srcaddr=%pI6c", 56862306a36Sopenharmony_ci &saddr6->sin6_addr); 56962306a36Sopenharmony_ci else if (srcaddr->sa_family == AF_INET) 57062306a36Sopenharmony_ci seq_printf(s, ",srcaddr=%pI4", 57162306a36Sopenharmony_ci &saddr4->sin_addr.s_addr); 57262306a36Sopenharmony_ci else 57362306a36Sopenharmony_ci seq_printf(s, ",srcaddr=BAD-AF:%i", 57462306a36Sopenharmony_ci (int)(srcaddr->sa_family)); 57562306a36Sopenharmony_ci } 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci seq_printf(s, ",uid=%u", 57862306a36Sopenharmony_ci from_kuid_munged(&init_user_ns, cifs_sb->ctx->linux_uid)); 57962306a36Sopenharmony_ci if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) 58062306a36Sopenharmony_ci seq_puts(s, ",forceuid"); 58162306a36Sopenharmony_ci else 58262306a36Sopenharmony_ci seq_puts(s, ",noforceuid"); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci seq_printf(s, ",gid=%u", 58562306a36Sopenharmony_ci from_kgid_munged(&init_user_ns, cifs_sb->ctx->linux_gid)); 58662306a36Sopenharmony_ci if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) 58762306a36Sopenharmony_ci seq_puts(s, ",forcegid"); 58862306a36Sopenharmony_ci else 58962306a36Sopenharmony_ci seq_puts(s, ",noforcegid"); 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci cifs_show_address(s, tcon->ses->server); 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci if (!tcon->unix_ext) 59462306a36Sopenharmony_ci seq_printf(s, ",file_mode=0%ho,dir_mode=0%ho", 59562306a36Sopenharmony_ci cifs_sb->ctx->file_mode, 59662306a36Sopenharmony_ci cifs_sb->ctx->dir_mode); 59762306a36Sopenharmony_ci if (cifs_sb->ctx->iocharset) 59862306a36Sopenharmony_ci seq_printf(s, ",iocharset=%s", cifs_sb->ctx->iocharset); 59962306a36Sopenharmony_ci if (tcon->seal) 60062306a36Sopenharmony_ci seq_puts(s, ",seal"); 60162306a36Sopenharmony_ci else if (tcon->ses->server->ignore_signature) 60262306a36Sopenharmony_ci seq_puts(s, ",signloosely"); 60362306a36Sopenharmony_ci if (tcon->nocase) 60462306a36Sopenharmony_ci seq_puts(s, ",nocase"); 60562306a36Sopenharmony_ci if (tcon->nodelete) 60662306a36Sopenharmony_ci seq_puts(s, ",nodelete"); 60762306a36Sopenharmony_ci if (cifs_sb->ctx->no_sparse) 60862306a36Sopenharmony_ci seq_puts(s, ",nosparse"); 60962306a36Sopenharmony_ci if (tcon->local_lease) 61062306a36Sopenharmony_ci seq_puts(s, ",locallease"); 61162306a36Sopenharmony_ci if (tcon->retry) 61262306a36Sopenharmony_ci seq_puts(s, ",hard"); 61362306a36Sopenharmony_ci else 61462306a36Sopenharmony_ci seq_puts(s, ",soft"); 61562306a36Sopenharmony_ci if (tcon->use_persistent) 61662306a36Sopenharmony_ci seq_puts(s, ",persistenthandles"); 61762306a36Sopenharmony_ci else if (tcon->use_resilient) 61862306a36Sopenharmony_ci seq_puts(s, ",resilienthandles"); 61962306a36Sopenharmony_ci if (tcon->posix_extensions) 62062306a36Sopenharmony_ci seq_puts(s, ",posix"); 62162306a36Sopenharmony_ci else if (tcon->unix_ext) 62262306a36Sopenharmony_ci seq_puts(s, ",unix"); 62362306a36Sopenharmony_ci else 62462306a36Sopenharmony_ci seq_puts(s, ",nounix"); 62562306a36Sopenharmony_ci if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS) 62662306a36Sopenharmony_ci seq_puts(s, ",nodfs"); 62762306a36Sopenharmony_ci if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) 62862306a36Sopenharmony_ci seq_puts(s, ",posixpaths"); 62962306a36Sopenharmony_ci if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) 63062306a36Sopenharmony_ci seq_puts(s, ",setuids"); 63162306a36Sopenharmony_ci if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UID_FROM_ACL) 63262306a36Sopenharmony_ci seq_puts(s, ",idsfromsid"); 63362306a36Sopenharmony_ci if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) 63462306a36Sopenharmony_ci seq_puts(s, ",serverino"); 63562306a36Sopenharmony_ci if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD) 63662306a36Sopenharmony_ci seq_puts(s, ",rwpidforward"); 63762306a36Sopenharmony_ci if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) 63862306a36Sopenharmony_ci seq_puts(s, ",forcemand"); 63962306a36Sopenharmony_ci if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) 64062306a36Sopenharmony_ci seq_puts(s, ",nouser_xattr"); 64162306a36Sopenharmony_ci if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR) 64262306a36Sopenharmony_ci seq_puts(s, ",mapchars"); 64362306a36Sopenharmony_ci if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SFM_CHR) 64462306a36Sopenharmony_ci seq_puts(s, ",mapposix"); 64562306a36Sopenharmony_ci if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) 64662306a36Sopenharmony_ci seq_puts(s, ",sfu"); 64762306a36Sopenharmony_ci if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) 64862306a36Sopenharmony_ci seq_puts(s, ",nobrl"); 64962306a36Sopenharmony_ci if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_HANDLE_CACHE) 65062306a36Sopenharmony_ci seq_puts(s, ",nohandlecache"); 65162306a36Sopenharmony_ci if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID) 65262306a36Sopenharmony_ci seq_puts(s, ",modefromsid"); 65362306a36Sopenharmony_ci if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) 65462306a36Sopenharmony_ci seq_puts(s, ",cifsacl"); 65562306a36Sopenharmony_ci if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) 65662306a36Sopenharmony_ci seq_puts(s, ",dynperm"); 65762306a36Sopenharmony_ci if (root->d_sb->s_flags & SB_POSIXACL) 65862306a36Sopenharmony_ci seq_puts(s, ",acl"); 65962306a36Sopenharmony_ci if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) 66062306a36Sopenharmony_ci seq_puts(s, ",mfsymlinks"); 66162306a36Sopenharmony_ci if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_FSCACHE) 66262306a36Sopenharmony_ci seq_puts(s, ",fsc"); 66362306a36Sopenharmony_ci if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC) 66462306a36Sopenharmony_ci seq_puts(s, ",nostrictsync"); 66562306a36Sopenharmony_ci if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) 66662306a36Sopenharmony_ci seq_puts(s, ",noperm"); 66762306a36Sopenharmony_ci if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_BACKUPUID) 66862306a36Sopenharmony_ci seq_printf(s, ",backupuid=%u", 66962306a36Sopenharmony_ci from_kuid_munged(&init_user_ns, 67062306a36Sopenharmony_ci cifs_sb->ctx->backupuid)); 67162306a36Sopenharmony_ci if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_BACKUPGID) 67262306a36Sopenharmony_ci seq_printf(s, ",backupgid=%u", 67362306a36Sopenharmony_ci from_kgid_munged(&init_user_ns, 67462306a36Sopenharmony_ci cifs_sb->ctx->backupgid)); 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci seq_printf(s, ",rsize=%u", cifs_sb->ctx->rsize); 67762306a36Sopenharmony_ci seq_printf(s, ",wsize=%u", cifs_sb->ctx->wsize); 67862306a36Sopenharmony_ci seq_printf(s, ",bsize=%u", cifs_sb->ctx->bsize); 67962306a36Sopenharmony_ci if (cifs_sb->ctx->rasize) 68062306a36Sopenharmony_ci seq_printf(s, ",rasize=%u", cifs_sb->ctx->rasize); 68162306a36Sopenharmony_ci if (tcon->ses->server->min_offload) 68262306a36Sopenharmony_ci seq_printf(s, ",esize=%u", tcon->ses->server->min_offload); 68362306a36Sopenharmony_ci seq_printf(s, ",echo_interval=%lu", 68462306a36Sopenharmony_ci tcon->ses->server->echo_interval / HZ); 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci /* Only display the following if overridden on mount */ 68762306a36Sopenharmony_ci if (tcon->ses->server->max_credits != SMB2_MAX_CREDITS_AVAILABLE) 68862306a36Sopenharmony_ci seq_printf(s, ",max_credits=%u", tcon->ses->server->max_credits); 68962306a36Sopenharmony_ci if (tcon->ses->server->tcp_nodelay) 69062306a36Sopenharmony_ci seq_puts(s, ",tcpnodelay"); 69162306a36Sopenharmony_ci if (tcon->ses->server->noautotune) 69262306a36Sopenharmony_ci seq_puts(s, ",noautotune"); 69362306a36Sopenharmony_ci if (tcon->ses->server->noblocksnd) 69462306a36Sopenharmony_ci seq_puts(s, ",noblocksend"); 69562306a36Sopenharmony_ci if (tcon->ses->server->nosharesock) 69662306a36Sopenharmony_ci seq_puts(s, ",nosharesock"); 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci if (tcon->snapshot_time) 69962306a36Sopenharmony_ci seq_printf(s, ",snapshot=%llu", tcon->snapshot_time); 70062306a36Sopenharmony_ci if (tcon->handle_timeout) 70162306a36Sopenharmony_ci seq_printf(s, ",handletimeout=%u", tcon->handle_timeout); 70262306a36Sopenharmony_ci if (tcon->max_cached_dirs != MAX_CACHED_FIDS) 70362306a36Sopenharmony_ci seq_printf(s, ",max_cached_dirs=%u", tcon->max_cached_dirs); 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci /* 70662306a36Sopenharmony_ci * Display file and directory attribute timeout in seconds. 70762306a36Sopenharmony_ci * If file and directory attribute timeout the same then actimeo 70862306a36Sopenharmony_ci * was likely specified on mount 70962306a36Sopenharmony_ci */ 71062306a36Sopenharmony_ci if (cifs_sb->ctx->acdirmax == cifs_sb->ctx->acregmax) 71162306a36Sopenharmony_ci seq_printf(s, ",actimeo=%lu", cifs_sb->ctx->acregmax / HZ); 71262306a36Sopenharmony_ci else { 71362306a36Sopenharmony_ci seq_printf(s, ",acdirmax=%lu", cifs_sb->ctx->acdirmax / HZ); 71462306a36Sopenharmony_ci seq_printf(s, ",acregmax=%lu", cifs_sb->ctx->acregmax / HZ); 71562306a36Sopenharmony_ci } 71662306a36Sopenharmony_ci seq_printf(s, ",closetimeo=%lu", cifs_sb->ctx->closetimeo / HZ); 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci if (tcon->ses->chan_max > 1) 71962306a36Sopenharmony_ci seq_printf(s, ",multichannel,max_channels=%zu", 72062306a36Sopenharmony_ci tcon->ses->chan_max); 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci if (tcon->use_witness) 72362306a36Sopenharmony_ci seq_puts(s, ",witness"); 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci return 0; 72662306a36Sopenharmony_ci} 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_cistatic void cifs_umount_begin(struct super_block *sb) 72962306a36Sopenharmony_ci{ 73062306a36Sopenharmony_ci struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 73162306a36Sopenharmony_ci struct cifs_tcon *tcon; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci if (cifs_sb == NULL) 73462306a36Sopenharmony_ci return; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci tcon = cifs_sb_master_tcon(cifs_sb); 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci spin_lock(&cifs_tcp_ses_lock); 73962306a36Sopenharmony_ci spin_lock(&tcon->tc_lock); 74062306a36Sopenharmony_ci if ((tcon->tc_count > 1) || (tcon->status == TID_EXITING)) { 74162306a36Sopenharmony_ci /* we have other mounts to same share or we have 74262306a36Sopenharmony_ci already tried to umount this and woken up 74362306a36Sopenharmony_ci all waiting network requests, nothing to do */ 74462306a36Sopenharmony_ci spin_unlock(&tcon->tc_lock); 74562306a36Sopenharmony_ci spin_unlock(&cifs_tcp_ses_lock); 74662306a36Sopenharmony_ci return; 74762306a36Sopenharmony_ci } 74862306a36Sopenharmony_ci /* 74962306a36Sopenharmony_ci * can not set tcon->status to TID_EXITING yet since we don't know if umount -f will 75062306a36Sopenharmony_ci * fail later (e.g. due to open files). TID_EXITING will be set just before tdis req sent 75162306a36Sopenharmony_ci */ 75262306a36Sopenharmony_ci spin_unlock(&tcon->tc_lock); 75362306a36Sopenharmony_ci spin_unlock(&cifs_tcp_ses_lock); 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci cifs_close_all_deferred_files(tcon); 75662306a36Sopenharmony_ci /* cancel_brl_requests(tcon); */ /* BB mark all brl mids as exiting */ 75762306a36Sopenharmony_ci /* cancel_notify_requests(tcon); */ 75862306a36Sopenharmony_ci if (tcon->ses && tcon->ses->server) { 75962306a36Sopenharmony_ci cifs_dbg(FYI, "wake up tasks now - umount begin not complete\n"); 76062306a36Sopenharmony_ci wake_up_all(&tcon->ses->server->request_q); 76162306a36Sopenharmony_ci wake_up_all(&tcon->ses->server->response_q); 76262306a36Sopenharmony_ci msleep(1); /* yield */ 76362306a36Sopenharmony_ci /* we have to kick the requests once more */ 76462306a36Sopenharmony_ci wake_up_all(&tcon->ses->server->response_q); 76562306a36Sopenharmony_ci msleep(1); 76662306a36Sopenharmony_ci } 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci return; 76962306a36Sopenharmony_ci} 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_cistatic int cifs_freeze(struct super_block *sb) 77262306a36Sopenharmony_ci{ 77362306a36Sopenharmony_ci struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 77462306a36Sopenharmony_ci struct cifs_tcon *tcon; 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci if (cifs_sb == NULL) 77762306a36Sopenharmony_ci return 0; 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci tcon = cifs_sb_master_tcon(cifs_sb); 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci cifs_close_all_deferred_files(tcon); 78262306a36Sopenharmony_ci return 0; 78362306a36Sopenharmony_ci} 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci#ifdef CONFIG_CIFS_STATS2 78662306a36Sopenharmony_cistatic int cifs_show_stats(struct seq_file *s, struct dentry *root) 78762306a36Sopenharmony_ci{ 78862306a36Sopenharmony_ci /* BB FIXME */ 78962306a36Sopenharmony_ci return 0; 79062306a36Sopenharmony_ci} 79162306a36Sopenharmony_ci#endif 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_cistatic int cifs_write_inode(struct inode *inode, struct writeback_control *wbc) 79462306a36Sopenharmony_ci{ 79562306a36Sopenharmony_ci fscache_unpin_writeback(wbc, cifs_inode_cookie(inode)); 79662306a36Sopenharmony_ci return 0; 79762306a36Sopenharmony_ci} 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_cistatic int cifs_drop_inode(struct inode *inode) 80062306a36Sopenharmony_ci{ 80162306a36Sopenharmony_ci struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci /* no serverino => unconditional eviction */ 80462306a36Sopenharmony_ci return !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) || 80562306a36Sopenharmony_ci generic_drop_inode(inode); 80662306a36Sopenharmony_ci} 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_cistatic const struct super_operations cifs_super_ops = { 80962306a36Sopenharmony_ci .statfs = cifs_statfs, 81062306a36Sopenharmony_ci .alloc_inode = cifs_alloc_inode, 81162306a36Sopenharmony_ci .write_inode = cifs_write_inode, 81262306a36Sopenharmony_ci .free_inode = cifs_free_inode, 81362306a36Sopenharmony_ci .drop_inode = cifs_drop_inode, 81462306a36Sopenharmony_ci .evict_inode = cifs_evict_inode, 81562306a36Sopenharmony_ci/* .show_path = cifs_show_path, */ /* Would we ever need show path? */ 81662306a36Sopenharmony_ci .show_devname = cifs_show_devname, 81762306a36Sopenharmony_ci/* .delete_inode = cifs_delete_inode, */ /* Do not need above 81862306a36Sopenharmony_ci function unless later we add lazy close of inodes or unless the 81962306a36Sopenharmony_ci kernel forgets to call us with the same number of releases (closes) 82062306a36Sopenharmony_ci as opens */ 82162306a36Sopenharmony_ci .show_options = cifs_show_options, 82262306a36Sopenharmony_ci .umount_begin = cifs_umount_begin, 82362306a36Sopenharmony_ci .freeze_fs = cifs_freeze, 82462306a36Sopenharmony_ci#ifdef CONFIG_CIFS_STATS2 82562306a36Sopenharmony_ci .show_stats = cifs_show_stats, 82662306a36Sopenharmony_ci#endif 82762306a36Sopenharmony_ci}; 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci/* 83062306a36Sopenharmony_ci * Get root dentry from superblock according to prefix path mount option. 83162306a36Sopenharmony_ci * Return dentry with refcount + 1 on success and NULL otherwise. 83262306a36Sopenharmony_ci */ 83362306a36Sopenharmony_cistatic struct dentry * 83462306a36Sopenharmony_cicifs_get_root(struct smb3_fs_context *ctx, struct super_block *sb) 83562306a36Sopenharmony_ci{ 83662306a36Sopenharmony_ci struct dentry *dentry; 83762306a36Sopenharmony_ci struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 83862306a36Sopenharmony_ci char *full_path = NULL; 83962306a36Sopenharmony_ci char *s, *p; 84062306a36Sopenharmony_ci char sep; 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH) 84362306a36Sopenharmony_ci return dget(sb->s_root); 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci full_path = cifs_build_path_to_root(ctx, cifs_sb, 84662306a36Sopenharmony_ci cifs_sb_master_tcon(cifs_sb), 0); 84762306a36Sopenharmony_ci if (full_path == NULL) 84862306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci cifs_dbg(FYI, "Get root dentry for %s\n", full_path); 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci sep = CIFS_DIR_SEP(cifs_sb); 85362306a36Sopenharmony_ci dentry = dget(sb->s_root); 85462306a36Sopenharmony_ci s = full_path; 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci do { 85762306a36Sopenharmony_ci struct inode *dir = d_inode(dentry); 85862306a36Sopenharmony_ci struct dentry *child; 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci if (!S_ISDIR(dir->i_mode)) { 86162306a36Sopenharmony_ci dput(dentry); 86262306a36Sopenharmony_ci dentry = ERR_PTR(-ENOTDIR); 86362306a36Sopenharmony_ci break; 86462306a36Sopenharmony_ci } 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci /* skip separators */ 86762306a36Sopenharmony_ci while (*s == sep) 86862306a36Sopenharmony_ci s++; 86962306a36Sopenharmony_ci if (!*s) 87062306a36Sopenharmony_ci break; 87162306a36Sopenharmony_ci p = s++; 87262306a36Sopenharmony_ci /* next separator */ 87362306a36Sopenharmony_ci while (*s && *s != sep) 87462306a36Sopenharmony_ci s++; 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci child = lookup_positive_unlocked(p, dentry, s - p); 87762306a36Sopenharmony_ci dput(dentry); 87862306a36Sopenharmony_ci dentry = child; 87962306a36Sopenharmony_ci } while (!IS_ERR(dentry)); 88062306a36Sopenharmony_ci kfree(full_path); 88162306a36Sopenharmony_ci return dentry; 88262306a36Sopenharmony_ci} 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_cistatic int cifs_set_super(struct super_block *sb, void *data) 88562306a36Sopenharmony_ci{ 88662306a36Sopenharmony_ci struct cifs_mnt_data *mnt_data = data; 88762306a36Sopenharmony_ci sb->s_fs_info = mnt_data->cifs_sb; 88862306a36Sopenharmony_ci return set_anon_super(sb, NULL); 88962306a36Sopenharmony_ci} 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_cistruct dentry * 89262306a36Sopenharmony_cicifs_smb3_do_mount(struct file_system_type *fs_type, 89362306a36Sopenharmony_ci int flags, struct smb3_fs_context *old_ctx) 89462306a36Sopenharmony_ci{ 89562306a36Sopenharmony_ci struct cifs_mnt_data mnt_data; 89662306a36Sopenharmony_ci struct cifs_sb_info *cifs_sb; 89762306a36Sopenharmony_ci struct super_block *sb; 89862306a36Sopenharmony_ci struct dentry *root; 89962306a36Sopenharmony_ci int rc; 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci if (cifsFYI) { 90262306a36Sopenharmony_ci cifs_dbg(FYI, "%s: devname=%s flags=0x%x\n", __func__, 90362306a36Sopenharmony_ci old_ctx->source, flags); 90462306a36Sopenharmony_ci } else { 90562306a36Sopenharmony_ci cifs_info("Attempting to mount %s\n", old_ctx->source); 90662306a36Sopenharmony_ci } 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci cifs_sb = kzalloc(sizeof(*cifs_sb), GFP_KERNEL); 90962306a36Sopenharmony_ci if (!cifs_sb) 91062306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci cifs_sb->ctx = kzalloc(sizeof(struct smb3_fs_context), GFP_KERNEL); 91362306a36Sopenharmony_ci if (!cifs_sb->ctx) { 91462306a36Sopenharmony_ci root = ERR_PTR(-ENOMEM); 91562306a36Sopenharmony_ci goto out; 91662306a36Sopenharmony_ci } 91762306a36Sopenharmony_ci rc = smb3_fs_context_dup(cifs_sb->ctx, old_ctx); 91862306a36Sopenharmony_ci if (rc) { 91962306a36Sopenharmony_ci root = ERR_PTR(rc); 92062306a36Sopenharmony_ci goto out; 92162306a36Sopenharmony_ci } 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci rc = cifs_setup_cifs_sb(cifs_sb); 92462306a36Sopenharmony_ci if (rc) { 92562306a36Sopenharmony_ci root = ERR_PTR(rc); 92662306a36Sopenharmony_ci goto out; 92762306a36Sopenharmony_ci } 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci rc = cifs_mount(cifs_sb, cifs_sb->ctx); 93062306a36Sopenharmony_ci if (rc) { 93162306a36Sopenharmony_ci if (!(flags & SB_SILENT)) 93262306a36Sopenharmony_ci cifs_dbg(VFS, "cifs_mount failed w/return code = %d\n", 93362306a36Sopenharmony_ci rc); 93462306a36Sopenharmony_ci root = ERR_PTR(rc); 93562306a36Sopenharmony_ci goto out; 93662306a36Sopenharmony_ci } 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci mnt_data.ctx = cifs_sb->ctx; 93962306a36Sopenharmony_ci mnt_data.cifs_sb = cifs_sb; 94062306a36Sopenharmony_ci mnt_data.flags = flags; 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci /* BB should we make this contingent on mount parm? */ 94362306a36Sopenharmony_ci flags |= SB_NODIRATIME | SB_NOATIME; 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci sb = sget(fs_type, cifs_match_super, cifs_set_super, flags, &mnt_data); 94662306a36Sopenharmony_ci if (IS_ERR(sb)) { 94762306a36Sopenharmony_ci cifs_umount(cifs_sb); 94862306a36Sopenharmony_ci return ERR_CAST(sb); 94962306a36Sopenharmony_ci } 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci if (sb->s_root) { 95262306a36Sopenharmony_ci cifs_dbg(FYI, "Use existing superblock\n"); 95362306a36Sopenharmony_ci cifs_umount(cifs_sb); 95462306a36Sopenharmony_ci cifs_sb = NULL; 95562306a36Sopenharmony_ci } else { 95662306a36Sopenharmony_ci rc = cifs_read_super(sb); 95762306a36Sopenharmony_ci if (rc) { 95862306a36Sopenharmony_ci root = ERR_PTR(rc); 95962306a36Sopenharmony_ci goto out_super; 96062306a36Sopenharmony_ci } 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci sb->s_flags |= SB_ACTIVE; 96362306a36Sopenharmony_ci } 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci root = cifs_get_root(cifs_sb ? cifs_sb->ctx : old_ctx, sb); 96662306a36Sopenharmony_ci if (IS_ERR(root)) 96762306a36Sopenharmony_ci goto out_super; 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci if (cifs_sb) 97062306a36Sopenharmony_ci cifs_sb->root = dget(root); 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci cifs_dbg(FYI, "dentry root is: %p\n", root); 97362306a36Sopenharmony_ci return root; 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ciout_super: 97662306a36Sopenharmony_ci deactivate_locked_super(sb); 97762306a36Sopenharmony_ci return root; 97862306a36Sopenharmony_ciout: 97962306a36Sopenharmony_ci kfree(cifs_sb->prepath); 98062306a36Sopenharmony_ci smb3_cleanup_fs_context(cifs_sb->ctx); 98162306a36Sopenharmony_ci kfree(cifs_sb); 98262306a36Sopenharmony_ci return root; 98362306a36Sopenharmony_ci} 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_cistatic ssize_t 98762306a36Sopenharmony_cicifs_loose_read_iter(struct kiocb *iocb, struct iov_iter *iter) 98862306a36Sopenharmony_ci{ 98962306a36Sopenharmony_ci ssize_t rc; 99062306a36Sopenharmony_ci struct inode *inode = file_inode(iocb->ki_filp); 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci if (iocb->ki_flags & IOCB_DIRECT) 99362306a36Sopenharmony_ci return cifs_user_readv(iocb, iter); 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci rc = cifs_revalidate_mapping(inode); 99662306a36Sopenharmony_ci if (rc) 99762306a36Sopenharmony_ci return rc; 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci return generic_file_read_iter(iocb, iter); 100062306a36Sopenharmony_ci} 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_cistatic ssize_t cifs_file_write_iter(struct kiocb *iocb, struct iov_iter *from) 100362306a36Sopenharmony_ci{ 100462306a36Sopenharmony_ci struct inode *inode = file_inode(iocb->ki_filp); 100562306a36Sopenharmony_ci struct cifsInodeInfo *cinode = CIFS_I(inode); 100662306a36Sopenharmony_ci ssize_t written; 100762306a36Sopenharmony_ci int rc; 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci if (iocb->ki_filp->f_flags & O_DIRECT) { 101062306a36Sopenharmony_ci written = cifs_user_writev(iocb, from); 101162306a36Sopenharmony_ci if (written > 0 && CIFS_CACHE_READ(cinode)) { 101262306a36Sopenharmony_ci cifs_zap_mapping(inode); 101362306a36Sopenharmony_ci cifs_dbg(FYI, 101462306a36Sopenharmony_ci "Set no oplock for inode=%p after a write operation\n", 101562306a36Sopenharmony_ci inode); 101662306a36Sopenharmony_ci cinode->oplock = 0; 101762306a36Sopenharmony_ci } 101862306a36Sopenharmony_ci return written; 101962306a36Sopenharmony_ci } 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci written = cifs_get_writer(cinode); 102262306a36Sopenharmony_ci if (written) 102362306a36Sopenharmony_ci return written; 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci written = generic_file_write_iter(iocb, from); 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci if (CIFS_CACHE_WRITE(CIFS_I(inode))) 102862306a36Sopenharmony_ci goto out; 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci rc = filemap_fdatawrite(inode->i_mapping); 103162306a36Sopenharmony_ci if (rc) 103262306a36Sopenharmony_ci cifs_dbg(FYI, "cifs_file_write_iter: %d rc on %p inode\n", 103362306a36Sopenharmony_ci rc, inode); 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ciout: 103662306a36Sopenharmony_ci cifs_put_writer(cinode); 103762306a36Sopenharmony_ci return written; 103862306a36Sopenharmony_ci} 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_cistatic loff_t cifs_llseek(struct file *file, loff_t offset, int whence) 104162306a36Sopenharmony_ci{ 104262306a36Sopenharmony_ci struct cifsFileInfo *cfile = file->private_data; 104362306a36Sopenharmony_ci struct cifs_tcon *tcon; 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci /* 104662306a36Sopenharmony_ci * whence == SEEK_END || SEEK_DATA || SEEK_HOLE => we must revalidate 104762306a36Sopenharmony_ci * the cached file length 104862306a36Sopenharmony_ci */ 104962306a36Sopenharmony_ci if (whence != SEEK_SET && whence != SEEK_CUR) { 105062306a36Sopenharmony_ci int rc; 105162306a36Sopenharmony_ci struct inode *inode = file_inode(file); 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci /* 105462306a36Sopenharmony_ci * We need to be sure that all dirty pages are written and the 105562306a36Sopenharmony_ci * server has the newest file length. 105662306a36Sopenharmony_ci */ 105762306a36Sopenharmony_ci if (!CIFS_CACHE_READ(CIFS_I(inode)) && inode->i_mapping && 105862306a36Sopenharmony_ci inode->i_mapping->nrpages != 0) { 105962306a36Sopenharmony_ci rc = filemap_fdatawait(inode->i_mapping); 106062306a36Sopenharmony_ci if (rc) { 106162306a36Sopenharmony_ci mapping_set_error(inode->i_mapping, rc); 106262306a36Sopenharmony_ci return rc; 106362306a36Sopenharmony_ci } 106462306a36Sopenharmony_ci } 106562306a36Sopenharmony_ci /* 106662306a36Sopenharmony_ci * Some applications poll for the file length in this strange 106762306a36Sopenharmony_ci * way so we must seek to end on non-oplocked files by 106862306a36Sopenharmony_ci * setting the revalidate time to zero. 106962306a36Sopenharmony_ci */ 107062306a36Sopenharmony_ci CIFS_I(inode)->time = 0; 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci rc = cifs_revalidate_file_attr(file); 107362306a36Sopenharmony_ci if (rc < 0) 107462306a36Sopenharmony_ci return (loff_t)rc; 107562306a36Sopenharmony_ci } 107662306a36Sopenharmony_ci if (cfile && cfile->tlink) { 107762306a36Sopenharmony_ci tcon = tlink_tcon(cfile->tlink); 107862306a36Sopenharmony_ci if (tcon->ses->server->ops->llseek) 107962306a36Sopenharmony_ci return tcon->ses->server->ops->llseek(file, tcon, 108062306a36Sopenharmony_ci offset, whence); 108162306a36Sopenharmony_ci } 108262306a36Sopenharmony_ci return generic_file_llseek(file, offset, whence); 108362306a36Sopenharmony_ci} 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_cistatic int 108662306a36Sopenharmony_cicifs_setlease(struct file *file, int arg, struct file_lock **lease, void **priv) 108762306a36Sopenharmony_ci{ 108862306a36Sopenharmony_ci /* 108962306a36Sopenharmony_ci * Note that this is called by vfs setlease with i_lock held to 109062306a36Sopenharmony_ci * protect *lease from going away. 109162306a36Sopenharmony_ci */ 109262306a36Sopenharmony_ci struct inode *inode = file_inode(file); 109362306a36Sopenharmony_ci struct cifsFileInfo *cfile = file->private_data; 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci if (!(S_ISREG(inode->i_mode))) 109662306a36Sopenharmony_ci return -EINVAL; 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci /* Check if file is oplocked if this is request for new lease */ 109962306a36Sopenharmony_ci if (arg == F_UNLCK || 110062306a36Sopenharmony_ci ((arg == F_RDLCK) && CIFS_CACHE_READ(CIFS_I(inode))) || 110162306a36Sopenharmony_ci ((arg == F_WRLCK) && CIFS_CACHE_WRITE(CIFS_I(inode)))) 110262306a36Sopenharmony_ci return generic_setlease(file, arg, lease, priv); 110362306a36Sopenharmony_ci else if (tlink_tcon(cfile->tlink)->local_lease && 110462306a36Sopenharmony_ci !CIFS_CACHE_READ(CIFS_I(inode))) 110562306a36Sopenharmony_ci /* 110662306a36Sopenharmony_ci * If the server claims to support oplock on this file, then we 110762306a36Sopenharmony_ci * still need to check oplock even if the local_lease mount 110862306a36Sopenharmony_ci * option is set, but there are servers which do not support 110962306a36Sopenharmony_ci * oplock for which this mount option may be useful if the user 111062306a36Sopenharmony_ci * knows that the file won't be changed on the server by anyone 111162306a36Sopenharmony_ci * else. 111262306a36Sopenharmony_ci */ 111362306a36Sopenharmony_ci return generic_setlease(file, arg, lease, priv); 111462306a36Sopenharmony_ci else 111562306a36Sopenharmony_ci return -EAGAIN; 111662306a36Sopenharmony_ci} 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_cistruct file_system_type cifs_fs_type = { 111962306a36Sopenharmony_ci .owner = THIS_MODULE, 112062306a36Sopenharmony_ci .name = "cifs", 112162306a36Sopenharmony_ci .init_fs_context = smb3_init_fs_context, 112262306a36Sopenharmony_ci .parameters = smb3_fs_parameters, 112362306a36Sopenharmony_ci .kill_sb = cifs_kill_sb, 112462306a36Sopenharmony_ci .fs_flags = FS_RENAME_DOES_D_MOVE, 112562306a36Sopenharmony_ci}; 112662306a36Sopenharmony_ciMODULE_ALIAS_FS("cifs"); 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_cistruct file_system_type smb3_fs_type = { 112962306a36Sopenharmony_ci .owner = THIS_MODULE, 113062306a36Sopenharmony_ci .name = "smb3", 113162306a36Sopenharmony_ci .init_fs_context = smb3_init_fs_context, 113262306a36Sopenharmony_ci .parameters = smb3_fs_parameters, 113362306a36Sopenharmony_ci .kill_sb = cifs_kill_sb, 113462306a36Sopenharmony_ci .fs_flags = FS_RENAME_DOES_D_MOVE, 113562306a36Sopenharmony_ci}; 113662306a36Sopenharmony_ciMODULE_ALIAS_FS("smb3"); 113762306a36Sopenharmony_ciMODULE_ALIAS("smb3"); 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ciconst struct inode_operations cifs_dir_inode_ops = { 114062306a36Sopenharmony_ci .create = cifs_create, 114162306a36Sopenharmony_ci .atomic_open = cifs_atomic_open, 114262306a36Sopenharmony_ci .lookup = cifs_lookup, 114362306a36Sopenharmony_ci .getattr = cifs_getattr, 114462306a36Sopenharmony_ci .unlink = cifs_unlink, 114562306a36Sopenharmony_ci .link = cifs_hardlink, 114662306a36Sopenharmony_ci .mkdir = cifs_mkdir, 114762306a36Sopenharmony_ci .rmdir = cifs_rmdir, 114862306a36Sopenharmony_ci .rename = cifs_rename2, 114962306a36Sopenharmony_ci .permission = cifs_permission, 115062306a36Sopenharmony_ci .setattr = cifs_setattr, 115162306a36Sopenharmony_ci .symlink = cifs_symlink, 115262306a36Sopenharmony_ci .mknod = cifs_mknod, 115362306a36Sopenharmony_ci .listxattr = cifs_listxattr, 115462306a36Sopenharmony_ci .get_acl = cifs_get_acl, 115562306a36Sopenharmony_ci .set_acl = cifs_set_acl, 115662306a36Sopenharmony_ci}; 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ciconst struct inode_operations cifs_file_inode_ops = { 115962306a36Sopenharmony_ci .setattr = cifs_setattr, 116062306a36Sopenharmony_ci .getattr = cifs_getattr, 116162306a36Sopenharmony_ci .permission = cifs_permission, 116262306a36Sopenharmony_ci .listxattr = cifs_listxattr, 116362306a36Sopenharmony_ci .fiemap = cifs_fiemap, 116462306a36Sopenharmony_ci .get_acl = cifs_get_acl, 116562306a36Sopenharmony_ci .set_acl = cifs_set_acl, 116662306a36Sopenharmony_ci}; 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ciconst char *cifs_get_link(struct dentry *dentry, struct inode *inode, 116962306a36Sopenharmony_ci struct delayed_call *done) 117062306a36Sopenharmony_ci{ 117162306a36Sopenharmony_ci char *target_path; 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci target_path = kmalloc(PATH_MAX, GFP_KERNEL); 117462306a36Sopenharmony_ci if (!target_path) 117562306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci spin_lock(&inode->i_lock); 117862306a36Sopenharmony_ci if (likely(CIFS_I(inode)->symlink_target)) { 117962306a36Sopenharmony_ci strscpy(target_path, CIFS_I(inode)->symlink_target, PATH_MAX); 118062306a36Sopenharmony_ci } else { 118162306a36Sopenharmony_ci kfree(target_path); 118262306a36Sopenharmony_ci target_path = ERR_PTR(-EOPNOTSUPP); 118362306a36Sopenharmony_ci } 118462306a36Sopenharmony_ci spin_unlock(&inode->i_lock); 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci if (!IS_ERR(target_path)) 118762306a36Sopenharmony_ci set_delayed_call(done, kfree_link, target_path); 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci return target_path; 119062306a36Sopenharmony_ci} 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ciconst struct inode_operations cifs_symlink_inode_ops = { 119362306a36Sopenharmony_ci .get_link = cifs_get_link, 119462306a36Sopenharmony_ci .setattr = cifs_setattr, 119562306a36Sopenharmony_ci .permission = cifs_permission, 119662306a36Sopenharmony_ci .listxattr = cifs_listxattr, 119762306a36Sopenharmony_ci}; 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci/* 120062306a36Sopenharmony_ci * Advance the EOF marker to after the source range. 120162306a36Sopenharmony_ci */ 120262306a36Sopenharmony_cistatic int cifs_precopy_set_eof(struct inode *src_inode, struct cifsInodeInfo *src_cifsi, 120362306a36Sopenharmony_ci struct cifs_tcon *src_tcon, 120462306a36Sopenharmony_ci unsigned int xid, loff_t src_end) 120562306a36Sopenharmony_ci{ 120662306a36Sopenharmony_ci struct cifsFileInfo *writeable_srcfile; 120762306a36Sopenharmony_ci int rc = -EINVAL; 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci writeable_srcfile = find_writable_file(src_cifsi, FIND_WR_FSUID_ONLY); 121062306a36Sopenharmony_ci if (writeable_srcfile) { 121162306a36Sopenharmony_ci if (src_tcon->ses->server->ops->set_file_size) 121262306a36Sopenharmony_ci rc = src_tcon->ses->server->ops->set_file_size( 121362306a36Sopenharmony_ci xid, src_tcon, writeable_srcfile, 121462306a36Sopenharmony_ci src_inode->i_size, true /* no need to set sparse */); 121562306a36Sopenharmony_ci else 121662306a36Sopenharmony_ci rc = -ENOSYS; 121762306a36Sopenharmony_ci cifsFileInfo_put(writeable_srcfile); 121862306a36Sopenharmony_ci cifs_dbg(FYI, "SetFSize for copychunk rc = %d\n", rc); 121962306a36Sopenharmony_ci } 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci if (rc < 0) 122262306a36Sopenharmony_ci goto set_failed; 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci netfs_resize_file(&src_cifsi->netfs, src_end); 122562306a36Sopenharmony_ci fscache_resize_cookie(cifs_inode_cookie(src_inode), src_end); 122662306a36Sopenharmony_ci return 0; 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ciset_failed: 122962306a36Sopenharmony_ci return filemap_write_and_wait(src_inode->i_mapping); 123062306a36Sopenharmony_ci} 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci/* 123362306a36Sopenharmony_ci * Flush out either the folio that overlaps the beginning of a range in which 123462306a36Sopenharmony_ci * pos resides or the folio that overlaps the end of a range unless that folio 123562306a36Sopenharmony_ci * is entirely within the range we're going to invalidate. We extend the flush 123662306a36Sopenharmony_ci * bounds to encompass the folio. 123762306a36Sopenharmony_ci */ 123862306a36Sopenharmony_cistatic int cifs_flush_folio(struct inode *inode, loff_t pos, loff_t *_fstart, loff_t *_fend, 123962306a36Sopenharmony_ci bool first) 124062306a36Sopenharmony_ci{ 124162306a36Sopenharmony_ci struct folio *folio; 124262306a36Sopenharmony_ci unsigned long long fpos, fend; 124362306a36Sopenharmony_ci pgoff_t index = pos / PAGE_SIZE; 124462306a36Sopenharmony_ci size_t size; 124562306a36Sopenharmony_ci int rc = 0; 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci folio = filemap_get_folio(inode->i_mapping, index); 124862306a36Sopenharmony_ci if (IS_ERR(folio)) 124962306a36Sopenharmony_ci return 0; 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_ci size = folio_size(folio); 125262306a36Sopenharmony_ci fpos = folio_pos(folio); 125362306a36Sopenharmony_ci fend = fpos + size - 1; 125462306a36Sopenharmony_ci *_fstart = min_t(unsigned long long, *_fstart, fpos); 125562306a36Sopenharmony_ci *_fend = max_t(unsigned long long, *_fend, fend); 125662306a36Sopenharmony_ci if ((first && pos == fpos) || (!first && pos == fend)) 125762306a36Sopenharmony_ci goto out; 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci rc = filemap_write_and_wait_range(inode->i_mapping, fpos, fend); 126062306a36Sopenharmony_ciout: 126162306a36Sopenharmony_ci folio_put(folio); 126262306a36Sopenharmony_ci return rc; 126362306a36Sopenharmony_ci} 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_cistatic loff_t cifs_remap_file_range(struct file *src_file, loff_t off, 126662306a36Sopenharmony_ci struct file *dst_file, loff_t destoff, loff_t len, 126762306a36Sopenharmony_ci unsigned int remap_flags) 126862306a36Sopenharmony_ci{ 126962306a36Sopenharmony_ci struct inode *src_inode = file_inode(src_file); 127062306a36Sopenharmony_ci struct inode *target_inode = file_inode(dst_file); 127162306a36Sopenharmony_ci struct cifsInodeInfo *src_cifsi = CIFS_I(src_inode); 127262306a36Sopenharmony_ci struct cifsInodeInfo *target_cifsi = CIFS_I(target_inode); 127362306a36Sopenharmony_ci struct cifsFileInfo *smb_file_src = src_file->private_data; 127462306a36Sopenharmony_ci struct cifsFileInfo *smb_file_target = dst_file->private_data; 127562306a36Sopenharmony_ci struct cifs_tcon *target_tcon, *src_tcon; 127662306a36Sopenharmony_ci unsigned long long destend, fstart, fend, new_size; 127762306a36Sopenharmony_ci unsigned int xid; 127862306a36Sopenharmony_ci int rc; 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci if (remap_flags & REMAP_FILE_DEDUP) 128162306a36Sopenharmony_ci return -EOPNOTSUPP; 128262306a36Sopenharmony_ci if (remap_flags & ~REMAP_FILE_ADVISORY) 128362306a36Sopenharmony_ci return -EINVAL; 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci cifs_dbg(FYI, "clone range\n"); 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci xid = get_xid(); 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci if (!smb_file_src || !smb_file_target) { 129062306a36Sopenharmony_ci rc = -EBADF; 129162306a36Sopenharmony_ci cifs_dbg(VFS, "missing cifsFileInfo on copy range src file\n"); 129262306a36Sopenharmony_ci goto out; 129362306a36Sopenharmony_ci } 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci src_tcon = tlink_tcon(smb_file_src->tlink); 129662306a36Sopenharmony_ci target_tcon = tlink_tcon(smb_file_target->tlink); 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci /* 129962306a36Sopenharmony_ci * Note: cifs case is easier than btrfs since server responsible for 130062306a36Sopenharmony_ci * checks for proper open modes and file type and if it wants 130162306a36Sopenharmony_ci * server could even support copy of range where source = target 130262306a36Sopenharmony_ci */ 130362306a36Sopenharmony_ci lock_two_nondirectories(target_inode, src_inode); 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_ci if (len == 0) 130662306a36Sopenharmony_ci len = src_inode->i_size - off; 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci cifs_dbg(FYI, "clone range\n"); 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_ci /* Flush the source buffer */ 131162306a36Sopenharmony_ci rc = filemap_write_and_wait_range(src_inode->i_mapping, off, 131262306a36Sopenharmony_ci off + len - 1); 131362306a36Sopenharmony_ci if (rc) 131462306a36Sopenharmony_ci goto unlock; 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci /* The server-side copy will fail if the source crosses the EOF marker. 131762306a36Sopenharmony_ci * Advance the EOF marker after the flush above to the end of the range 131862306a36Sopenharmony_ci * if it's short of that. 131962306a36Sopenharmony_ci */ 132062306a36Sopenharmony_ci if (src_cifsi->netfs.remote_i_size < off + len) { 132162306a36Sopenharmony_ci rc = cifs_precopy_set_eof(src_inode, src_cifsi, src_tcon, xid, off + len); 132262306a36Sopenharmony_ci if (rc < 0) 132362306a36Sopenharmony_ci goto unlock; 132462306a36Sopenharmony_ci } 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci new_size = destoff + len; 132762306a36Sopenharmony_ci destend = destoff + len - 1; 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci /* Flush the folios at either end of the destination range to prevent 133062306a36Sopenharmony_ci * accidental loss of dirty data outside of the range. 133162306a36Sopenharmony_ci */ 133262306a36Sopenharmony_ci fstart = destoff; 133362306a36Sopenharmony_ci fend = destend; 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci rc = cifs_flush_folio(target_inode, destoff, &fstart, &fend, true); 133662306a36Sopenharmony_ci if (rc) 133762306a36Sopenharmony_ci goto unlock; 133862306a36Sopenharmony_ci rc = cifs_flush_folio(target_inode, destend, &fstart, &fend, false); 133962306a36Sopenharmony_ci if (rc) 134062306a36Sopenharmony_ci goto unlock; 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci /* Discard all the folios that overlap the destination region. */ 134362306a36Sopenharmony_ci cifs_dbg(FYI, "about to discard pages %llx-%llx\n", fstart, fend); 134462306a36Sopenharmony_ci truncate_inode_pages_range(&target_inode->i_data, fstart, fend); 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ci fscache_invalidate(cifs_inode_cookie(target_inode), NULL, 134762306a36Sopenharmony_ci i_size_read(target_inode), 0); 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_ci rc = -EOPNOTSUPP; 135062306a36Sopenharmony_ci if (target_tcon->ses->server->ops->duplicate_extents) { 135162306a36Sopenharmony_ci rc = target_tcon->ses->server->ops->duplicate_extents(xid, 135262306a36Sopenharmony_ci smb_file_src, smb_file_target, off, len, destoff); 135362306a36Sopenharmony_ci if (rc == 0 && new_size > i_size_read(target_inode)) { 135462306a36Sopenharmony_ci truncate_setsize(target_inode, new_size); 135562306a36Sopenharmony_ci netfs_resize_file(&target_cifsi->netfs, new_size); 135662306a36Sopenharmony_ci fscache_resize_cookie(cifs_inode_cookie(target_inode), 135762306a36Sopenharmony_ci new_size); 135862306a36Sopenharmony_ci } 135962306a36Sopenharmony_ci } 136062306a36Sopenharmony_ci 136162306a36Sopenharmony_ci /* force revalidate of size and timestamps of target file now 136262306a36Sopenharmony_ci that target is updated on the server */ 136362306a36Sopenharmony_ci CIFS_I(target_inode)->time = 0; 136462306a36Sopenharmony_ciunlock: 136562306a36Sopenharmony_ci /* although unlocking in the reverse order from locking is not 136662306a36Sopenharmony_ci strictly necessary here it is a little cleaner to be consistent */ 136762306a36Sopenharmony_ci unlock_two_nondirectories(src_inode, target_inode); 136862306a36Sopenharmony_ciout: 136962306a36Sopenharmony_ci free_xid(xid); 137062306a36Sopenharmony_ci return rc < 0 ? rc : len; 137162306a36Sopenharmony_ci} 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_cissize_t cifs_file_copychunk_range(unsigned int xid, 137462306a36Sopenharmony_ci struct file *src_file, loff_t off, 137562306a36Sopenharmony_ci struct file *dst_file, loff_t destoff, 137662306a36Sopenharmony_ci size_t len, unsigned int flags) 137762306a36Sopenharmony_ci{ 137862306a36Sopenharmony_ci struct inode *src_inode = file_inode(src_file); 137962306a36Sopenharmony_ci struct inode *target_inode = file_inode(dst_file); 138062306a36Sopenharmony_ci struct cifsInodeInfo *src_cifsi = CIFS_I(src_inode); 138162306a36Sopenharmony_ci struct cifsFileInfo *smb_file_src; 138262306a36Sopenharmony_ci struct cifsFileInfo *smb_file_target; 138362306a36Sopenharmony_ci struct cifs_tcon *src_tcon; 138462306a36Sopenharmony_ci struct cifs_tcon *target_tcon; 138562306a36Sopenharmony_ci unsigned long long destend, fstart, fend; 138662306a36Sopenharmony_ci ssize_t rc; 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_ci cifs_dbg(FYI, "copychunk range\n"); 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci if (!src_file->private_data || !dst_file->private_data) { 139162306a36Sopenharmony_ci rc = -EBADF; 139262306a36Sopenharmony_ci cifs_dbg(VFS, "missing cifsFileInfo on copy range src file\n"); 139362306a36Sopenharmony_ci goto out; 139462306a36Sopenharmony_ci } 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci rc = -EXDEV; 139762306a36Sopenharmony_ci smb_file_target = dst_file->private_data; 139862306a36Sopenharmony_ci smb_file_src = src_file->private_data; 139962306a36Sopenharmony_ci src_tcon = tlink_tcon(smb_file_src->tlink); 140062306a36Sopenharmony_ci target_tcon = tlink_tcon(smb_file_target->tlink); 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_ci if (src_tcon->ses != target_tcon->ses) { 140362306a36Sopenharmony_ci cifs_dbg(VFS, "source and target of copy not on same server\n"); 140462306a36Sopenharmony_ci goto out; 140562306a36Sopenharmony_ci } 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ci rc = -EOPNOTSUPP; 140862306a36Sopenharmony_ci if (!target_tcon->ses->server->ops->copychunk_range) 140962306a36Sopenharmony_ci goto out; 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_ci /* 141262306a36Sopenharmony_ci * Note: cifs case is easier than btrfs since server responsible for 141362306a36Sopenharmony_ci * checks for proper open modes and file type and if it wants 141462306a36Sopenharmony_ci * server could even support copy of range where source = target 141562306a36Sopenharmony_ci */ 141662306a36Sopenharmony_ci lock_two_nondirectories(target_inode, src_inode); 141762306a36Sopenharmony_ci 141862306a36Sopenharmony_ci cifs_dbg(FYI, "about to flush pages\n"); 141962306a36Sopenharmony_ci 142062306a36Sopenharmony_ci rc = filemap_write_and_wait_range(src_inode->i_mapping, off, 142162306a36Sopenharmony_ci off + len - 1); 142262306a36Sopenharmony_ci if (rc) 142362306a36Sopenharmony_ci goto unlock; 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_ci /* The server-side copy will fail if the source crosses the EOF marker. 142662306a36Sopenharmony_ci * Advance the EOF marker after the flush above to the end of the range 142762306a36Sopenharmony_ci * if it's short of that. 142862306a36Sopenharmony_ci */ 142962306a36Sopenharmony_ci if (src_cifsi->server_eof < off + len) { 143062306a36Sopenharmony_ci rc = cifs_precopy_set_eof(src_inode, src_cifsi, src_tcon, xid, off + len); 143162306a36Sopenharmony_ci if (rc < 0) 143262306a36Sopenharmony_ci goto unlock; 143362306a36Sopenharmony_ci } 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_ci destend = destoff + len - 1; 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_ci /* Flush the folios at either end of the destination range to prevent 143862306a36Sopenharmony_ci * accidental loss of dirty data outside of the range. 143962306a36Sopenharmony_ci */ 144062306a36Sopenharmony_ci fstart = destoff; 144162306a36Sopenharmony_ci fend = destend; 144262306a36Sopenharmony_ci 144362306a36Sopenharmony_ci rc = cifs_flush_folio(target_inode, destoff, &fstart, &fend, true); 144462306a36Sopenharmony_ci if (rc) 144562306a36Sopenharmony_ci goto unlock; 144662306a36Sopenharmony_ci rc = cifs_flush_folio(target_inode, destend, &fstart, &fend, false); 144762306a36Sopenharmony_ci if (rc) 144862306a36Sopenharmony_ci goto unlock; 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ci /* Discard all the folios that overlap the destination region. */ 145162306a36Sopenharmony_ci truncate_inode_pages_range(&target_inode->i_data, fstart, fend); 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci rc = file_modified(dst_file); 145462306a36Sopenharmony_ci if (!rc) { 145562306a36Sopenharmony_ci rc = target_tcon->ses->server->ops->copychunk_range(xid, 145662306a36Sopenharmony_ci smb_file_src, smb_file_target, off, len, destoff); 145762306a36Sopenharmony_ci if (rc > 0 && destoff + rc > i_size_read(target_inode)) 145862306a36Sopenharmony_ci truncate_setsize(target_inode, destoff + rc); 145962306a36Sopenharmony_ci } 146062306a36Sopenharmony_ci 146162306a36Sopenharmony_ci file_accessed(src_file); 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci /* force revalidate of size and timestamps of target file now 146462306a36Sopenharmony_ci * that target is updated on the server 146562306a36Sopenharmony_ci */ 146662306a36Sopenharmony_ci CIFS_I(target_inode)->time = 0; 146762306a36Sopenharmony_ci 146862306a36Sopenharmony_ciunlock: 146962306a36Sopenharmony_ci /* although unlocking in the reverse order from locking is not 147062306a36Sopenharmony_ci * strictly necessary here it is a little cleaner to be consistent 147162306a36Sopenharmony_ci */ 147262306a36Sopenharmony_ci unlock_two_nondirectories(src_inode, target_inode); 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ciout: 147562306a36Sopenharmony_ci return rc; 147662306a36Sopenharmony_ci} 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_ci/* 147962306a36Sopenharmony_ci * Directory operations under CIFS/SMB2/SMB3 are synchronous, so fsync() 148062306a36Sopenharmony_ci * is a dummy operation. 148162306a36Sopenharmony_ci */ 148262306a36Sopenharmony_cistatic int cifs_dir_fsync(struct file *file, loff_t start, loff_t end, int datasync) 148362306a36Sopenharmony_ci{ 148462306a36Sopenharmony_ci cifs_dbg(FYI, "Sync directory - name: %pD datasync: 0x%x\n", 148562306a36Sopenharmony_ci file, datasync); 148662306a36Sopenharmony_ci 148762306a36Sopenharmony_ci return 0; 148862306a36Sopenharmony_ci} 148962306a36Sopenharmony_ci 149062306a36Sopenharmony_cistatic ssize_t cifs_copy_file_range(struct file *src_file, loff_t off, 149162306a36Sopenharmony_ci struct file *dst_file, loff_t destoff, 149262306a36Sopenharmony_ci size_t len, unsigned int flags) 149362306a36Sopenharmony_ci{ 149462306a36Sopenharmony_ci unsigned int xid = get_xid(); 149562306a36Sopenharmony_ci ssize_t rc; 149662306a36Sopenharmony_ci struct cifsFileInfo *cfile = dst_file->private_data; 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci if (cfile->swapfile) { 149962306a36Sopenharmony_ci rc = -EOPNOTSUPP; 150062306a36Sopenharmony_ci free_xid(xid); 150162306a36Sopenharmony_ci return rc; 150262306a36Sopenharmony_ci } 150362306a36Sopenharmony_ci 150462306a36Sopenharmony_ci rc = cifs_file_copychunk_range(xid, src_file, off, dst_file, destoff, 150562306a36Sopenharmony_ci len, flags); 150662306a36Sopenharmony_ci free_xid(xid); 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_ci if (rc == -EOPNOTSUPP || rc == -EXDEV) 150962306a36Sopenharmony_ci rc = generic_copy_file_range(src_file, off, dst_file, 151062306a36Sopenharmony_ci destoff, len, flags); 151162306a36Sopenharmony_ci return rc; 151262306a36Sopenharmony_ci} 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_ciconst struct file_operations cifs_file_ops = { 151562306a36Sopenharmony_ci .read_iter = cifs_loose_read_iter, 151662306a36Sopenharmony_ci .write_iter = cifs_file_write_iter, 151762306a36Sopenharmony_ci .open = cifs_open, 151862306a36Sopenharmony_ci .release = cifs_close, 151962306a36Sopenharmony_ci .lock = cifs_lock, 152062306a36Sopenharmony_ci .flock = cifs_flock, 152162306a36Sopenharmony_ci .fsync = cifs_fsync, 152262306a36Sopenharmony_ci .flush = cifs_flush, 152362306a36Sopenharmony_ci .mmap = cifs_file_mmap, 152462306a36Sopenharmony_ci .splice_read = filemap_splice_read, 152562306a36Sopenharmony_ci .splice_write = iter_file_splice_write, 152662306a36Sopenharmony_ci .llseek = cifs_llseek, 152762306a36Sopenharmony_ci .unlocked_ioctl = cifs_ioctl, 152862306a36Sopenharmony_ci .copy_file_range = cifs_copy_file_range, 152962306a36Sopenharmony_ci .remap_file_range = cifs_remap_file_range, 153062306a36Sopenharmony_ci .setlease = cifs_setlease, 153162306a36Sopenharmony_ci .fallocate = cifs_fallocate, 153262306a36Sopenharmony_ci}; 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_ciconst struct file_operations cifs_file_strict_ops = { 153562306a36Sopenharmony_ci .read_iter = cifs_strict_readv, 153662306a36Sopenharmony_ci .write_iter = cifs_strict_writev, 153762306a36Sopenharmony_ci .open = cifs_open, 153862306a36Sopenharmony_ci .release = cifs_close, 153962306a36Sopenharmony_ci .lock = cifs_lock, 154062306a36Sopenharmony_ci .flock = cifs_flock, 154162306a36Sopenharmony_ci .fsync = cifs_strict_fsync, 154262306a36Sopenharmony_ci .flush = cifs_flush, 154362306a36Sopenharmony_ci .mmap = cifs_file_strict_mmap, 154462306a36Sopenharmony_ci .splice_read = filemap_splice_read, 154562306a36Sopenharmony_ci .splice_write = iter_file_splice_write, 154662306a36Sopenharmony_ci .llseek = cifs_llseek, 154762306a36Sopenharmony_ci .unlocked_ioctl = cifs_ioctl, 154862306a36Sopenharmony_ci .copy_file_range = cifs_copy_file_range, 154962306a36Sopenharmony_ci .remap_file_range = cifs_remap_file_range, 155062306a36Sopenharmony_ci .setlease = cifs_setlease, 155162306a36Sopenharmony_ci .fallocate = cifs_fallocate, 155262306a36Sopenharmony_ci}; 155362306a36Sopenharmony_ci 155462306a36Sopenharmony_ciconst struct file_operations cifs_file_direct_ops = { 155562306a36Sopenharmony_ci .read_iter = cifs_direct_readv, 155662306a36Sopenharmony_ci .write_iter = cifs_direct_writev, 155762306a36Sopenharmony_ci .open = cifs_open, 155862306a36Sopenharmony_ci .release = cifs_close, 155962306a36Sopenharmony_ci .lock = cifs_lock, 156062306a36Sopenharmony_ci .flock = cifs_flock, 156162306a36Sopenharmony_ci .fsync = cifs_fsync, 156262306a36Sopenharmony_ci .flush = cifs_flush, 156362306a36Sopenharmony_ci .mmap = cifs_file_mmap, 156462306a36Sopenharmony_ci .splice_read = copy_splice_read, 156562306a36Sopenharmony_ci .splice_write = iter_file_splice_write, 156662306a36Sopenharmony_ci .unlocked_ioctl = cifs_ioctl, 156762306a36Sopenharmony_ci .copy_file_range = cifs_copy_file_range, 156862306a36Sopenharmony_ci .remap_file_range = cifs_remap_file_range, 156962306a36Sopenharmony_ci .llseek = cifs_llseek, 157062306a36Sopenharmony_ci .setlease = cifs_setlease, 157162306a36Sopenharmony_ci .fallocate = cifs_fallocate, 157262306a36Sopenharmony_ci}; 157362306a36Sopenharmony_ci 157462306a36Sopenharmony_ciconst struct file_operations cifs_file_nobrl_ops = { 157562306a36Sopenharmony_ci .read_iter = cifs_loose_read_iter, 157662306a36Sopenharmony_ci .write_iter = cifs_file_write_iter, 157762306a36Sopenharmony_ci .open = cifs_open, 157862306a36Sopenharmony_ci .release = cifs_close, 157962306a36Sopenharmony_ci .fsync = cifs_fsync, 158062306a36Sopenharmony_ci .flush = cifs_flush, 158162306a36Sopenharmony_ci .mmap = cifs_file_mmap, 158262306a36Sopenharmony_ci .splice_read = filemap_splice_read, 158362306a36Sopenharmony_ci .splice_write = iter_file_splice_write, 158462306a36Sopenharmony_ci .llseek = cifs_llseek, 158562306a36Sopenharmony_ci .unlocked_ioctl = cifs_ioctl, 158662306a36Sopenharmony_ci .copy_file_range = cifs_copy_file_range, 158762306a36Sopenharmony_ci .remap_file_range = cifs_remap_file_range, 158862306a36Sopenharmony_ci .setlease = cifs_setlease, 158962306a36Sopenharmony_ci .fallocate = cifs_fallocate, 159062306a36Sopenharmony_ci}; 159162306a36Sopenharmony_ci 159262306a36Sopenharmony_ciconst struct file_operations cifs_file_strict_nobrl_ops = { 159362306a36Sopenharmony_ci .read_iter = cifs_strict_readv, 159462306a36Sopenharmony_ci .write_iter = cifs_strict_writev, 159562306a36Sopenharmony_ci .open = cifs_open, 159662306a36Sopenharmony_ci .release = cifs_close, 159762306a36Sopenharmony_ci .fsync = cifs_strict_fsync, 159862306a36Sopenharmony_ci .flush = cifs_flush, 159962306a36Sopenharmony_ci .mmap = cifs_file_strict_mmap, 160062306a36Sopenharmony_ci .splice_read = filemap_splice_read, 160162306a36Sopenharmony_ci .splice_write = iter_file_splice_write, 160262306a36Sopenharmony_ci .llseek = cifs_llseek, 160362306a36Sopenharmony_ci .unlocked_ioctl = cifs_ioctl, 160462306a36Sopenharmony_ci .copy_file_range = cifs_copy_file_range, 160562306a36Sopenharmony_ci .remap_file_range = cifs_remap_file_range, 160662306a36Sopenharmony_ci .setlease = cifs_setlease, 160762306a36Sopenharmony_ci .fallocate = cifs_fallocate, 160862306a36Sopenharmony_ci}; 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_ciconst struct file_operations cifs_file_direct_nobrl_ops = { 161162306a36Sopenharmony_ci .read_iter = cifs_direct_readv, 161262306a36Sopenharmony_ci .write_iter = cifs_direct_writev, 161362306a36Sopenharmony_ci .open = cifs_open, 161462306a36Sopenharmony_ci .release = cifs_close, 161562306a36Sopenharmony_ci .fsync = cifs_fsync, 161662306a36Sopenharmony_ci .flush = cifs_flush, 161762306a36Sopenharmony_ci .mmap = cifs_file_mmap, 161862306a36Sopenharmony_ci .splice_read = copy_splice_read, 161962306a36Sopenharmony_ci .splice_write = iter_file_splice_write, 162062306a36Sopenharmony_ci .unlocked_ioctl = cifs_ioctl, 162162306a36Sopenharmony_ci .copy_file_range = cifs_copy_file_range, 162262306a36Sopenharmony_ci .remap_file_range = cifs_remap_file_range, 162362306a36Sopenharmony_ci .llseek = cifs_llseek, 162462306a36Sopenharmony_ci .setlease = cifs_setlease, 162562306a36Sopenharmony_ci .fallocate = cifs_fallocate, 162662306a36Sopenharmony_ci}; 162762306a36Sopenharmony_ci 162862306a36Sopenharmony_ciconst struct file_operations cifs_dir_ops = { 162962306a36Sopenharmony_ci .iterate_shared = cifs_readdir, 163062306a36Sopenharmony_ci .release = cifs_closedir, 163162306a36Sopenharmony_ci .read = generic_read_dir, 163262306a36Sopenharmony_ci .unlocked_ioctl = cifs_ioctl, 163362306a36Sopenharmony_ci .copy_file_range = cifs_copy_file_range, 163462306a36Sopenharmony_ci .remap_file_range = cifs_remap_file_range, 163562306a36Sopenharmony_ci .llseek = generic_file_llseek, 163662306a36Sopenharmony_ci .fsync = cifs_dir_fsync, 163762306a36Sopenharmony_ci}; 163862306a36Sopenharmony_ci 163962306a36Sopenharmony_cistatic void 164062306a36Sopenharmony_cicifs_init_once(void *inode) 164162306a36Sopenharmony_ci{ 164262306a36Sopenharmony_ci struct cifsInodeInfo *cifsi = inode; 164362306a36Sopenharmony_ci 164462306a36Sopenharmony_ci inode_init_once(&cifsi->netfs.inode); 164562306a36Sopenharmony_ci init_rwsem(&cifsi->lock_sem); 164662306a36Sopenharmony_ci} 164762306a36Sopenharmony_ci 164862306a36Sopenharmony_cistatic int __init 164962306a36Sopenharmony_cicifs_init_inodecache(void) 165062306a36Sopenharmony_ci{ 165162306a36Sopenharmony_ci cifs_inode_cachep = kmem_cache_create("cifs_inode_cache", 165262306a36Sopenharmony_ci sizeof(struct cifsInodeInfo), 165362306a36Sopenharmony_ci 0, (SLAB_RECLAIM_ACCOUNT| 165462306a36Sopenharmony_ci SLAB_MEM_SPREAD|SLAB_ACCOUNT), 165562306a36Sopenharmony_ci cifs_init_once); 165662306a36Sopenharmony_ci if (cifs_inode_cachep == NULL) 165762306a36Sopenharmony_ci return -ENOMEM; 165862306a36Sopenharmony_ci 165962306a36Sopenharmony_ci return 0; 166062306a36Sopenharmony_ci} 166162306a36Sopenharmony_ci 166262306a36Sopenharmony_cistatic void 166362306a36Sopenharmony_cicifs_destroy_inodecache(void) 166462306a36Sopenharmony_ci{ 166562306a36Sopenharmony_ci /* 166662306a36Sopenharmony_ci * Make sure all delayed rcu free inodes are flushed before we 166762306a36Sopenharmony_ci * destroy cache. 166862306a36Sopenharmony_ci */ 166962306a36Sopenharmony_ci rcu_barrier(); 167062306a36Sopenharmony_ci kmem_cache_destroy(cifs_inode_cachep); 167162306a36Sopenharmony_ci} 167262306a36Sopenharmony_ci 167362306a36Sopenharmony_cistatic int 167462306a36Sopenharmony_cicifs_init_request_bufs(void) 167562306a36Sopenharmony_ci{ 167662306a36Sopenharmony_ci /* 167762306a36Sopenharmony_ci * SMB2 maximum header size is bigger than CIFS one - no problems to 167862306a36Sopenharmony_ci * allocate some more bytes for CIFS. 167962306a36Sopenharmony_ci */ 168062306a36Sopenharmony_ci size_t max_hdr_size = MAX_SMB2_HDR_SIZE; 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_ci if (CIFSMaxBufSize < 8192) { 168362306a36Sopenharmony_ci /* Buffer size can not be smaller than 2 * PATH_MAX since maximum 168462306a36Sopenharmony_ci Unicode path name has to fit in any SMB/CIFS path based frames */ 168562306a36Sopenharmony_ci CIFSMaxBufSize = 8192; 168662306a36Sopenharmony_ci } else if (CIFSMaxBufSize > 1024*127) { 168762306a36Sopenharmony_ci CIFSMaxBufSize = 1024 * 127; 168862306a36Sopenharmony_ci } else { 168962306a36Sopenharmony_ci CIFSMaxBufSize &= 0x1FE00; /* Round size to even 512 byte mult*/ 169062306a36Sopenharmony_ci } 169162306a36Sopenharmony_ci/* 169262306a36Sopenharmony_ci cifs_dbg(VFS, "CIFSMaxBufSize %d 0x%x\n", 169362306a36Sopenharmony_ci CIFSMaxBufSize, CIFSMaxBufSize); 169462306a36Sopenharmony_ci*/ 169562306a36Sopenharmony_ci cifs_req_cachep = kmem_cache_create_usercopy("cifs_request", 169662306a36Sopenharmony_ci CIFSMaxBufSize + max_hdr_size, 0, 169762306a36Sopenharmony_ci SLAB_HWCACHE_ALIGN, 0, 169862306a36Sopenharmony_ci CIFSMaxBufSize + max_hdr_size, 169962306a36Sopenharmony_ci NULL); 170062306a36Sopenharmony_ci if (cifs_req_cachep == NULL) 170162306a36Sopenharmony_ci return -ENOMEM; 170262306a36Sopenharmony_ci 170362306a36Sopenharmony_ci if (cifs_min_rcv < 1) 170462306a36Sopenharmony_ci cifs_min_rcv = 1; 170562306a36Sopenharmony_ci else if (cifs_min_rcv > 64) { 170662306a36Sopenharmony_ci cifs_min_rcv = 64; 170762306a36Sopenharmony_ci cifs_dbg(VFS, "cifs_min_rcv set to maximum (64)\n"); 170862306a36Sopenharmony_ci } 170962306a36Sopenharmony_ci 171062306a36Sopenharmony_ci cifs_req_poolp = mempool_create_slab_pool(cifs_min_rcv, 171162306a36Sopenharmony_ci cifs_req_cachep); 171262306a36Sopenharmony_ci 171362306a36Sopenharmony_ci if (cifs_req_poolp == NULL) { 171462306a36Sopenharmony_ci kmem_cache_destroy(cifs_req_cachep); 171562306a36Sopenharmony_ci return -ENOMEM; 171662306a36Sopenharmony_ci } 171762306a36Sopenharmony_ci /* MAX_CIFS_SMALL_BUFFER_SIZE bytes is enough for most SMB responses and 171862306a36Sopenharmony_ci almost all handle based requests (but not write response, nor is it 171962306a36Sopenharmony_ci sufficient for path based requests). A smaller size would have 172062306a36Sopenharmony_ci been more efficient (compacting multiple slab items on one 4k page) 172162306a36Sopenharmony_ci for the case in which debug was on, but this larger size allows 172262306a36Sopenharmony_ci more SMBs to use small buffer alloc and is still much more 172362306a36Sopenharmony_ci efficient to alloc 1 per page off the slab compared to 17K (5page) 172462306a36Sopenharmony_ci alloc of large cifs buffers even when page debugging is on */ 172562306a36Sopenharmony_ci cifs_sm_req_cachep = kmem_cache_create_usercopy("cifs_small_rq", 172662306a36Sopenharmony_ci MAX_CIFS_SMALL_BUFFER_SIZE, 0, SLAB_HWCACHE_ALIGN, 172762306a36Sopenharmony_ci 0, MAX_CIFS_SMALL_BUFFER_SIZE, NULL); 172862306a36Sopenharmony_ci if (cifs_sm_req_cachep == NULL) { 172962306a36Sopenharmony_ci mempool_destroy(cifs_req_poolp); 173062306a36Sopenharmony_ci kmem_cache_destroy(cifs_req_cachep); 173162306a36Sopenharmony_ci return -ENOMEM; 173262306a36Sopenharmony_ci } 173362306a36Sopenharmony_ci 173462306a36Sopenharmony_ci if (cifs_min_small < 2) 173562306a36Sopenharmony_ci cifs_min_small = 2; 173662306a36Sopenharmony_ci else if (cifs_min_small > 256) { 173762306a36Sopenharmony_ci cifs_min_small = 256; 173862306a36Sopenharmony_ci cifs_dbg(FYI, "cifs_min_small set to maximum (256)\n"); 173962306a36Sopenharmony_ci } 174062306a36Sopenharmony_ci 174162306a36Sopenharmony_ci cifs_sm_req_poolp = mempool_create_slab_pool(cifs_min_small, 174262306a36Sopenharmony_ci cifs_sm_req_cachep); 174362306a36Sopenharmony_ci 174462306a36Sopenharmony_ci if (cifs_sm_req_poolp == NULL) { 174562306a36Sopenharmony_ci mempool_destroy(cifs_req_poolp); 174662306a36Sopenharmony_ci kmem_cache_destroy(cifs_req_cachep); 174762306a36Sopenharmony_ci kmem_cache_destroy(cifs_sm_req_cachep); 174862306a36Sopenharmony_ci return -ENOMEM; 174962306a36Sopenharmony_ci } 175062306a36Sopenharmony_ci 175162306a36Sopenharmony_ci return 0; 175262306a36Sopenharmony_ci} 175362306a36Sopenharmony_ci 175462306a36Sopenharmony_cistatic void 175562306a36Sopenharmony_cicifs_destroy_request_bufs(void) 175662306a36Sopenharmony_ci{ 175762306a36Sopenharmony_ci mempool_destroy(cifs_req_poolp); 175862306a36Sopenharmony_ci kmem_cache_destroy(cifs_req_cachep); 175962306a36Sopenharmony_ci mempool_destroy(cifs_sm_req_poolp); 176062306a36Sopenharmony_ci kmem_cache_destroy(cifs_sm_req_cachep); 176162306a36Sopenharmony_ci} 176262306a36Sopenharmony_ci 176362306a36Sopenharmony_cistatic int init_mids(void) 176462306a36Sopenharmony_ci{ 176562306a36Sopenharmony_ci cifs_mid_cachep = kmem_cache_create("cifs_mpx_ids", 176662306a36Sopenharmony_ci sizeof(struct mid_q_entry), 0, 176762306a36Sopenharmony_ci SLAB_HWCACHE_ALIGN, NULL); 176862306a36Sopenharmony_ci if (cifs_mid_cachep == NULL) 176962306a36Sopenharmony_ci return -ENOMEM; 177062306a36Sopenharmony_ci 177162306a36Sopenharmony_ci /* 3 is a reasonable minimum number of simultaneous operations */ 177262306a36Sopenharmony_ci cifs_mid_poolp = mempool_create_slab_pool(3, cifs_mid_cachep); 177362306a36Sopenharmony_ci if (cifs_mid_poolp == NULL) { 177462306a36Sopenharmony_ci kmem_cache_destroy(cifs_mid_cachep); 177562306a36Sopenharmony_ci return -ENOMEM; 177662306a36Sopenharmony_ci } 177762306a36Sopenharmony_ci 177862306a36Sopenharmony_ci return 0; 177962306a36Sopenharmony_ci} 178062306a36Sopenharmony_ci 178162306a36Sopenharmony_cistatic void destroy_mids(void) 178262306a36Sopenharmony_ci{ 178362306a36Sopenharmony_ci mempool_destroy(cifs_mid_poolp); 178462306a36Sopenharmony_ci kmem_cache_destroy(cifs_mid_cachep); 178562306a36Sopenharmony_ci} 178662306a36Sopenharmony_ci 178762306a36Sopenharmony_cistatic int __init 178862306a36Sopenharmony_ciinit_cifs(void) 178962306a36Sopenharmony_ci{ 179062306a36Sopenharmony_ci int rc = 0; 179162306a36Sopenharmony_ci cifs_proc_init(); 179262306a36Sopenharmony_ci INIT_LIST_HEAD(&cifs_tcp_ses_list); 179362306a36Sopenharmony_ci/* 179462306a36Sopenharmony_ci * Initialize Global counters 179562306a36Sopenharmony_ci */ 179662306a36Sopenharmony_ci atomic_set(&sesInfoAllocCount, 0); 179762306a36Sopenharmony_ci atomic_set(&tconInfoAllocCount, 0); 179862306a36Sopenharmony_ci atomic_set(&tcpSesNextId, 0); 179962306a36Sopenharmony_ci atomic_set(&tcpSesAllocCount, 0); 180062306a36Sopenharmony_ci atomic_set(&tcpSesReconnectCount, 0); 180162306a36Sopenharmony_ci atomic_set(&tconInfoReconnectCount, 0); 180262306a36Sopenharmony_ci 180362306a36Sopenharmony_ci atomic_set(&buf_alloc_count, 0); 180462306a36Sopenharmony_ci atomic_set(&small_buf_alloc_count, 0); 180562306a36Sopenharmony_ci#ifdef CONFIG_CIFS_STATS2 180662306a36Sopenharmony_ci atomic_set(&total_buf_alloc_count, 0); 180762306a36Sopenharmony_ci atomic_set(&total_small_buf_alloc_count, 0); 180862306a36Sopenharmony_ci if (slow_rsp_threshold < 1) 180962306a36Sopenharmony_ci cifs_dbg(FYI, "slow_response_threshold msgs disabled\n"); 181062306a36Sopenharmony_ci else if (slow_rsp_threshold > 32767) 181162306a36Sopenharmony_ci cifs_dbg(VFS, 181262306a36Sopenharmony_ci "slow response threshold set higher than recommended (0 to 32767)\n"); 181362306a36Sopenharmony_ci#endif /* CONFIG_CIFS_STATS2 */ 181462306a36Sopenharmony_ci 181562306a36Sopenharmony_ci atomic_set(&mid_count, 0); 181662306a36Sopenharmony_ci GlobalCurrentXid = 0; 181762306a36Sopenharmony_ci GlobalTotalActiveXid = 0; 181862306a36Sopenharmony_ci GlobalMaxActiveXid = 0; 181962306a36Sopenharmony_ci spin_lock_init(&cifs_tcp_ses_lock); 182062306a36Sopenharmony_ci spin_lock_init(&GlobalMid_Lock); 182162306a36Sopenharmony_ci 182262306a36Sopenharmony_ci cifs_lock_secret = get_random_u32(); 182362306a36Sopenharmony_ci 182462306a36Sopenharmony_ci if (cifs_max_pending < 2) { 182562306a36Sopenharmony_ci cifs_max_pending = 2; 182662306a36Sopenharmony_ci cifs_dbg(FYI, "cifs_max_pending set to min of 2\n"); 182762306a36Sopenharmony_ci } else if (cifs_max_pending > CIFS_MAX_REQ) { 182862306a36Sopenharmony_ci cifs_max_pending = CIFS_MAX_REQ; 182962306a36Sopenharmony_ci cifs_dbg(FYI, "cifs_max_pending set to max of %u\n", 183062306a36Sopenharmony_ci CIFS_MAX_REQ); 183162306a36Sopenharmony_ci } 183262306a36Sopenharmony_ci 183362306a36Sopenharmony_ci /* Limit max to about 18 hours, and setting to zero disables directory entry caching */ 183462306a36Sopenharmony_ci if (dir_cache_timeout > 65000) { 183562306a36Sopenharmony_ci dir_cache_timeout = 65000; 183662306a36Sopenharmony_ci cifs_dbg(VFS, "dir_cache_timeout set to max of 65000 seconds\n"); 183762306a36Sopenharmony_ci } 183862306a36Sopenharmony_ci 183962306a36Sopenharmony_ci cifsiod_wq = alloc_workqueue("cifsiod", WQ_FREEZABLE|WQ_MEM_RECLAIM, 0); 184062306a36Sopenharmony_ci if (!cifsiod_wq) { 184162306a36Sopenharmony_ci rc = -ENOMEM; 184262306a36Sopenharmony_ci goto out_clean_proc; 184362306a36Sopenharmony_ci } 184462306a36Sopenharmony_ci 184562306a36Sopenharmony_ci /* 184662306a36Sopenharmony_ci * Consider in future setting limit!=0 maybe to min(num_of_cores - 1, 3) 184762306a36Sopenharmony_ci * so that we don't launch too many worker threads but 184862306a36Sopenharmony_ci * Documentation/core-api/workqueue.rst recommends setting it to 0 184962306a36Sopenharmony_ci */ 185062306a36Sopenharmony_ci 185162306a36Sopenharmony_ci /* WQ_UNBOUND allows decrypt tasks to run on any CPU */ 185262306a36Sopenharmony_ci decrypt_wq = alloc_workqueue("smb3decryptd", 185362306a36Sopenharmony_ci WQ_UNBOUND|WQ_FREEZABLE|WQ_MEM_RECLAIM, 0); 185462306a36Sopenharmony_ci if (!decrypt_wq) { 185562306a36Sopenharmony_ci rc = -ENOMEM; 185662306a36Sopenharmony_ci goto out_destroy_cifsiod_wq; 185762306a36Sopenharmony_ci } 185862306a36Sopenharmony_ci 185962306a36Sopenharmony_ci fileinfo_put_wq = alloc_workqueue("cifsfileinfoput", 186062306a36Sopenharmony_ci WQ_UNBOUND|WQ_FREEZABLE|WQ_MEM_RECLAIM, 0); 186162306a36Sopenharmony_ci if (!fileinfo_put_wq) { 186262306a36Sopenharmony_ci rc = -ENOMEM; 186362306a36Sopenharmony_ci goto out_destroy_decrypt_wq; 186462306a36Sopenharmony_ci } 186562306a36Sopenharmony_ci 186662306a36Sopenharmony_ci cifsoplockd_wq = alloc_workqueue("cifsoplockd", 186762306a36Sopenharmony_ci WQ_FREEZABLE|WQ_MEM_RECLAIM, 0); 186862306a36Sopenharmony_ci if (!cifsoplockd_wq) { 186962306a36Sopenharmony_ci rc = -ENOMEM; 187062306a36Sopenharmony_ci goto out_destroy_fileinfo_put_wq; 187162306a36Sopenharmony_ci } 187262306a36Sopenharmony_ci 187362306a36Sopenharmony_ci deferredclose_wq = alloc_workqueue("deferredclose", 187462306a36Sopenharmony_ci WQ_FREEZABLE|WQ_MEM_RECLAIM, 0); 187562306a36Sopenharmony_ci if (!deferredclose_wq) { 187662306a36Sopenharmony_ci rc = -ENOMEM; 187762306a36Sopenharmony_ci goto out_destroy_cifsoplockd_wq; 187862306a36Sopenharmony_ci } 187962306a36Sopenharmony_ci 188062306a36Sopenharmony_ci rc = cifs_init_inodecache(); 188162306a36Sopenharmony_ci if (rc) 188262306a36Sopenharmony_ci goto out_destroy_deferredclose_wq; 188362306a36Sopenharmony_ci 188462306a36Sopenharmony_ci rc = init_mids(); 188562306a36Sopenharmony_ci if (rc) 188662306a36Sopenharmony_ci goto out_destroy_inodecache; 188762306a36Sopenharmony_ci 188862306a36Sopenharmony_ci rc = cifs_init_request_bufs(); 188962306a36Sopenharmony_ci if (rc) 189062306a36Sopenharmony_ci goto out_destroy_mids; 189162306a36Sopenharmony_ci 189262306a36Sopenharmony_ci#ifdef CONFIG_CIFS_DFS_UPCALL 189362306a36Sopenharmony_ci rc = dfs_cache_init(); 189462306a36Sopenharmony_ci if (rc) 189562306a36Sopenharmony_ci goto out_destroy_request_bufs; 189662306a36Sopenharmony_ci#endif /* CONFIG_CIFS_DFS_UPCALL */ 189762306a36Sopenharmony_ci#ifdef CONFIG_CIFS_UPCALL 189862306a36Sopenharmony_ci rc = init_cifs_spnego(); 189962306a36Sopenharmony_ci if (rc) 190062306a36Sopenharmony_ci goto out_destroy_dfs_cache; 190162306a36Sopenharmony_ci#endif /* CONFIG_CIFS_UPCALL */ 190262306a36Sopenharmony_ci#ifdef CONFIG_CIFS_SWN_UPCALL 190362306a36Sopenharmony_ci rc = cifs_genl_init(); 190462306a36Sopenharmony_ci if (rc) 190562306a36Sopenharmony_ci goto out_register_key_type; 190662306a36Sopenharmony_ci#endif /* CONFIG_CIFS_SWN_UPCALL */ 190762306a36Sopenharmony_ci 190862306a36Sopenharmony_ci rc = init_cifs_idmap(); 190962306a36Sopenharmony_ci if (rc) 191062306a36Sopenharmony_ci goto out_cifs_swn_init; 191162306a36Sopenharmony_ci 191262306a36Sopenharmony_ci rc = register_filesystem(&cifs_fs_type); 191362306a36Sopenharmony_ci if (rc) 191462306a36Sopenharmony_ci goto out_init_cifs_idmap; 191562306a36Sopenharmony_ci 191662306a36Sopenharmony_ci rc = register_filesystem(&smb3_fs_type); 191762306a36Sopenharmony_ci if (rc) { 191862306a36Sopenharmony_ci unregister_filesystem(&cifs_fs_type); 191962306a36Sopenharmony_ci goto out_init_cifs_idmap; 192062306a36Sopenharmony_ci } 192162306a36Sopenharmony_ci 192262306a36Sopenharmony_ci return 0; 192362306a36Sopenharmony_ci 192462306a36Sopenharmony_ciout_init_cifs_idmap: 192562306a36Sopenharmony_ci exit_cifs_idmap(); 192662306a36Sopenharmony_ciout_cifs_swn_init: 192762306a36Sopenharmony_ci#ifdef CONFIG_CIFS_SWN_UPCALL 192862306a36Sopenharmony_ci cifs_genl_exit(); 192962306a36Sopenharmony_ciout_register_key_type: 193062306a36Sopenharmony_ci#endif 193162306a36Sopenharmony_ci#ifdef CONFIG_CIFS_UPCALL 193262306a36Sopenharmony_ci exit_cifs_spnego(); 193362306a36Sopenharmony_ciout_destroy_dfs_cache: 193462306a36Sopenharmony_ci#endif 193562306a36Sopenharmony_ci#ifdef CONFIG_CIFS_DFS_UPCALL 193662306a36Sopenharmony_ci dfs_cache_destroy(); 193762306a36Sopenharmony_ciout_destroy_request_bufs: 193862306a36Sopenharmony_ci#endif 193962306a36Sopenharmony_ci cifs_destroy_request_bufs(); 194062306a36Sopenharmony_ciout_destroy_mids: 194162306a36Sopenharmony_ci destroy_mids(); 194262306a36Sopenharmony_ciout_destroy_inodecache: 194362306a36Sopenharmony_ci cifs_destroy_inodecache(); 194462306a36Sopenharmony_ciout_destroy_deferredclose_wq: 194562306a36Sopenharmony_ci destroy_workqueue(deferredclose_wq); 194662306a36Sopenharmony_ciout_destroy_cifsoplockd_wq: 194762306a36Sopenharmony_ci destroy_workqueue(cifsoplockd_wq); 194862306a36Sopenharmony_ciout_destroy_fileinfo_put_wq: 194962306a36Sopenharmony_ci destroy_workqueue(fileinfo_put_wq); 195062306a36Sopenharmony_ciout_destroy_decrypt_wq: 195162306a36Sopenharmony_ci destroy_workqueue(decrypt_wq); 195262306a36Sopenharmony_ciout_destroy_cifsiod_wq: 195362306a36Sopenharmony_ci destroy_workqueue(cifsiod_wq); 195462306a36Sopenharmony_ciout_clean_proc: 195562306a36Sopenharmony_ci cifs_proc_clean(); 195662306a36Sopenharmony_ci return rc; 195762306a36Sopenharmony_ci} 195862306a36Sopenharmony_ci 195962306a36Sopenharmony_cistatic void __exit 196062306a36Sopenharmony_ciexit_cifs(void) 196162306a36Sopenharmony_ci{ 196262306a36Sopenharmony_ci cifs_dbg(NOISY, "exit_smb3\n"); 196362306a36Sopenharmony_ci unregister_filesystem(&cifs_fs_type); 196462306a36Sopenharmony_ci unregister_filesystem(&smb3_fs_type); 196562306a36Sopenharmony_ci cifs_release_automount_timer(); 196662306a36Sopenharmony_ci exit_cifs_idmap(); 196762306a36Sopenharmony_ci#ifdef CONFIG_CIFS_SWN_UPCALL 196862306a36Sopenharmony_ci cifs_genl_exit(); 196962306a36Sopenharmony_ci#endif 197062306a36Sopenharmony_ci#ifdef CONFIG_CIFS_UPCALL 197162306a36Sopenharmony_ci exit_cifs_spnego(); 197262306a36Sopenharmony_ci#endif 197362306a36Sopenharmony_ci#ifdef CONFIG_CIFS_DFS_UPCALL 197462306a36Sopenharmony_ci dfs_cache_destroy(); 197562306a36Sopenharmony_ci#endif 197662306a36Sopenharmony_ci cifs_destroy_request_bufs(); 197762306a36Sopenharmony_ci destroy_mids(); 197862306a36Sopenharmony_ci cifs_destroy_inodecache(); 197962306a36Sopenharmony_ci destroy_workqueue(deferredclose_wq); 198062306a36Sopenharmony_ci destroy_workqueue(cifsoplockd_wq); 198162306a36Sopenharmony_ci destroy_workqueue(decrypt_wq); 198262306a36Sopenharmony_ci destroy_workqueue(fileinfo_put_wq); 198362306a36Sopenharmony_ci destroy_workqueue(cifsiod_wq); 198462306a36Sopenharmony_ci cifs_proc_clean(); 198562306a36Sopenharmony_ci} 198662306a36Sopenharmony_ci 198762306a36Sopenharmony_ciMODULE_AUTHOR("Steve French"); 198862306a36Sopenharmony_ciMODULE_LICENSE("GPL"); /* combination of LGPL + GPL source behaves as GPL */ 198962306a36Sopenharmony_ciMODULE_DESCRIPTION 199062306a36Sopenharmony_ci ("VFS to access SMB3 servers e.g. Samba, Macs, Azure and Windows (and " 199162306a36Sopenharmony_ci "also older servers complying with the SNIA CIFS Specification)"); 199262306a36Sopenharmony_ciMODULE_VERSION(CIFS_VERSION); 199362306a36Sopenharmony_ciMODULE_SOFTDEP("ecb"); 199462306a36Sopenharmony_ciMODULE_SOFTDEP("hmac"); 199562306a36Sopenharmony_ciMODULE_SOFTDEP("md5"); 199662306a36Sopenharmony_ciMODULE_SOFTDEP("nls"); 199762306a36Sopenharmony_ciMODULE_SOFTDEP("aes"); 199862306a36Sopenharmony_ciMODULE_SOFTDEP("cmac"); 199962306a36Sopenharmony_ciMODULE_SOFTDEP("sha256"); 200062306a36Sopenharmony_ciMODULE_SOFTDEP("sha512"); 200162306a36Sopenharmony_ciMODULE_SOFTDEP("aead2"); 200262306a36Sopenharmony_ciMODULE_SOFTDEP("ccm"); 200362306a36Sopenharmony_ciMODULE_SOFTDEP("gcm"); 200462306a36Sopenharmony_cimodule_init(init_cifs) 200562306a36Sopenharmony_cimodule_exit(exit_cifs) 2006