commit 72dd7961a4bb4fa1fc456169a61dd12e68e50645 upstream. Currently, cached directory contents were not reused across subsequent 'ls' operations because the cache validity check relied on comparing the ctx pointer, which changes with each readdir invocation. As a result, the cached dir entries was not marked as valid and the cache was not utilized for subsequent 'ls' operations. This change uses the file pointer, which remains consistent across all readdir calls for a given directory instance, to associate and validate the cache. As a result, cached directory contents can now be correctly reused, improving performance for repeated directory listings. Performance gains with local windows SMB server: Without the patch and default actimeo=1: 1000 directory enumeration operations on dir with 10k files took 135.0s With this patch and actimeo=0: 1000 directory enumeration operations on dir with 10k files took just 5.1s Signed-off-by: Bharath SM <bharathsm@microsoft.com> Reviewed-by: Shyam Prasad N <sprasad@microsoft.com> Cc: stable@vger.kernel.org Signed-off-by: Steve French <stfrench@microsoft.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
86 lines
2.2 KiB
C
86 lines
2.2 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/*
|
|
* Functions to handle the cached directory entries
|
|
*
|
|
* Copyright (c) 2022, Ronnie Sahlberg <lsahlber@redhat.com>
|
|
*/
|
|
|
|
#ifndef _CACHED_DIR_H
|
|
#define _CACHED_DIR_H
|
|
|
|
|
|
struct cached_dirent {
|
|
struct list_head entry;
|
|
char *name;
|
|
int namelen;
|
|
loff_t pos;
|
|
|
|
struct cifs_fattr fattr;
|
|
};
|
|
|
|
struct cached_dirents {
|
|
bool is_valid:1;
|
|
bool is_failed:1;
|
|
struct file *file; /*
|
|
* Used to associate the cache with a single
|
|
* open file instance.
|
|
*/
|
|
struct mutex de_mutex;
|
|
int pos; /* Expected ctx->pos */
|
|
struct list_head entries;
|
|
};
|
|
|
|
struct cached_fid {
|
|
struct list_head entry;
|
|
struct cached_fids *cfids;
|
|
const char *path;
|
|
bool has_lease:1;
|
|
bool is_open:1;
|
|
bool on_list:1;
|
|
bool file_all_info_is_valid:1;
|
|
unsigned long time; /* jiffies of when lease was taken */
|
|
struct kref refcount;
|
|
struct cifs_fid fid;
|
|
spinlock_t fid_lock;
|
|
struct cifs_tcon *tcon;
|
|
struct dentry *dentry;
|
|
struct work_struct put_work;
|
|
struct work_struct close_work;
|
|
struct smb2_file_all_info file_all_info;
|
|
struct cached_dirents dirents;
|
|
};
|
|
|
|
/* default MAX_CACHED_FIDS is 16 */
|
|
struct cached_fids {
|
|
/* Must be held when:
|
|
* - accessing the cfids->entries list
|
|
* - accessing the cfids->dying list
|
|
*/
|
|
spinlock_t cfid_list_lock;
|
|
int num_entries;
|
|
struct list_head entries;
|
|
struct list_head dying;
|
|
struct work_struct invalidation_work;
|
|
struct delayed_work laundromat_work;
|
|
};
|
|
|
|
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,
|
|
const char *path,
|
|
struct cifs_sb_info *cifs_sb,
|
|
bool lookup_only, struct cached_fid **cfid);
|
|
extern int open_cached_dir_by_dentry(struct cifs_tcon *tcon,
|
|
struct dentry *dentry,
|
|
struct cached_fid **cfid);
|
|
extern void close_cached_dir(struct cached_fid *cfid);
|
|
extern void drop_cached_dir_by_name(const unsigned int xid,
|
|
struct cifs_tcon *tcon,
|
|
const char *name,
|
|
struct cifs_sb_info *cifs_sb);
|
|
extern void close_all_cached_dirs(struct cifs_sb_info *cifs_sb);
|
|
extern void invalidate_all_cached_dirs(struct cifs_tcon *tcon);
|
|
extern int cached_dir_lease_break(struct cifs_tcon *tcon, __u8 lease_key[16]);
|
|
|
|
#endif /* _CACHED_DIR_H */
|