Skip to content

Commit d384cc1

Browse files
committed
smb: client: fix perf regression with deferred closes
jira LE-3557 Rebuild_History Non-Buildable kernel-5.14.0-570.26.1.el9_6 commit-author Paulo Alcantara <[email protected]> commit b64af6b Customer reported that one of their applications started failing to open files with STATUS_INSUFFICIENT_RESOURCES due to NetApp server hitting the maximum number of opens to same file that it would allow for a single client connection. It turned out the client was failing to reuse open handles with deferred closes because matching ->f_flags directly without masking off O_CREAT|O_EXCL|O_TRUNC bits first broke the comparision and then client ended up with thousands of deferred closes to same file. Those bits are already satisfied on the original open, so no need to check them against existing open handles. Reproducer: #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <pthread.h> #define NR_THREADS 4 #define NR_ITERATIONS 2500 #define TEST_FILE "/mnt/1/test/dir/foo" static char buf[64]; static void *worker(void *arg) { int i, j; int fd; for (i = 0; i < NR_ITERATIONS; i++) { fd = open(TEST_FILE, O_WRONLY|O_CREAT|O_APPEND, 0666); for (j = 0; j < 16; j++) write(fd, buf, sizeof(buf)); close(fd); } } int main(int argc, char *argv[]) { pthread_t t[NR_THREADS]; int fd; int i; fd = open(TEST_FILE, O_WRONLY|O_CREAT|O_TRUNC, 0666); close(fd); memset(buf, 'a', sizeof(buf)); for (i = 0; i < NR_THREADS; i++) pthread_create(&t[i], NULL, worker, NULL); for (i = 0; i < NR_THREADS; i++) pthread_join(t[i], NULL); return 0; } Before patch: $ mount.cifs //srv/share /mnt/1 -o ... $ mkdir -p /mnt/1/test/dir $ gcc repro.c && ./a.out ... number of opens: 1391 After patch: $ mount.cifs //srv/share /mnt/1 -o ... $ mkdir -p /mnt/1/test/dir $ gcc repro.c && ./a.out ... number of opens: 1 Cc: [email protected] Cc: David Howells <[email protected]> Cc: Jay Shin <[email protected]> Cc: Pierguido Lambri <[email protected]> Fixes: b8ea3b1 ("smb: enable reuse of deferred file handles for write operations") Acked-by: Shyam Prasad N <[email protected]> Signed-off-by: Paulo Alcantara (Red Hat) <[email protected]> Signed-off-by: Steve French <[email protected]> (cherry picked from commit b64af6b) Signed-off-by: Jonathan Maple <[email protected]>
1 parent 10ebde9 commit d384cc1

File tree

1 file changed

+6
-3
lines changed

1 file changed

+6
-3
lines changed

fs/smb/client/file.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -685,15 +685,18 @@ int cifs_open(struct inode *inode, struct file *file)
685685
rc = cifs_get_readable_path(tcon, full_path, &cfile);
686686
}
687687
if (rc == 0) {
688-
if (file->f_flags == cfile->f_flags) {
688+
unsigned int oflags = file->f_flags & ~(O_CREAT|O_EXCL|O_TRUNC);
689+
unsigned int cflags = cfile->f_flags & ~(O_CREAT|O_EXCL|O_TRUNC);
690+
691+
if (cifs_convert_flags(oflags, 0) == cifs_convert_flags(cflags, 0) &&
692+
(oflags & (O_SYNC|O_DIRECT)) == (cflags & (O_SYNC|O_DIRECT))) {
689693
file->private_data = cfile;
690694
spin_lock(&CIFS_I(inode)->deferred_lock);
691695
cifs_del_deferred_close(cfile);
692696
spin_unlock(&CIFS_I(inode)->deferred_lock);
693697
goto use_cache;
694-
} else {
695-
_cifsFileInfo_put(cfile, true, false);
696698
}
699+
_cifsFileInfo_put(cfile, true, false);
697700
} else {
698701
/* hard link on the defeered close file */
699702
rc = cifs_get_hardlink_path(tcon, inode, file);

0 commit comments

Comments
 (0)