three smb3 client fixes

-----BEGIN PGP SIGNATURE-----
 
 iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAmhNnYsACgkQiiy9cAdy
 T1HNMwv+N3G4LGJljr25eIk6ycFA5HLH/XCCo/BjUiue1MBPIDqckpEmnM1e583+
 cDnW/h01R8TLpM5yYppZSymvEoVfErAOsGlCEb+a1CSwbnK4RyGQfowNgJYMUsvA
 pJDFjqwfZjXoPMz/KO4WKBkrOqXgo41aAVwCm4b4N/KNBz06G52IX1PD9P8gaech
 LLts/3JxX6oUU/w06fCGqqPwtf3qa/EIOBD9qaAQ3SPLXCLdpdd6szuLcux5yWNf
 ncXB//fZZFpT4Ylb46bexENHV4Q664KdI6f11+IcaR1kgvEhSrgwpXb/c4G3wmk4
 wl0+Qn7kYdjcPCLtAkmo2LzcaDzLN3I9I5zYl+y2r7MiUixPzN27oYr6bNE4M+Z8
 FIaQ3VOtpY7jHnvILjtjTP2xKF/Oo1KgeqHS+yBTkp7TvUPY8AWG/em+mzb+ZShv
 9zCTjdt8k6taIh1uaZIDLd5tSQAE2wN20XjBbV4CHeM6z6GoFneXNCeZAf84+xRe
 pSLQpof1
 =QF6Q
 -----END PGP SIGNATURE-----

Merge tag 'v6.16-rc1-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6

Pull smb client fixes from Steve French:

 - SMB3.1.1 POSIX extensions fix for char remapping

 - Fix for repeated directory listings when directory leases enabled

 - deferred close handle reuse fix

* tag 'v6.16-rc1-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6:
  smb: improve directory cache reuse for readdir operations
  smb: client: fix perf regression with deferred closes
  smb: client: disable path remapping with POSIX extensions
This commit is contained in:
Linus Torvalds 2025-06-14 10:13:32 -07:00
commit 8c6bc74c7f
5 changed files with 35 additions and 22 deletions

View File

@ -270,6 +270,8 @@ configured for Unix Extensions (and the client has not disabled
illegal Windows/NTFS/SMB characters to a remap range (this mount parameter
is the default for SMB3). This remap (``mapposix``) range is also
compatible with Mac (and "Services for Mac" on some older Windows).
When POSIX Extensions for SMB 3.1.1 are negotiated, remapping is automatically
disabled.
CIFS VFS Mount Options
======================

View File

@ -21,9 +21,9 @@ struct cached_dirent {
struct cached_dirents {
bool is_valid:1;
bool is_failed:1;
struct dir_context *ctx; /*
* Only used to make sure we only take entries
* from a single context. Never dereferenced.
struct file *file; /*
* Used to associate the cache with a single
* open file instance.
*/
struct mutex de_mutex;
int pos; /* Expected ctx->pos */

View File

@ -3718,9 +3718,15 @@ int cifs_mount_get_tcon(struct cifs_mount_ctx *mnt_ctx)
goto out;
}
/* if new SMB3.11 POSIX extensions are supported do not remap / and \ */
if (tcon->posix_extensions)
/*
* if new SMB3.11 POSIX extensions are supported, do not change anything in the
* path (i.e., do not remap / and \ and do not map any special characters)
*/
if (tcon->posix_extensions) {
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS;
cifs_sb->mnt_cifs_flags &= ~(CIFS_MOUNT_MAP_SFM_CHR |
CIFS_MOUNT_MAP_SPECIAL_CHR);
}
#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
/* tell server which Unix caps we support */

View File

@ -999,15 +999,18 @@ int cifs_open(struct inode *inode, struct file *file)
rc = cifs_get_readable_path(tcon, full_path, &cfile);
}
if (rc == 0) {
if (file->f_flags == cfile->f_flags) {
unsigned int oflags = file->f_flags & ~(O_CREAT|O_EXCL|O_TRUNC);
unsigned int cflags = cfile->f_flags & ~(O_CREAT|O_EXCL|O_TRUNC);
if (cifs_convert_flags(oflags, 0) == cifs_convert_flags(cflags, 0) &&
(oflags & (O_SYNC|O_DIRECT)) == (cflags & (O_SYNC|O_DIRECT))) {
file->private_data = cfile;
spin_lock(&CIFS_I(inode)->deferred_lock);
cifs_del_deferred_close(cfile);
spin_unlock(&CIFS_I(inode)->deferred_lock);
goto use_cache;
} else {
_cifsFileInfo_put(cfile, true, false);
}
_cifsFileInfo_put(cfile, true, false);
} else {
/* hard link on the defeered close file */
rc = cifs_get_hardlink_path(tcon, inode, file);

View File

@ -851,9 +851,9 @@ static bool emit_cached_dirents(struct cached_dirents *cde,
}
static void update_cached_dirents_count(struct cached_dirents *cde,
struct dir_context *ctx)
struct file *file)
{
if (cde->ctx != ctx)
if (cde->file != file)
return;
if (cde->is_valid || cde->is_failed)
return;
@ -862,9 +862,9 @@ static void update_cached_dirents_count(struct cached_dirents *cde,
}
static void finished_cached_dirents_count(struct cached_dirents *cde,
struct dir_context *ctx)
struct dir_context *ctx, struct file *file)
{
if (cde->ctx != ctx)
if (cde->file != file)
return;
if (cde->is_valid || cde->is_failed)
return;
@ -877,11 +877,12 @@ static void finished_cached_dirents_count(struct cached_dirents *cde,
static void add_cached_dirent(struct cached_dirents *cde,
struct dir_context *ctx,
const char *name, int namelen,
struct cifs_fattr *fattr)
struct cifs_fattr *fattr,
struct file *file)
{
struct cached_dirent *de;
if (cde->ctx != ctx)
if (cde->file != file)
return;
if (cde->is_valid || cde->is_failed)
return;
@ -911,7 +912,8 @@ static void add_cached_dirent(struct cached_dirents *cde,
static bool cifs_dir_emit(struct dir_context *ctx,
const char *name, int namelen,
struct cifs_fattr *fattr,
struct cached_fid *cfid)
struct cached_fid *cfid,
struct file *file)
{
bool rc;
ino_t ino = cifs_uniqueid_to_ino_t(fattr->cf_uniqueid);
@ -923,7 +925,7 @@ static bool cifs_dir_emit(struct dir_context *ctx,
if (cfid) {
mutex_lock(&cfid->dirents.de_mutex);
add_cached_dirent(&cfid->dirents, ctx, name, namelen,
fattr);
fattr, file);
mutex_unlock(&cfid->dirents.de_mutex);
}
@ -1023,7 +1025,7 @@ static int cifs_filldir(char *find_entry, struct file *file,
cifs_prime_dcache(file_dentry(file), &name, &fattr);
return !cifs_dir_emit(ctx, name.name, name.len,
&fattr, cfid);
&fattr, cfid, file);
}
@ -1074,8 +1076,8 @@ int cifs_readdir(struct file *file, struct dir_context *ctx)
* we need to initialize scanning and storing the
* directory content.
*/
if (ctx->pos == 0 && cfid->dirents.ctx == NULL) {
cfid->dirents.ctx = ctx;
if (ctx->pos == 0 && cfid->dirents.file == NULL) {
cfid->dirents.file = file;
cfid->dirents.pos = 2;
}
/*
@ -1143,7 +1145,7 @@ int cifs_readdir(struct file *file, struct dir_context *ctx)
} else {
if (cfid) {
mutex_lock(&cfid->dirents.de_mutex);
finished_cached_dirents_count(&cfid->dirents, ctx);
finished_cached_dirents_count(&cfid->dirents, ctx, file);
mutex_unlock(&cfid->dirents.de_mutex);
}
cifs_dbg(FYI, "Could not find entry\n");
@ -1184,7 +1186,7 @@ int cifs_readdir(struct file *file, struct dir_context *ctx)
ctx->pos++;
if (cfid) {
mutex_lock(&cfid->dirents.de_mutex);
update_cached_dirents_count(&cfid->dirents, ctx);
update_cached_dirents_count(&cfid->dirents, file);
mutex_unlock(&cfid->dirents.de_mutex);
}