From patchwork Sun Oct 4 23:37:03 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ronnie Sahlberg X-Patchwork-Id: 11815967 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 8379F13B2 for ; Sun, 4 Oct 2020 23:37:28 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 68C1A206C3 for ; Sun, 4 Oct 2020 23:37:28 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="ONdmO5FI" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1725846AbgJDXh2 (ORCPT ); Sun, 4 Oct 2020 19:37:28 -0400 Received: from us-smtp-delivery-124.mimecast.com ([63.128.21.124]:28125 "EHLO us-smtp-delivery-124.mimecast.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725838AbgJDXh2 (ORCPT ); Sun, 4 Oct 2020 19:37:28 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1601854646; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:in-reply-to:in-reply-to:references:references; bh=UkqRAdB0wpUIuXLers+tFvBNSTD/ZxG1lUcX/i6DpM8=; b=ONdmO5FIIJNfSAT9VazAiBQalQczfv7x0IJ3JgnmaRfYq/w5+TA2c1Ri88pBIY8Mq7jEiZ Z8SJm+lwOU5Sl5KrxUTOiCNKz2DVl1F0G3/hQMeeWMR7hibGtXbFgp+vKmNjKQPIwXlCVa gcTShqKqlo6+T8pLYSFMJbRKSAMB+Ms= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-540-bTq4k30BOpa6qLBoFJbtGQ-1; Sun, 04 Oct 2020 19:37:24 -0400 X-MC-Unique: bTq4k30BOpa6qLBoFJbtGQ-1 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 88D1D1074668; Sun, 4 Oct 2020 23:37:23 +0000 (UTC) Received: from test1103.test.redhat.com (vpn2-54-124.bne.redhat.com [10.64.54.124]) by smtp.corp.redhat.com (Postfix) with ESMTP id E1CE55C1BD; Sun, 4 Oct 2020 23:37:22 +0000 (UTC) From: Ronnie Sahlberg To: linux-cifs Cc: Steve French Subject: [PATCH 1/3] cifs: return cached_fid from open_shroot Date: Mon, 5 Oct 2020 09:37:03 +1000 Message-Id: <20201004233705.31436-2-lsahlber@redhat.com> In-Reply-To: <20201004233705.31436-1-lsahlber@redhat.com> References: <20201004233705.31436-1-lsahlber@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org Signed-off-by: Ronnie Sahlberg --- fs/cifs/smb2inode.c | 11 ++++++----- fs/cifs/smb2ops.c | 22 +++++++++++++++------- fs/cifs/smb2proto.h | 3 ++- 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c index eba01d0908dd..df6212e55e10 100644 --- a/fs/cifs/smb2inode.c +++ b/fs/cifs/smb2inode.c @@ -511,9 +511,9 @@ smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, int rc; struct smb2_file_all_info *smb2_data; __u32 create_options = 0; - struct cifs_fid fid; bool no_cached_open = tcon->nohandlecache; struct cifsFileInfo *cfile; + struct cached_fid *cfid = NULL; *adjust_tz = false; *symlink = false; @@ -525,7 +525,7 @@ smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, /* If it is a root and its handle is cached then use it */ if (!strlen(full_path) && !no_cached_open) { - rc = open_shroot(xid, tcon, cifs_sb, &fid); + rc = open_shroot(xid, tcon, cifs_sb, &cfid); if (rc) goto out; @@ -533,12 +533,13 @@ smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, move_smb2_info_to_cifs(data, &tcon->crfid.file_all_info); } else { - rc = SMB2_query_info(xid, tcon, fid.persistent_fid, - fid.volatile_fid, smb2_data); + rc = SMB2_query_info(xid, tcon, + cfid->fid->persistent_fid, + cfid->fid->volatile_fid, smb2_data); if (!rc) move_smb2_info_to_cifs(data, smb2_data); } - close_shroot(&tcon->crfid); + close_shroot(cfid); goto out; } diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 32f90dc82c84..fd6c136066df 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -651,7 +651,8 @@ smb2_cached_lease_break(struct work_struct *work) * Open the directory at the root of a share */ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, - struct cifs_sb_info *cifs_sb, struct cifs_fid *pfid) + struct cifs_sb_info *cifs_sb, + struct cached_fid **cfid) { struct cifs_ses *ses = tcon->ses; struct TCP_Server_Info *server = ses->server; @@ -666,11 +667,12 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, int rc, flags = 0; __le16 utf16_path = 0; /* Null - since an open of top of share */ u8 oplock = SMB2_OPLOCK_LEVEL_II; + struct cifs_fid *pfid; mutex_lock(&tcon->crfid.fid_mutex); if (tcon->crfid.is_valid) { cifs_dbg(FYI, "found a cached root file handle\n"); - memcpy(pfid, tcon->crfid.fid, sizeof(struct cifs_fid)); + *cfid = &tcon->crfid; kref_get(&tcon->crfid.refcount); mutex_unlock(&tcon->crfid.fid_mutex); return 0; @@ -691,6 +693,7 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, if (!server->ops->new_lease_key) return -EIO; + pfid = tcon->crfid.fid; server->ops->new_lease_key(pfid); memset(rqst, 0, sizeof(rqst)); @@ -820,6 +823,8 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, SMB2_query_info_free(&rqst[1]); free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base); free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base); + if (rc == 0) + *cfid = &tcon->crfid; return rc; } @@ -833,6 +838,7 @@ smb3_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon, struct cifs_open_parms oparms; struct cifs_fid fid; bool no_cached_open = tcon->nohandlecache; + struct cached_fid *cfid = NULL; oparms.tcon = tcon; oparms.desired_access = FILE_READ_ATTRIBUTES; @@ -841,12 +847,14 @@ smb3_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon, oparms.fid = &fid; oparms.reconnect = false; - if (no_cached_open) + if (no_cached_open) { rc = SMB2_open(xid, &oparms, &srch_path, &oplock, NULL, NULL, NULL, NULL); - else - rc = open_shroot(xid, tcon, cifs_sb, &fid); - + } else { + rc = open_shroot(xid, tcon, cifs_sb, &cfid); + if (rc == 0) + memcpy(&fid, cfid->fid, sizeof(struct cifs_fid)); + } if (rc) return; @@ -863,7 +871,7 @@ smb3_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon, if (no_cached_open) SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid); else - close_shroot(&tcon->crfid); + close_shroot(cfid); } static void diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index 2f8ecbf54214..67c50d78caa1 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h @@ -70,7 +70,8 @@ extern int smb3_handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid); extern int open_shroot(unsigned int xid, struct cifs_tcon *tcon, - struct cifs_sb_info *cifs_sb, struct cifs_fid *pfid); + struct cifs_sb_info *cifs_sb, + struct cached_fid **cfid); extern void close_shroot(struct cached_fid *cfid); extern void close_shroot_lease(struct cached_fid *cfid); extern void close_shroot_lease_locked(struct cached_fid *cfid); From patchwork Sun Oct 4 23:37:04 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ronnie Sahlberg X-Patchwork-Id: 11815965 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 1A33F13B2 for ; Sun, 4 Oct 2020 23:37:26 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id F0459206B6 for ; Sun, 4 Oct 2020 23:37:25 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="b4jDB7Q4" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1725836AbgJDXhZ (ORCPT ); Sun, 4 Oct 2020 19:37:25 -0400 Received: from us-smtp-delivery-124.mimecast.com ([216.205.24.124]:55302 "EHLO us-smtp-delivery-124.mimecast.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725838AbgJDXhZ (ORCPT ); Sun, 4 Oct 2020 19:37:25 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1601854644; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:in-reply-to:in-reply-to:references:references; bh=LSeRlQfK32FKryUo3y0Clt3/kQxkCj0X061YOS5hAXU=; b=b4jDB7Q4CtkDrNQnVspcqI8Y8gSx8VIfYqMx9G4y2O96WH1i/iNO5JDtLQaCNLrQ7gH+n7 PyU1UpTt97Ot1q1K8++ZSMdu5SOXug0sjYGnB0t/HkrJHAq7WI231zqF7ZJPLt9XPcHZd+ 2bUYh0S9ey5LtmG7xDYqvpPQPP6SbXk= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-225-dzvf9Ss_PPeN_ZQgG-DCIQ-1; Sun, 04 Oct 2020 19:37:22 -0400 X-MC-Unique: dzvf9Ss_PPeN_ZQgG-DCIQ-1 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 1A074185A0F0; Sun, 4 Oct 2020 23:37:21 +0000 (UTC) Received: from test1103.test.redhat.com (vpn2-54-124.bne.redhat.com [10.64.54.124]) by smtp.corp.redhat.com (Postfix) with ESMTP id 6FC225D9CC; Sun, 4 Oct 2020 23:37:20 +0000 (UTC) From: Ronnie Sahlberg To: linux-cifs Cc: Steve French Subject: [PATCH 2/3] cifs: compute full_path already in cifs_readdir() Date: Mon, 5 Oct 2020 09:37:04 +1000 Message-Id: <20201004233705.31436-3-lsahlber@redhat.com> In-Reply-To: <20201004233705.31436-1-lsahlber@redhat.com> References: <20201004233705.31436-1-lsahlber@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org Signed-off-by: Ronnie Sahlberg --- fs/cifs/readdir.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 6df0922e7e30..31a18aae5e64 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -360,11 +360,11 @@ int get_symlink_reparse_path(char *full_path, struct cifs_sb_info *cifs_sb, */ static int -initiate_cifs_search(const unsigned int xid, struct file *file) +initiate_cifs_search(const unsigned int xid, struct file *file, + char *full_path) { __u16 search_flags; int rc = 0; - char *full_path = NULL; struct cifsFileInfo *cifsFile; struct cifs_sb_info *cifs_sb = CIFS_FILE_SB(file); struct tcon_link *tlink = NULL; @@ -400,12 +400,6 @@ initiate_cifs_search(const unsigned int xid, struct file *file) cifsFile->invalidHandle = true; cifsFile->srch_inf.endOfSearch = false; - full_path = build_path_from_dentry(file_dentry(file)); - if (full_path == NULL) { - rc = -ENOMEM; - goto error_exit; - } - cifs_dbg(FYI, "Full path: %s start at: %lld\n", full_path, file->f_pos); ffirst_retry: @@ -444,7 +438,6 @@ initiate_cifs_search(const unsigned int xid, struct file *file) goto ffirst_retry; } error_exit: - kfree(full_path); cifs_put_tlink(tlink); return rc; } @@ -688,7 +681,8 @@ static int cifs_save_resume_key(const char *current_entry, */ static int find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon, loff_t pos, - struct file *file, char **current_entry, int *num_to_ret) + struct file *file, char *full_path, + char **current_entry, int *num_to_ret) { __u16 search_flags; int rc = 0; @@ -741,7 +735,7 @@ find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon, loff_t pos, ntwrk_buf_start); cfile->srch_inf.ntwrk_buf_start = NULL; } - rc = initiate_cifs_search(xid, file); + rc = initiate_cifs_search(xid, file, full_path); if (rc) { cifs_dbg(FYI, "error %d reinitiating a search on rewind\n", rc); @@ -925,15 +919,22 @@ int cifs_readdir(struct file *file, struct dir_context *ctx) char *tmp_buf = NULL; char *end_of_smb; unsigned int max_len; + char *full_path = NULL; xid = get_xid(); + full_path = build_path_from_dentry(file_dentry(file)); + if (full_path == NULL) { + rc = -ENOMEM; + goto rddir2_exit; + } + /* * Ensure FindFirst doesn't fail before doing filldir() for '.' and * '..'. Otherwise we won't be able to notify VFS in case of failure. */ if (file->private_data == NULL) { - rc = initiate_cifs_search(xid, file); + rc = initiate_cifs_search(xid, file, full_path); cifs_dbg(FYI, "initiate cifs search rc %d\n", rc); if (rc) goto rddir2_exit; @@ -960,8 +961,8 @@ int cifs_readdir(struct file *file, struct dir_context *ctx) } */ tcon = tlink_tcon(cifsFile->tlink); - rc = find_cifs_entry(xid, tcon, ctx->pos, file, ¤t_entry, - &num_to_fill); + rc = find_cifs_entry(xid, tcon, ctx->pos, file, full_path, + ¤t_entry, &num_to_fill); if (rc) { cifs_dbg(FYI, "fce error %d\n", rc); goto rddir2_exit; @@ -1019,6 +1020,7 @@ int cifs_readdir(struct file *file, struct dir_context *ctx) kfree(tmp_buf); rddir2_exit: + kfree(full_path); free_xid(xid); return rc; } From patchwork Sun Oct 4 23:37:05 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ronnie Sahlberg X-Patchwork-Id: 11815963 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 29D7392C for ; Sun, 4 Oct 2020 23:37:25 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id EB9A2206C3 for ; Sun, 4 Oct 2020 23:37:24 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="J90U6z8G" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1725845AbgJDXhY (ORCPT ); Sun, 4 Oct 2020 19:37:24 -0400 Received: from us-smtp-delivery-124.mimecast.com ([216.205.24.124]:30167 "EHLO us-smtp-delivery-124.mimecast.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725836AbgJDXhY (ORCPT ); Sun, 4 Oct 2020 19:37:24 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1601854641; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:in-reply-to:in-reply-to:references:references; bh=UEz4yLeifELr3trT5z5ptz+vSv1npUQj/a7rtr+rvOE=; b=J90U6z8G2u8aUS/PL4QULhUfiN1vhtMbfggyaRXgqUUZZLFcG5fsLNCRRqWEK3zklDBlnP GLwwmldkTVcI7gGycTlhsyd5AFGQFYx0qWn8bKGoGsvOTGuE+epMQw9fYoN9NeNy2aaF25 7+noF05cuBsR6mxMonfC/PH9U11Mf0E= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-381-wt_dbbncMFyGmO7WnhhLwQ-1; Sun, 04 Oct 2020 19:37:18 -0400 X-MC-Unique: wt_dbbncMFyGmO7WnhhLwQ-1 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 821C7801ADB; Sun, 4 Oct 2020 23:37:17 +0000 (UTC) Received: from test1103.test.redhat.com (vpn2-54-124.bne.redhat.com [10.64.54.124]) by smtp.corp.redhat.com (Postfix) with ESMTP id D853819D7C; Sun, 4 Oct 2020 23:37:16 +0000 (UTC) From: Ronnie Sahlberg To: linux-cifs Cc: Steve French Subject: [PATCH 3/3] cifs: cache the directory content for shroot Date: Mon, 5 Oct 2020 09:37:05 +1000 Message-Id: <20201004233705.31436-4-lsahlber@redhat.com> In-Reply-To: <20201004233705.31436-1-lsahlber@redhat.com> References: <20201004233705.31436-1-lsahlber@redhat.com> X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org Add caching of the directory content for the shroot. Populate the cache during the initial scan in readdir() and then try to serve out of the cache for subsequent scans. Signed-off-by: Ronnie Sahlberg --- fs/cifs/cifsglob.h | 22 +++++++ fs/cifs/misc.c | 2 + fs/cifs/readdir.c | 169 ++++++++++++++++++++++++++++++++++++++++++++++++++--- fs/cifs/smb2ops.c | 14 +++++ 4 files changed, 200 insertions(+), 7 deletions(-) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index b565d83ba89e..487e6de80e47 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -1073,6 +1073,27 @@ cap_unix(struct cifs_ses *ses) return ses->server->vals->cap_unix & ses->capabilities; } +struct cached_dirent { + struct list_head entry; + char *name; + int namelen; + loff_t pos; + u64 ino; + unsigned type; +}; + +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 mutex de_mutex; + int pos; /* Expected ctx->pos */ + struct list_head entries; +}; + struct cached_fid { bool is_valid:1; /* Do we have a useable root fid */ bool file_all_info_is_valid:1; @@ -1083,6 +1104,7 @@ struct cached_fid { struct cifs_tcon *tcon; struct work_struct lease_break; struct smb2_file_all_info file_all_info; + struct cached_dirents dirents; }; /* diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 1c14cf01dbef..a106bd3cc20b 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -124,6 +124,8 @@ tconInfoAlloc(void) kfree(ret_buf); return NULL; } + INIT_LIST_HEAD(&ret_buf->crfid.dirents.entries); + mutex_init(&ret_buf->crfid.dirents.de_mutex); atomic_inc(&tconInfoAllocCount); ret_buf->tidStatus = CifsNew; diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 31a18aae5e64..10b651e585fc 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -811,9 +811,110 @@ find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon, loff_t pos, return rc; } +static bool emit_cached_dirents(struct cached_dirents *cde, + struct dir_context *ctx) +{ + struct list_head *tmp; + struct cached_dirent *dirent; + int rc; + + list_for_each(tmp, &cde->entries) { + dirent = list_entry(tmp, struct cached_dirent, entry); + if (ctx->pos >= dirent->pos) + continue; + ctx->pos = dirent->pos; + rc = dir_emit(ctx, dirent->name, dirent->namelen, + dirent->ino, dirent->type); + if (!rc) + return rc; + } + return true; +} + +static void update_cached_dirents_count(struct cached_dirents *cde, + struct dir_context *ctx) +{ + if (cde->ctx != ctx) + return; + if (cde->is_valid || cde->is_failed) + return; + + cde->pos++; +} + +static void finished_cached_dirents_count(struct cached_dirents *cde, + struct dir_context *ctx) +{ + if (cde->ctx != ctx) + return; + if (cde->is_valid || cde->is_failed) + return; + if (ctx->pos != cde->pos) + return; + + cde->is_valid = 1; +} + +static void add_cached_dirent(struct cached_dirents *cde, + struct dir_context *ctx, + const char *name, int namelen, + u64 ino, unsigned type) +{ + struct cached_dirent *de; + + if (cde->ctx != ctx) + return; + if (cde->is_valid || cde->is_failed) + return; + if (ctx->pos != cde->pos) { + cde->is_failed = 1; + return; + } + de = kzalloc(sizeof(*de), GFP_ATOMIC); + if (de == NULL) { + cde->is_failed = 1; + return; + } + de->name = kzalloc(namelen, GFP_ATOMIC); + if (de->name == NULL) { + kfree(de); + cde->is_failed = 1; + return; + } + memcpy(de->name, name, namelen); + de->namelen = namelen; + de->pos = ctx->pos; + de->ino = ino; + de->type = type; + + list_add_tail(&de->entry, &cde->entries); +} + +static bool cifs_dir_emit(struct dir_context *ctx, + const char *name, int namelen, + u64 ino, unsigned type, + struct cached_fid *cfid) +{ + bool rc; + + rc = dir_emit(ctx, name, namelen, ino, type); + if (!rc) + return rc; + + if (cfid) { + mutex_lock(&cfid->dirents.de_mutex); + add_cached_dirent(&cfid->dirents, ctx, name, namelen, ino, + type); + mutex_unlock(&cfid->dirents.de_mutex); + } + + return rc; +} + static int cifs_filldir(char *find_entry, struct file *file, - struct dir_context *ctx, - char *scratch_buf, unsigned int max_len) + struct dir_context *ctx, + char *scratch_buf, unsigned int max_len, + struct cached_fid *cfid) { struct cifsFileInfo *file_info = file->private_data; struct super_block *sb = file_inode(file)->i_sb; @@ -903,10 +1004,10 @@ static int cifs_filldir(char *find_entry, struct file *file, cifs_prime_dcache(file_dentry(file), &name, &fattr); ino = cifs_uniqueid_to_ino_t(fattr.cf_uniqueid); - return !dir_emit(ctx, name.name, name.len, ino, fattr.cf_dtype); + return !cifs_dir_emit(ctx, name.name, name.len, ino, fattr.cf_dtype, + cfid); } - int cifs_readdir(struct file *file, struct dir_context *ctx) { int rc = 0; @@ -920,6 +1021,8 @@ int cifs_readdir(struct file *file, struct dir_context *ctx) char *end_of_smb; unsigned int max_len; char *full_path = NULL; + struct cached_fid *cfid = NULL; + struct cifs_sb_info *cifs_sb = CIFS_FILE_SB(file); xid = get_xid(); @@ -928,7 +1031,6 @@ int cifs_readdir(struct file *file, struct dir_context *ctx) rc = -ENOMEM; goto rddir2_exit; } - /* * Ensure FindFirst doesn't fail before doing filldir() for '.' and * '..'. Otherwise we won't be able to notify VFS in case of failure. @@ -949,6 +1051,37 @@ int cifs_readdir(struct file *file, struct dir_context *ctx) if after then keep searching till find it */ cifsFile = file->private_data; + tcon = tlink_tcon(cifsFile->tlink); + if (!is_smb1_server(tcon->ses->server) && !strcmp(full_path, "")) { + rc = open_shroot(xid, tcon, cifs_sb, &cfid); + if (rc) + goto cache_not_found; + + mutex_lock(&cfid->dirents.de_mutex); + /* + * If this was reading from the start of the directory + * we need to initialize scanning and storing the + * directory content. + * We check for pos == 2 because we have already emitted + * '.' and '..' above in dir_emit_dots() + */ + if (ctx->pos == 2 && cfid->dirents.ctx == NULL) { + cfid->dirents.ctx = ctx; + cfid->dirents.pos = 2; + } + /* + * If we already have the entire directory cached then + * we cna just serve the cache. + */ + if (cfid->dirents.is_valid) { + emit_cached_dirents(&cfid->dirents, ctx); + mutex_unlock(&cfid->dirents.de_mutex); + goto rddir2_exit; + } + mutex_unlock(&cfid->dirents.de_mutex); + } + cache_not_found: + if (cifsFile->srch_inf.endOfSearch) { if (cifsFile->srch_inf.emptyDir) { cifs_dbg(FYI, "End of search, empty dir\n"); @@ -960,15 +1093,29 @@ int cifs_readdir(struct file *file, struct dir_context *ctx) tcon->ses->server->close(xid, tcon, &cifsFile->fid); } */ - tcon = tlink_tcon(cifsFile->tlink); + /* Drop the cache while calling find_cifs_entry in case there will + * be reconnects during query_directory. + */ + if (cfid) { + close_shroot(cfid); + cfid = NULL; + } rc = find_cifs_entry(xid, tcon, ctx->pos, file, full_path, ¤t_entry, &num_to_fill); + if (!is_smb1_server(tcon->ses->server) && !strcmp(full_path, "")) { + open_shroot(xid, tcon, cifs_sb, &cfid); + } if (rc) { cifs_dbg(FYI, "fce error %d\n", rc); goto rddir2_exit; } else if (current_entry != NULL) { cifs_dbg(FYI, "entry %lld found\n", ctx->pos); } else { + if (cfid) { + mutex_lock(&cfid->dirents.de_mutex); + finished_cached_dirents_count(&cfid->dirents, ctx); + mutex_unlock(&cfid->dirents.de_mutex); + } cifs_dbg(FYI, "Could not find entry\n"); goto rddir2_exit; } @@ -998,7 +1145,7 @@ int cifs_readdir(struct file *file, struct dir_context *ctx) */ *tmp_buf = 0; rc = cifs_filldir(current_entry, file, ctx, - tmp_buf, max_len); + tmp_buf, max_len, cfid); if (rc) { if (rc > 0) rc = 0; @@ -1006,6 +1153,12 @@ 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); + mutex_unlock(&cfid->dirents.de_mutex); + } + if (ctx->pos == cifsFile->srch_inf.index_of_last_entry) { cifs_dbg(FYI, "last entry in buf at pos %lld %s\n", @@ -1020,6 +1173,8 @@ int cifs_readdir(struct file *file, struct dir_context *ctx) kfree(tmp_buf); rddir2_exit: + if (cfid) + close_shroot(cfid); kfree(full_path); free_xid(xid); return rc; diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index fd6c136066df..280464e21a5f 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -605,6 +605,8 @@ smb2_close_cached_fid(struct kref *ref) { struct cached_fid *cfid = container_of(ref, struct cached_fid, refcount); + struct list_head *pos, *q; + struct cached_dirent *dirent; if (cfid->is_valid) { cifs_dbg(FYI, "clear cached root file handle\n"); @@ -613,6 +615,18 @@ smb2_close_cached_fid(struct kref *ref) cfid->is_valid = false; cfid->file_all_info_is_valid = false; cfid->has_lease = false; + mutex_lock(&cfid->dirents.de_mutex); + list_for_each_safe(pos, q, &cfid->dirents.entries) { + dirent = list_entry(pos, struct cached_dirent, entry); + list_del(pos); + kfree(dirent->name); + kfree(dirent); + } + cfid->dirents.is_valid = 0; + cfid->dirents.is_failed = 0; + cfid->dirents.ctx = NULL; + cfid->dirents.pos = 0; + mutex_unlock(&cfid->dirents.de_mutex); } }