Commit 63e62baa authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag '6.18-rc-part1-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6

Pull smb client updates from Steve French:

 - Fix oops in crypt message

 - Remove duplicate arc4 code

 - Fix potential io_uring reconnect

 - Two important directory leases fixes and three perf improvements

 - Three minor cleanups

 - Four debug improvements (e.g. for showing more information on leases,
   and one for adding more helpful information on reconnect)

* tag '6.18-rc-part1-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6:
  cifs: client: force multichannel=off when max_channels=1
  smb client: fix bug with newly created file in cached dir
  smb: client: short-circuit negative lookups when parent dir is fully cached
  smb: client: short-circuit in open_cached_dir_by_dentry() if !dentry
  smb: client: remove pointless cfid->has_lease check
  smb: client: transport: minor indentation style fix
  smb: client: transport: avoid reconnects triggered by pending task work
  smb: client: remove unused fid_lock
  smb: client: update cfid->last_access_time in open_cached_dir_by_dentry()
  smb: client: ensure open_cached_dir_by_dentry() only returns valid cfid
  smb: client: account smb directory cache usage and per-tcon totals
  smb: client: add drop_dir_cache module parameter to invalidate cached dirents
  smb: client: show lease state as R/H/W (or NONE) in open_files
  smb: client: fix crypto buffers in non-linear memory
  smb: Use arc4 library instead of duplicate arc4 code
  smb: client: add tcon information to smb2_reconnect() debug messages
parents b3fee71e 37e263e6
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@ config CIFS
	select CRYPTO_GCM
	select CRYPTO_ECB
	select CRYPTO_AES
	select CRYPTO_LIB_ARC4
	select KEYS
	select DNS_RESOLVER
	select ASN1
+31 −19
Original line number Diff line number Diff line
@@ -36,9 +36,8 @@ static struct cached_fid *find_or_create_cached_dir(struct cached_fids *cfids,
			 * fully cached or it may be in the process of
			 * being deleted due to a lease break.
			 */
			if (!cfid->time || !cfid->has_lease) {
			if (!is_valid_cached_dir(cfid))
				return NULL;
			}
			kref_get(&cfid->refcount);
			return cfid;
		}
@@ -194,7 +193,7 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
	 * Otherwise, it is either a new entry or laundromat worker removed it
	 * from @cfids->entries.  Caller will put last reference if the latter.
	 */
	if (cfid->has_lease && cfid->time) {
	if (is_valid_cached_dir(cfid)) {
		cfid->last_access_time = jiffies;
		spin_unlock(&cfids->cfid_list_lock);
		*ret_cfid = cfid;
@@ -233,7 +232,7 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
			list_for_each_entry(parent_cfid, &cfids->entries, entry) {
				if (parent_cfid->dentry == dentry->d_parent) {
					cifs_dbg(FYI, "found a parent cached file handle\n");
					if (parent_cfid->has_lease && parent_cfid->time) {
					if (is_valid_cached_dir(parent_cfid)) {
						lease_flags
							|= SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET_LE;
						memcpy(pfid->parent_lease_key,
@@ -417,12 +416,18 @@ int open_cached_dir_by_dentry(struct cifs_tcon *tcon,
	if (cfids == NULL)
		return -EOPNOTSUPP;

	if (!dentry)
		return -ENOENT;

	spin_lock(&cfids->cfid_list_lock);
	list_for_each_entry(cfid, &cfids->entries, entry) {
		if (dentry && cfid->dentry == dentry) {
		if (cfid->dentry == dentry) {
			if (!is_valid_cached_dir(cfid))
				break;
			cifs_dbg(FYI, "found a cached file handle by dentry\n");
			kref_get(&cfid->refcount);
			*ret_cfid = cfid;
			cfid->last_access_time = jiffies;
			spin_unlock(&cfids->cfid_list_lock);
			return 0;
		}
@@ -522,10 +527,9 @@ void close_all_cached_dirs(struct cifs_sb_info *cifs_sb)
				spin_unlock(&cifs_sb->tlink_tree_lock);
				goto done;
			}
			spin_lock(&cfid->fid_lock);

			tmp_list->dentry = cfid->dentry;
			cfid->dentry = NULL;
			spin_unlock(&cfid->fid_lock);

			list_add_tail(&tmp_list->entry, &entry);
		}
@@ -608,14 +612,9 @@ static void cached_dir_put_work(struct work_struct *work)
{
	struct cached_fid *cfid = container_of(work, struct cached_fid,
					       put_work);
	struct dentry *dentry;

	spin_lock(&cfid->fid_lock);
	dentry = cfid->dentry;
	dput(cfid->dentry);
	cfid->dentry = NULL;
	spin_unlock(&cfid->fid_lock);

	dput(dentry);
	queue_work(serverclose_wq, &cfid->close_work);
}

@@ -673,7 +672,6 @@ static struct cached_fid *init_cached_dir(const char *path)
	INIT_LIST_HEAD(&cfid->entry);
	INIT_LIST_HEAD(&cfid->dirents.entries);
	mutex_init(&cfid->dirents.de_mutex);
	spin_lock_init(&cfid->fid_lock);
	kref_init(&cfid->refcount);
	return cfid;
}
@@ -697,6 +695,21 @@ static void free_cached_dir(struct cached_fid *cfid)
		kfree(dirent);
	}

	/* adjust tcon-level counters and reset per-dir accounting */
	if (cfid->cfids) {
		if (cfid->dirents.entries_count)
			atomic_long_sub((long)cfid->dirents.entries_count,
					&cfid->cfids->total_dirents_entries);
		if (cfid->dirents.bytes_used) {
			atomic64_sub((long long)cfid->dirents.bytes_used,
					&cfid->cfids->total_dirents_bytes);
			atomic64_sub((long long)cfid->dirents.bytes_used,
					&cifs_dircache_bytes_used);
		}
	}
	cfid->dirents.entries_count = 0;
	cfid->dirents.bytes_used = 0;

	kfree(cfid->path);
	cfid->path = NULL;
	kfree(cfid);
@@ -725,7 +738,6 @@ static void cfids_laundromat_worker(struct work_struct *work)
{
	struct cached_fids *cfids;
	struct cached_fid *cfid, *q;
	struct dentry *dentry;
	LIST_HEAD(entry);

	cfids = container_of(work, struct cached_fids, laundromat_work.work);
@@ -752,12 +764,9 @@ static void cfids_laundromat_worker(struct work_struct *work)
	list_for_each_entry_safe(cfid, q, &entry, entry) {
		list_del(&cfid->entry);

		spin_lock(&cfid->fid_lock);
		dentry = cfid->dentry;
		dput(cfid->dentry);
		cfid->dentry = NULL;
		spin_unlock(&cfid->fid_lock);

		dput(dentry);
		if (cfid->is_open) {
			spin_lock(&cifs_tcp_ses_lock);
			++cfid->tcon->tc_count;
@@ -792,6 +801,9 @@ struct cached_fids *init_cached_dirs(void)
	queue_delayed_work(cfid_put_wq, &cfids->laundromat_work,
			   dir_cache_timeout * HZ);

	atomic_long_set(&cfids->total_dirents_entries, 0);
	atomic64_set(&cfids->total_dirents_bytes, 0);

	return cfids;
}

+15 −1
Original line number Diff line number Diff line
@@ -27,6 +27,9 @@ struct cached_dirents {
	struct mutex de_mutex;
	loff_t pos;		 /* Expected ctx->pos */
	struct list_head entries;
	/* accounting for cached entries in this directory */
	unsigned long entries_count;
	unsigned long bytes_used;
};

struct cached_fid {
@@ -41,7 +44,6 @@ struct cached_fid {
	unsigned long last_access_time; /* jiffies of when last accessed */
	struct kref refcount;
	struct cifs_fid fid;
	spinlock_t fid_lock;
	struct cifs_tcon *tcon;
	struct dentry *dentry;
	struct work_struct put_work;
@@ -62,8 +64,20 @@ struct cached_fids {
	struct list_head dying;
	struct work_struct invalidation_work;
	struct delayed_work laundromat_work;
	/* aggregate accounting for all cached dirents under this tcon */
	atomic_long_t total_dirents_entries;
	atomic64_t total_dirents_bytes;
};

/* Module-wide directory cache accounting (defined in cifsfs.c) */
extern atomic64_t cifs_dircache_bytes_used; /* bytes across all mounts */

static inline bool
is_valid_cached_dir(struct cached_fid *cfid)
{
	return cfid->time && cfid->has_lease;
}

extern struct cached_fids *init_cached_dirs(void);
extern void free_cached_dirs(struct cached_fids *cfids);
extern int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
+35 −6
Original line number Diff line number Diff line
@@ -240,14 +240,18 @@ static int cifs_debug_files_proc_show(struct seq_file *m, void *v)
	struct cifs_ses *ses;
	struct cifs_tcon *tcon;
	struct cifsFileInfo *cfile;
	struct inode *inode;
	struct cifsInodeInfo *cinode;
	char lease[4];
	int n;

	seq_puts(m, "# Version:1\n");
	seq_puts(m, "# Format:\n");
	seq_puts(m, "# <tree id> <ses id> <persistent fid> <flags> <count> <pid> <uid>");
#ifdef CONFIG_CIFS_DEBUG2
	seq_printf(m, " <filename> <mid>\n");
	seq_puts(m, " <filename> <lease> <mid>\n");
#else
	seq_printf(m, " <filename>\n");
	seq_puts(m, " <filename> <lease>\n");
#endif /* CIFS_DEBUG2 */
	spin_lock(&cifs_tcp_ses_lock);
	list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) {
@@ -267,11 +271,30 @@ static int cifs_debug_files_proc_show(struct seq_file *m, void *v)
						cfile->pid,
						from_kuid(&init_user_ns, cfile->uid),
						cfile->dentry);

					/* Append lease/oplock caching state as RHW letters */
					inode = d_inode(cfile->dentry);
					n = 0;
					if (inode) {
						cinode = CIFS_I(inode);
						if (CIFS_CACHE_READ(cinode))
							lease[n++] = 'R';
						if (CIFS_CACHE_HANDLE(cinode))
							lease[n++] = 'H';
						if (CIFS_CACHE_WRITE(cinode))
							lease[n++] = 'W';
					}
					lease[n] = '\0';
					seq_puts(m, " ");
					if (n)
						seq_printf(m, "%s", lease);
					else
						seq_puts(m, "NONE");

#ifdef CONFIG_CIFS_DEBUG2
					seq_printf(m, " %llu\n", cfile->fid.mid);
#else
					seq_printf(m, " %llu", cfile->fid.mid);
#endif /* CONFIG_CIFS_DEBUG2 */
					seq_printf(m, "\n");
#endif /* CIFS_DEBUG2 */
				}
				spin_unlock(&tcon->open_file_lock);
			}
@@ -308,7 +331,10 @@ static int cifs_debug_dirs_proc_show(struct seq_file *m, void *v)
				if (!cfids)
					continue;
				spin_lock(&cfids->cfid_list_lock); /* check lock ordering */
				seq_printf(m, "Num entries: %d\n", cfids->num_entries);
				seq_printf(m, "Num entries: %d, cached_dirents: %lu entries, %llu bytes\n",
						cfids->num_entries,
						(unsigned long)atomic_long_read(&cfids->total_dirents_entries),
						(unsigned long long)atomic64_read(&cfids->total_dirents_bytes));
				list_for_each_entry(cfid, &cfids->entries, entry) {
					seq_printf(m, "0x%x 0x%llx 0x%llx     %s",
						tcon->tid,
@@ -319,6 +345,9 @@ static int cifs_debug_dirs_proc_show(struct seq_file *m, void *v)
						seq_printf(m, "\tvalid file info");
					if (cfid->dirents.is_valid)
						seq_printf(m, ", valid dirents");
					if (!list_empty(&cfid->dirents.entries))
						seq_printf(m, ", dirents: %lu entries, %lu bytes",
						cfid->dirents.entries_count, cfid->dirents.bytes_used);
					seq_printf(m, "\n");
				}
				spin_unlock(&cfids->cfid_list_lock);
+4 −4
Original line number Diff line number Diff line
@@ -22,8 +22,8 @@
#include <linux/highmem.h>
#include <linux/fips.h>
#include <linux/iov_iter.h>
#include "../common/arc4.h"
#include <crypto/aead.h>
#include <crypto/arc4.h>

static size_t cifs_shash_step(void *iter_base, size_t progress, size_t len,
			      void *priv, void *priv2)
@@ -725,8 +725,8 @@ calc_seckey(struct cifs_ses *ses)
		return -ENOMEM;
	}

	cifs_arc4_setkey(ctx_arc4, ses->auth_key.response, CIFS_SESS_KEY_SIZE);
	cifs_arc4_crypt(ctx_arc4, ses->ntlmssp->ciphertext, sec_key,
	arc4_setkey(ctx_arc4, ses->auth_key.response, CIFS_SESS_KEY_SIZE);
	arc4_crypt(ctx_arc4, ses->ntlmssp->ciphertext, sec_key,
		   CIFS_CPHTXT_SIZE);

	/* make secondary_key/nonce as session key */
Loading