From patchwork Tue Aug 9 02:11:48 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ronnie Sahlberg X-Patchwork-Id: 12939283 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3EA5BC00140 for ; Tue, 9 Aug 2022 02:12:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229578AbiHICMW (ORCPT ); Mon, 8 Aug 2022 22:12:22 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57260 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229561AbiHICMV (ORCPT ); Mon, 8 Aug 2022 22:12:21 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 4A3AB18B09 for ; Mon, 8 Aug 2022 19:12:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1660011138; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=r+8lW8efHUVOfrYWlrYV/fUF0TEjHSh3+LTLMIgpMo0=; b=Q6GBbSySFK2yvVC2wC7wWWwUfZUeMTZJ5xbs4UtUzrcSPn6h5ArJgJWBx5vSoAiIaxGc2O bRIFEw+JDvPGCoZAjE39g0fUvvX9GmL0Yj+fQ6GCZpPc0L97czryviCMPQ2CZlyzWdc21v kORb6sotkiCv6f2QbHEU+fHlrXaObnA= Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-516-ZswrbrXRNPu_onaRv_gA_A-1; Mon, 08 Aug 2022 22:12:15 -0400 X-MC-Unique: ZswrbrXRNPu_onaRv_gA_A-1 Received: from smtp.corp.redhat.com (int-mx10.intmail.prod.int.rdu2.redhat.com [10.11.54.10]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id BA0543C0D191; Tue, 9 Aug 2022 02:12:14 +0000 (UTC) Received: from localhost.localdomain (vpn2-52-16.bne.redhat.com [10.64.52.16]) by smtp.corp.redhat.com (Postfix) with ESMTP id 3740D403178; Tue, 9 Aug 2022 02:12:12 +0000 (UTC) From: Ronnie Sahlberg To: linux-cifs Cc: Steve French , Ronnie Sahlberg Subject: [PATCH 1/9] cifs: Move cached-dir functions into a separate file Date: Tue, 9 Aug 2022 12:11:48 +1000 Message-Id: <20220809021156.3086869-2-lsahlber@redhat.com> In-Reply-To: <20220809021156.3086869-1-lsahlber@redhat.com> References: <20220809021156.3086869-1-lsahlber@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.85 on 10.11.54.10 Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org Also rename crfid to cfid to have consistent naming for this variable. This commit does not change any logic. Signed-off-by: Ronnie Sahlberg Reviewed-by: Paulo Alcantara (SUSE) --- fs/cifs/Makefile | 2 +- fs/cifs/cached_dir.c | 363 +++++++++++++++++++++++++++++++++++++++++++ fs/cifs/cached_dir.h | 26 ++++ fs/cifs/cifsfs.c | 20 +-- fs/cifs/cifsglob.h | 2 +- fs/cifs/cifsproto.h | 1 - fs/cifs/cifssmb.c | 8 +- fs/cifs/inode.c | 1 + fs/cifs/misc.c | 12 +- fs/cifs/readdir.c | 1 + fs/cifs/smb2inode.c | 5 +- fs/cifs/smb2misc.c | 13 +- fs/cifs/smb2ops.c | 297 +---------------------------------- fs/cifs/smb2pdu.c | 3 +- fs/cifs/smb2proto.h | 10 -- 15 files changed, 412 insertions(+), 352 deletions(-) create mode 100644 fs/cifs/cached_dir.c create mode 100644 fs/cifs/cached_dir.h diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile index 8c9f2c00be72..343a59e0d64d 100644 --- a/fs/cifs/Makefile +++ b/fs/cifs/Makefile @@ -7,7 +7,7 @@ obj-$(CONFIG_CIFS) += cifs.o cifs-y := trace.o cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o \ inode.o link.o misc.o netmisc.o smbencrypt.o transport.o \ - cifs_unicode.o nterr.o cifsencrypt.o \ + cached_dir.o cifs_unicode.o nterr.o cifsencrypt.o \ readdir.o ioctl.o sess.o export.o unc.o winucase.o \ smb2ops.o smb2maperror.o smb2transport.o \ smb2misc.o smb2pdu.o smb2inode.o smb2file.o cifsacl.o fs_context.o \ diff --git a/fs/cifs/cached_dir.c b/fs/cifs/cached_dir.c new file mode 100644 index 000000000000..f2e17c1d5196 --- /dev/null +++ b/fs/cifs/cached_dir.c @@ -0,0 +1,363 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Functions to handle the cached directory entries + * + * Copyright (c) 2022, Ronnie Sahlberg + */ + +#include "cifsglob.h" +#include "cifsproto.h" +#include "cifs_debug.h" +#include "smb2proto.h" +#include "cached_dir.h" + +/* + * Open the and cache a directory handle. + * If error then *cfid is not initialized. + */ +int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, + const char *path, + struct cifs_sb_info *cifs_sb, + struct cached_fid **cfid) +{ + struct cifs_ses *ses; + struct TCP_Server_Info *server; + struct cifs_open_parms oparms; + struct smb2_create_rsp *o_rsp = NULL; + struct smb2_query_info_rsp *qi_rsp = NULL; + int resp_buftype[2]; + struct smb_rqst rqst[2]; + struct kvec rsp_iov[2]; + struct kvec open_iov[SMB2_CREATE_IOV_SIZE]; + struct kvec qi_iov[1]; + 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; + struct dentry *dentry; + + if (tcon == NULL || tcon->nohandlecache || + is_smb1_server(tcon->ses->server)) + return -ENOTSUPP; + + ses = tcon->ses; + server = ses->server; + + if (cifs_sb->root == NULL) + return -ENOENT; + + if (strlen(path)) + return -ENOENT; + + dentry = cifs_sb->root; + + mutex_lock(&tcon->cfid.fid_mutex); + if (tcon->cfid.is_valid) { + cifs_dbg(FYI, "found a cached root file handle\n"); + *cfid = &tcon->cfid; + kref_get(&tcon->cfid.refcount); + mutex_unlock(&tcon->cfid.fid_mutex); + return 0; + } + + /* + * We do not hold the lock for the open because in case + * SMB2_open needs to reconnect, it will end up calling + * cifs_mark_open_files_invalid() which takes the lock again + * thus causing a deadlock + */ + + mutex_unlock(&tcon->cfid.fid_mutex); + + if (smb3_encryption_required(tcon)) + flags |= CIFS_TRANSFORM_REQ; + + if (!server->ops->new_lease_key) + return -EIO; + + pfid = tcon->cfid.fid; + server->ops->new_lease_key(pfid); + + memset(rqst, 0, sizeof(rqst)); + resp_buftype[0] = resp_buftype[1] = CIFS_NO_BUFFER; + memset(rsp_iov, 0, sizeof(rsp_iov)); + + /* Open */ + memset(&open_iov, 0, sizeof(open_iov)); + rqst[0].rq_iov = open_iov; + rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE; + + oparms.tcon = tcon; + oparms.create_options = cifs_create_options(cifs_sb, CREATE_NOT_FILE); + oparms.desired_access = FILE_READ_ATTRIBUTES; + oparms.disposition = FILE_OPEN; + oparms.fid = pfid; + oparms.reconnect = false; + + rc = SMB2_open_init(tcon, server, + &rqst[0], &oplock, &oparms, &utf16_path); + if (rc) + goto oshr_free; + smb2_set_next_command(tcon, &rqst[0]); + + memset(&qi_iov, 0, sizeof(qi_iov)); + rqst[1].rq_iov = qi_iov; + rqst[1].rq_nvec = 1; + + rc = SMB2_query_info_init(tcon, server, + &rqst[1], COMPOUND_FID, + COMPOUND_FID, FILE_ALL_INFORMATION, + SMB2_O_INFO_FILE, 0, + sizeof(struct smb2_file_all_info) + + PATH_MAX * 2, 0, NULL); + if (rc) + goto oshr_free; + + smb2_set_related(&rqst[1]); + + rc = compound_send_recv(xid, ses, server, + flags, 2, rqst, + resp_buftype, rsp_iov); + mutex_lock(&tcon->cfid.fid_mutex); + + /* + * Now we need to check again as the cached root might have + * been successfully re-opened from a concurrent process + */ + + if (tcon->cfid.is_valid) { + /* work was already done */ + + /* stash fids for close() later */ + struct cifs_fid fid = { + .persistent_fid = pfid->persistent_fid, + .volatile_fid = pfid->volatile_fid, + }; + + /* + * caller expects this func to set the fid in cfid to valid + * cached root, so increment the refcount. + */ + kref_get(&tcon->cfid.refcount); + + mutex_unlock(&tcon->cfid.fid_mutex); + + if (rc == 0) { + /* close extra handle outside of crit sec */ + SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid); + } + rc = 0; + goto oshr_free; + } + + /* Cached root is still invalid, continue normaly */ + + if (rc) { + if (rc == -EREMCHG) { + tcon->need_reconnect = true; + pr_warn_once("server share %s deleted\n", + tcon->treeName); + } + goto oshr_exit; + } + + atomic_inc(&tcon->num_remote_opens); + + o_rsp = (struct smb2_create_rsp *)rsp_iov[0].iov_base; + oparms.fid->persistent_fid = o_rsp->PersistentFileId; + oparms.fid->volatile_fid = o_rsp->VolatileFileId; +#ifdef CONFIG_CIFS_DEBUG2 + oparms.fid->mid = le64_to_cpu(o_rsp->hdr.MessageId); +#endif /* CIFS_DEBUG2 */ + + tcon->cfid.tcon = tcon; + tcon->cfid.is_valid = true; + tcon->cfid.dentry = dentry; + dget(dentry); + kref_init(&tcon->cfid.refcount); + + /* BB TBD check to see if oplock level check can be removed below */ + if (o_rsp->OplockLevel == SMB2_OPLOCK_LEVEL_LEASE) { + /* + * See commit 2f94a3125b87. Increment the refcount when we + * get a lease for root, release it if lease break occurs + */ + kref_get(&tcon->cfid.refcount); + tcon->cfid.has_lease = true; + smb2_parse_contexts(server, o_rsp, + &oparms.fid->epoch, + oparms.fid->lease_key, &oplock, + NULL, NULL); + } else + goto oshr_exit; + + qi_rsp = (struct smb2_query_info_rsp *)rsp_iov[1].iov_base; + if (le32_to_cpu(qi_rsp->OutputBufferLength) < sizeof(struct smb2_file_all_info)) + goto oshr_exit; + if (!smb2_validate_and_copy_iov( + le16_to_cpu(qi_rsp->OutputBufferOffset), + sizeof(struct smb2_file_all_info), + &rsp_iov[1], sizeof(struct smb2_file_all_info), + (char *)&tcon->cfid.file_all_info)) + tcon->cfid.file_all_info_is_valid = true; + tcon->cfid.time = jiffies; + + +oshr_exit: + mutex_unlock(&tcon->cfid.fid_mutex); +oshr_free: + SMB2_open_free(&rqst[0]); + 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->cfid; +} + return rc; +} + +int open_cached_dir_by_dentry(struct cifs_tcon *tcon, + struct dentry *dentry, + struct cached_fid **cfid) +{ + mutex_lock(&tcon->cfid.fid_mutex); + if (tcon->cfid.dentry == dentry) { + cifs_dbg(FYI, "found a cached root file handle by dentry\n"); + *cfid = &tcon->cfid; + kref_get(&tcon->cfid.refcount); + mutex_unlock(&tcon->cfid.fid_mutex); + return 0; + } + mutex_unlock(&tcon->cfid.fid_mutex); + return -ENOENT; +} + +static void +smb2_close_cached_fid(struct kref *ref) +{ + struct cached_fid *cfid = container_of(ref, struct cached_fid, + refcount); + struct cached_dirent *dirent, *q; + + if (cfid->is_valid) { + cifs_dbg(FYI, "clear cached root file handle\n"); + SMB2_close(0, cfid->tcon, cfid->fid->persistent_fid, + cfid->fid->volatile_fid); + } + + /* + * We only check validity above to send SMB2_close, + * but we still need to invalidate these entries + * when this function is called + */ + cfid->is_valid = false; + cfid->file_all_info_is_valid = false; + cfid->has_lease = false; + if (cfid->dentry) { + dput(cfid->dentry); + cfid->dentry = NULL; + } + /* + * Delete all cached dirent names + */ + mutex_lock(&cfid->dirents.de_mutex); + list_for_each_entry_safe(dirent, q, &cfid->dirents.entries, entry) { + list_del(&dirent->entry); + 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); + +} + +void close_cached_dir(struct cached_fid *cfid) +{ + mutex_lock(&cfid->fid_mutex); + kref_put(&cfid->refcount, smb2_close_cached_fid); + mutex_unlock(&cfid->fid_mutex); +} + +void close_cached_dir_lease_locked(struct cached_fid *cfid) +{ + if (cfid->has_lease) { + cfid->has_lease = false; + kref_put(&cfid->refcount, smb2_close_cached_fid); + } +} + +void close_cached_dir_lease(struct cached_fid *cfid) +{ + mutex_lock(&cfid->fid_mutex); + close_cached_dir_lease_locked(cfid); + mutex_unlock(&cfid->fid_mutex); +} + +/* + * Called from cifs_kill_sb when we unmount a share + */ +void close_all_cached_dirs(struct cifs_sb_info *cifs_sb) +{ + struct rb_root *root = &cifs_sb->tlink_tree; + struct rb_node *node; + struct cached_fid *cfid; + struct cifs_tcon *tcon; + struct tcon_link *tlink; + + for (node = rb_first(root); node; node = rb_next(node)) { + tlink = rb_entry(node, struct tcon_link, tl_rbnode); + tcon = tlink_tcon(tlink); + if (IS_ERR(tcon)) + continue; + cfid = &tcon->cfid; + mutex_lock(&cfid->fid_mutex); + if (cfid->dentry) { + dput(cfid->dentry); + cfid->dentry = NULL; + } + mutex_unlock(&cfid->fid_mutex); + } +} + +/* + * Invalidate and close all cached dirs when a TCON has been reset + * due to a session loss. + */ +void invalidate_all_cached_dirs(struct cifs_tcon *tcon) +{ + mutex_lock(&tcon->cfid.fid_mutex); + tcon->cfid.is_valid = false; + /* cached handle is not valid, so SMB2_CLOSE won't be sent below */ + close_cached_dir_lease_locked(&tcon->cfid); + memset(tcon->cfid.fid, 0, sizeof(struct cifs_fid)); + mutex_unlock(&tcon->cfid.fid_mutex); +} + +static void +smb2_cached_lease_break(struct work_struct *work) +{ + struct cached_fid *cfid = container_of(work, + struct cached_fid, lease_break); + + close_cached_dir_lease(cfid); +} + +int cached_dir_lease_break(struct cifs_tcon *tcon, __u8 lease_key[16]) +{ + if (tcon->cfid.is_valid && + !memcmp(lease_key, + tcon->cfid.fid->lease_key, + SMB2_LEASE_KEY_SIZE)) { + tcon->cfid.time = 0; + INIT_WORK(&tcon->cfid.lease_break, + smb2_cached_lease_break); + queue_work(cifsiod_wq, + &tcon->cfid.lease_break); + spin_unlock(&cifs_tcp_ses_lock); + return true; + } + return false; +} diff --git a/fs/cifs/cached_dir.h b/fs/cifs/cached_dir.h new file mode 100644 index 000000000000..3731c755eea5 --- /dev/null +++ b/fs/cifs/cached_dir.h @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Functions to handle the cached directory entries + * + * Copyright (c) 2022, Ronnie Sahlberg + */ + +#ifndef _CACHED_DIR_H +#define _CACHED_DIR_H + + +extern int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, + const char *path, + struct cifs_sb_info *cifs_sb, + 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 close_cached_dir_lease(struct cached_fid *cfid); +extern void close_cached_dir_lease_locked(struct cached_fid *cfid); +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 */ diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index f909d9e9faaa..615fbe2bff3c 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -46,6 +46,7 @@ #include "netlink.h" #endif #include "fs_context.h" +#include "cached_dir.h" /* * DOS dates from 1980/1/1 through 2107/12/31 @@ -264,30 +265,13 @@ cifs_read_super(struct super_block *sb) static void cifs_kill_sb(struct super_block *sb) { struct cifs_sb_info *cifs_sb = CIFS_SB(sb); - struct cifs_tcon *tcon; - struct cached_fid *cfid; - struct rb_root *root = &cifs_sb->tlink_tree; - struct rb_node *node; - struct tcon_link *tlink; /* * We ned to release all dentries for the cached directories * before we kill the sb. */ if (cifs_sb->root) { - for (node = rb_first(root); node; node = rb_next(node)) { - tlink = rb_entry(node, struct tcon_link, tl_rbnode); - tcon = tlink_tcon(tlink); - if (IS_ERR(tcon)) - continue; - cfid = &tcon->crfid; - mutex_lock(&cfid->fid_mutex); - if (cfid->dentry) { - dput(cfid->dentry); - cfid->dentry = NULL; - } - mutex_unlock(&cfid->fid_mutex); - } + close_all_cached_dirs(cifs_sb); /* finally release root dentry */ dput(cifs_sb->root); diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 9b7f409bfc8c..657fabb9067b 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -1253,7 +1253,7 @@ struct cifs_tcon { struct fscache_volume *fscache; /* cookie for share */ #endif struct list_head pending_opens; /* list of incomplete opens */ - struct cached_fid crfid; /* Cached root fid */ + struct cached_fid cfid; /* Cached root fid */ /* BB add field for back pointer to sb struct(s)? */ #ifdef CONFIG_CIFS_DFS_UPCALL struct list_head ulist; /* cache update list */ diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index d59aebefa71c..881bf112d6ae 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -599,7 +599,6 @@ enum securityEnum cifs_select_sectype(struct TCP_Server_Info *, struct cifs_aio_ctx *cifs_aio_ctx_alloc(void); void cifs_aio_ctx_release(struct kref *refcount); int setup_aio_ctx_iter(struct cifs_aio_ctx *ctx, struct iov_iter *iter, int rw); -void smb2_cached_lease_break(struct work_struct *work); int cifs_alloc_hash(const char *name, struct crypto_shash **shash, struct sdesc **sdesc); diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 9ed21752f2df..78dfadd729fe 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -35,6 +35,7 @@ #ifdef CONFIG_CIFS_DFS_UPCALL #include "dfs_cache.h" #endif +#include "cached_dir.h" #ifdef CONFIG_CIFS_POSIX static struct { @@ -91,12 +92,7 @@ cifs_mark_open_files_invalid(struct cifs_tcon *tcon) } spin_unlock(&tcon->open_file_lock); - mutex_lock(&tcon->crfid.fid_mutex); - tcon->crfid.is_valid = false; - /* cached handle is not valid, so SMB2_CLOSE won't be sent below */ - close_cached_dir_lease_locked(&tcon->crfid); - memset(tcon->crfid.fid, 0, sizeof(struct cifs_fid)); - mutex_unlock(&tcon->crfid.fid_mutex); + invalidate_all_cached_dirs(tcon); spin_lock(&cifs_tcp_ses_lock); if (tcon->status == TID_IN_FILES_INVALIDATE) diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 3ad303dd5e5a..7714f47d199b 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -25,6 +25,7 @@ #include "fscache.h" #include "fs_context.h" #include "cifs_ioctl.h" +#include "cached_dir.h" static void cifs_set_ops(struct inode *inode) { diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 16168ebd1a62..fa1a03ddbbe2 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -115,13 +115,13 @@ tconInfoAlloc(void) ret_buf = kzalloc(sizeof(*ret_buf), GFP_KERNEL); if (!ret_buf) return NULL; - ret_buf->crfid.fid = kzalloc(sizeof(*ret_buf->crfid.fid), GFP_KERNEL); - if (!ret_buf->crfid.fid) { + ret_buf->cfid.fid = kzalloc(sizeof(*ret_buf->cfid.fid), GFP_KERNEL); + if (!ret_buf->cfid.fid) { kfree(ret_buf); return NULL; } - INIT_LIST_HEAD(&ret_buf->crfid.dirents.entries); - mutex_init(&ret_buf->crfid.dirents.de_mutex); + INIT_LIST_HEAD(&ret_buf->cfid.dirents.entries); + mutex_init(&ret_buf->cfid.dirents.de_mutex); atomic_inc(&tconInfoAllocCount); ret_buf->status = TID_NEW; @@ -129,7 +129,7 @@ tconInfoAlloc(void) INIT_LIST_HEAD(&ret_buf->openFileList); INIT_LIST_HEAD(&ret_buf->tcon_list); spin_lock_init(&ret_buf->open_file_lock); - mutex_init(&ret_buf->crfid.fid_mutex); + mutex_init(&ret_buf->cfid.fid_mutex); spin_lock_init(&ret_buf->stat_lock); atomic_set(&ret_buf->num_local_opens, 0); atomic_set(&ret_buf->num_remote_opens, 0); @@ -147,7 +147,7 @@ tconInfoFree(struct cifs_tcon *buf_to_free) atomic_dec(&tconInfoAllocCount); kfree(buf_to_free->nativeFileSystem); kfree_sensitive(buf_to_free->password); - kfree(buf_to_free->crfid.fid); + kfree(buf_to_free->cfid.fid); kfree(buf_to_free); } diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 384cabdf47ca..a06072ae6c7e 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -21,6 +21,7 @@ #include "cifsfs.h" #include "smb2proto.h" #include "fs_context.h" +#include "cached_dir.h" /* * To be safe - for UCS to UTF-8 with strings loaded with the rare long diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c index 8571a459c710..f6f9fc3f2e2d 100644 --- a/fs/cifs/smb2inode.c +++ b/fs/cifs/smb2inode.c @@ -23,6 +23,7 @@ #include "smb2glob.h" #include "smb2pdu.h" #include "smb2proto.h" +#include "cached_dir.h" static void free_set_inf_compound(struct smb_rqst *rqst) @@ -518,9 +519,9 @@ smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, rc = open_cached_dir(xid, tcon, full_path, cifs_sb, &cfid); /* If it is a root and its handle is cached then use it */ if (!rc) { - if (tcon->crfid.file_all_info_is_valid) { + if (tcon->cfid.file_all_info_is_valid) { move_smb2_info_to_cifs(data, - &tcon->crfid.file_all_info); + &tcon->cfid.file_all_info); } else { rc = SMB2_query_info(xid, tcon, cfid->fid->persistent_fid, diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c index db0f27fd373b..d3d9174ddd7c 100644 --- a/fs/cifs/smb2misc.c +++ b/fs/cifs/smb2misc.c @@ -16,6 +16,7 @@ #include "smb2status.h" #include "smb2glob.h" #include "nterr.h" +#include "cached_dir.h" static int check_smb2_hdr(struct smb2_hdr *shdr, __u64 mid) @@ -639,18 +640,8 @@ smb2_is_valid_lease_break(char *buffer) } spin_unlock(&tcon->open_file_lock); - if (tcon->crfid.is_valid && - !memcmp(rsp->LeaseKey, - tcon->crfid.fid->lease_key, - SMB2_LEASE_KEY_SIZE)) { - tcon->crfid.time = 0; - INIT_WORK(&tcon->crfid.lease_break, - smb2_cached_lease_break); - queue_work(cifsiod_wq, - &tcon->crfid.lease_break); - spin_unlock(&cifs_tcp_ses_lock); + if (cached_dir_lease_break(tcon, rsp->LeaseKey)) return true; - } } } } diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index aa4c1d403708..01aafedc477e 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -27,6 +27,7 @@ #include "smbdirect.h" #include "fscache.h" #include "fs_context.h" +#include "cached_dir.h" /* Change credits for different ops and return the total number of credits */ static int @@ -701,300 +702,6 @@ SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon) return rc; } -static void -smb2_close_cached_fid(struct kref *ref) -{ - struct cached_fid *cfid = container_of(ref, struct cached_fid, - refcount); - struct cached_dirent *dirent, *q; - - if (cfid->is_valid) { - cifs_dbg(FYI, "clear cached root file handle\n"); - SMB2_close(0, cfid->tcon, cfid->fid->persistent_fid, - cfid->fid->volatile_fid); - } - - /* - * We only check validity above to send SMB2_close, - * but we still need to invalidate these entries - * when this function is called - */ - cfid->is_valid = false; - cfid->file_all_info_is_valid = false; - cfid->has_lease = false; - if (cfid->dentry) { - dput(cfid->dentry); - cfid->dentry = NULL; - } - /* - * Delete all cached dirent names - */ - mutex_lock(&cfid->dirents.de_mutex); - list_for_each_entry_safe(dirent, q, &cfid->dirents.entries, entry) { - list_del(&dirent->entry); - 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); - -} - -void close_cached_dir(struct cached_fid *cfid) -{ - mutex_lock(&cfid->fid_mutex); - kref_put(&cfid->refcount, smb2_close_cached_fid); - mutex_unlock(&cfid->fid_mutex); -} - -void close_cached_dir_lease_locked(struct cached_fid *cfid) -{ - if (cfid->has_lease) { - cfid->has_lease = false; - kref_put(&cfid->refcount, smb2_close_cached_fid); - } -} - -void close_cached_dir_lease(struct cached_fid *cfid) -{ - mutex_lock(&cfid->fid_mutex); - close_cached_dir_lease_locked(cfid); - mutex_unlock(&cfid->fid_mutex); -} - -void -smb2_cached_lease_break(struct work_struct *work) -{ - struct cached_fid *cfid = container_of(work, - struct cached_fid, lease_break); - - close_cached_dir_lease(cfid); -} - -/* - * Open the and cache a directory handle. - * Only supported for the root handle. - * If error then *cfid is not initialized. - */ -int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, - const char *path, - struct cifs_sb_info *cifs_sb, - struct cached_fid **cfid) -{ - struct cifs_ses *ses; - struct TCP_Server_Info *server; - struct cifs_open_parms oparms; - struct smb2_create_rsp *o_rsp = NULL; - struct smb2_query_info_rsp *qi_rsp = NULL; - int resp_buftype[2]; - struct smb_rqst rqst[2]; - struct kvec rsp_iov[2]; - struct kvec open_iov[SMB2_CREATE_IOV_SIZE]; - struct kvec qi_iov[1]; - 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; - struct dentry *dentry; - - if (tcon == NULL || tcon->nohandlecache || - is_smb1_server(tcon->ses->server)) - return -ENOTSUPP; - - ses = tcon->ses; - server = ses->server; - - if (cifs_sb->root == NULL) - return -ENOENT; - - if (strlen(path)) - return -ENOENT; - - dentry = cifs_sb->root; - - mutex_lock(&tcon->crfid.fid_mutex); - if (tcon->crfid.is_valid) { - cifs_dbg(FYI, "found a cached root file handle\n"); - *cfid = &tcon->crfid; - kref_get(&tcon->crfid.refcount); - mutex_unlock(&tcon->crfid.fid_mutex); - return 0; - } - - /* - * We do not hold the lock for the open because in case - * SMB2_open needs to reconnect, it will end up calling - * cifs_mark_open_files_invalid() which takes the lock again - * thus causing a deadlock - */ - - mutex_unlock(&tcon->crfid.fid_mutex); - - if (smb3_encryption_required(tcon)) - flags |= CIFS_TRANSFORM_REQ; - - if (!server->ops->new_lease_key) - return -EIO; - - pfid = tcon->crfid.fid; - server->ops->new_lease_key(pfid); - - memset(rqst, 0, sizeof(rqst)); - resp_buftype[0] = resp_buftype[1] = CIFS_NO_BUFFER; - memset(rsp_iov, 0, sizeof(rsp_iov)); - - /* Open */ - memset(&open_iov, 0, sizeof(open_iov)); - rqst[0].rq_iov = open_iov; - rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE; - - oparms.tcon = tcon; - oparms.create_options = cifs_create_options(cifs_sb, CREATE_NOT_FILE); - oparms.desired_access = FILE_READ_ATTRIBUTES; - oparms.disposition = FILE_OPEN; - oparms.fid = pfid; - oparms.reconnect = false; - - rc = SMB2_open_init(tcon, server, - &rqst[0], &oplock, &oparms, &utf16_path); - if (rc) - goto oshr_free; - smb2_set_next_command(tcon, &rqst[0]); - - memset(&qi_iov, 0, sizeof(qi_iov)); - rqst[1].rq_iov = qi_iov; - rqst[1].rq_nvec = 1; - - rc = SMB2_query_info_init(tcon, server, - &rqst[1], COMPOUND_FID, - COMPOUND_FID, FILE_ALL_INFORMATION, - SMB2_O_INFO_FILE, 0, - sizeof(struct smb2_file_all_info) + - PATH_MAX * 2, 0, NULL); - if (rc) - goto oshr_free; - - smb2_set_related(&rqst[1]); - - rc = compound_send_recv(xid, ses, server, - flags, 2, rqst, - resp_buftype, rsp_iov); - mutex_lock(&tcon->crfid.fid_mutex); - - /* - * Now we need to check again as the cached root might have - * been successfully re-opened from a concurrent process - */ - - if (tcon->crfid.is_valid) { - /* work was already done */ - - /* stash fids for close() later */ - struct cifs_fid fid = { - .persistent_fid = pfid->persistent_fid, - .volatile_fid = pfid->volatile_fid, - }; - - /* - * caller expects this func to set the fid in crfid to valid - * cached root, so increment the refcount. - */ - kref_get(&tcon->crfid.refcount); - - mutex_unlock(&tcon->crfid.fid_mutex); - - if (rc == 0) { - /* close extra handle outside of crit sec */ - SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid); - } - rc = 0; - goto oshr_free; - } - - /* Cached root is still invalid, continue normaly */ - - if (rc) { - if (rc == -EREMCHG) { - tcon->need_reconnect = true; - pr_warn_once("server share %s deleted\n", - tcon->treeName); - } - goto oshr_exit; - } - - atomic_inc(&tcon->num_remote_opens); - - o_rsp = (struct smb2_create_rsp *)rsp_iov[0].iov_base; - oparms.fid->persistent_fid = o_rsp->PersistentFileId; - oparms.fid->volatile_fid = o_rsp->VolatileFileId; -#ifdef CONFIG_CIFS_DEBUG2 - oparms.fid->mid = le64_to_cpu(o_rsp->hdr.MessageId); -#endif /* CIFS_DEBUG2 */ - - tcon->crfid.tcon = tcon; - tcon->crfid.is_valid = true; - tcon->crfid.dentry = dentry; - dget(dentry); - kref_init(&tcon->crfid.refcount); - - /* BB TBD check to see if oplock level check can be removed below */ - if (o_rsp->OplockLevel == SMB2_OPLOCK_LEVEL_LEASE) { - /* - * See commit 2f94a3125b87. Increment the refcount when we - * get a lease for root, release it if lease break occurs - */ - kref_get(&tcon->crfid.refcount); - tcon->crfid.has_lease = true; - smb2_parse_contexts(server, o_rsp, - &oparms.fid->epoch, - oparms.fid->lease_key, &oplock, - NULL, NULL); - } else - goto oshr_exit; - - qi_rsp = (struct smb2_query_info_rsp *)rsp_iov[1].iov_base; - if (le32_to_cpu(qi_rsp->OutputBufferLength) < sizeof(struct smb2_file_all_info)) - goto oshr_exit; - if (!smb2_validate_and_copy_iov( - le16_to_cpu(qi_rsp->OutputBufferOffset), - sizeof(struct smb2_file_all_info), - &rsp_iov[1], sizeof(struct smb2_file_all_info), - (char *)&tcon->crfid.file_all_info)) - tcon->crfid.file_all_info_is_valid = true; - tcon->crfid.time = jiffies; - - -oshr_exit: - mutex_unlock(&tcon->crfid.fid_mutex); -oshr_free: - SMB2_open_free(&rqst[0]); - 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; -} - -int open_cached_dir_by_dentry(struct cifs_tcon *tcon, - struct dentry *dentry, - struct cached_fid **cfid) -{ - mutex_lock(&tcon->crfid.fid_mutex); - if (tcon->crfid.dentry == dentry) { - cifs_dbg(FYI, "found a cached root file handle by dentry\n"); - *cfid = &tcon->crfid; - kref_get(&tcon->crfid.refcount); - mutex_unlock(&tcon->crfid.fid_mutex); - return 0; - } - mutex_unlock(&tcon->crfid.fid_mutex); - return -ENOENT; -} - static void smb3_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon, struct cifs_sb_info *cifs_sb) @@ -1077,7 +784,7 @@ smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon, struct cifs_open_parms oparms; struct cifs_fid fid; - if ((*full_path == 0) && tcon->crfid.is_valid) + if ((*full_path == 0) && tcon->cfid.is_valid) return 0; utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb); diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 295ee8b88055..9ee1b6225619 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -39,6 +39,7 @@ #ifdef CONFIG_CIFS_DFS_UPCALL #include "dfs_cache.h" #endif +#include "cached_dir.h" /* * The following table defines the expected "StructureSize" of SMB2 requests @@ -1978,7 +1979,7 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon) } spin_unlock(&ses->chan_lock); - close_cached_dir_lease(&tcon->crfid); + close_cached_dir_lease(&tcon->cfid); rc = smb2_plain_req_init(SMB2_TREE_DISCONNECT, tcon, ses->server, (void **) &req, diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index a69f1eed1cfe..51c5bf4a338a 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h @@ -54,16 +54,6 @@ extern bool smb2_is_valid_oplock_break(char *buffer, extern int smb3_handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid); -extern int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, - const char *path, - struct cifs_sb_info *cifs_sb, - 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 close_cached_dir_lease(struct cached_fid *cfid); -extern void close_cached_dir_lease_locked(struct cached_fid *cfid); extern void move_smb2_info_to_cifs(FILE_ALL_INFO *dst, struct smb2_file_all_info *src); extern int smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon, From patchwork Tue Aug 9 02:11:49 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ronnie Sahlberg X-Patchwork-Id: 12939285 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B1E13C00140 for ; Tue, 9 Aug 2022 02:12:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229642AbiHICM2 (ORCPT ); Mon, 8 Aug 2022 22:12:28 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57316 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229561AbiHICM1 (ORCPT ); Mon, 8 Aug 2022 22:12:27 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 5FD5918B09 for ; Mon, 8 Aug 2022 19:12:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1660011145; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=HYnrwpqBmn4hfmQygj3FP9ktl9kU7vtyHT5wppxLS+s=; b=T1SzV5cerNrVRBMf2igAuVqrK+4hQNEwWha9PwAze/vq7RLr90ZEFrZs4XohZLUNPlS/z0 r7Ln+lGXgBmSYPACt05XEXaWBGxHkdeFdVJ0MC63FnTlHxi0v7N2tn8FFjOkL/x5Cj7GsH shqKVosyKqEYt+8f8Z/lzjRGiccUbpM= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-649-MCm9FHnIOr6VI0yjvE_Hjg-1; Mon, 08 Aug 2022 22:12:21 -0400 X-MC-Unique: MCm9FHnIOr6VI0yjvE_Hjg-1 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.rdu2.redhat.com [10.11.54.7]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 25A7F802D2C; Tue, 9 Aug 2022 02:12:21 +0000 (UTC) Received: from localhost.localdomain (vpn2-52-16.bne.redhat.com [10.64.52.16]) by smtp.corp.redhat.com (Postfix) with ESMTP id 63936140EBE3; Tue, 9 Aug 2022 02:12:19 +0000 (UTC) From: Ronnie Sahlberg To: linux-cifs Cc: Steve French , Ronnie Sahlberg Subject: [PATCH 2/9] cifs: Do not use tcon->cfid directly, use the cfid we get from open_cached_dir Date: Tue, 9 Aug 2022 12:11:49 +1000 Message-Id: <20220809021156.3086869-3-lsahlber@redhat.com> In-Reply-To: <20220809021156.3086869-1-lsahlber@redhat.com> References: <20220809021156.3086869-1-lsahlber@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.85 on 10.11.54.7 Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org They are the same right now but tcon-> will later point to a different type of struct containing a list of cfids. Signed-off-by: Ronnie Sahlberg Reviewed-by: Paulo Alcantara (SUSE) --- fs/cifs/smb2inode.c | 4 ++-- fs/cifs/smb2pdu.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c index f6f9fc3f2e2d..09f01f70e020 100644 --- a/fs/cifs/smb2inode.c +++ b/fs/cifs/smb2inode.c @@ -519,9 +519,9 @@ smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, rc = open_cached_dir(xid, tcon, full_path, cifs_sb, &cfid); /* If it is a root and its handle is cached then use it */ if (!rc) { - if (tcon->cfid.file_all_info_is_valid) { + if (cfid->file_all_info_is_valid) { move_smb2_info_to_cifs(data, - &tcon->cfid.file_all_info); + &cfid->file_all_info); } else { rc = SMB2_query_info(xid, tcon, cfid->fid->persistent_fid, diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 9ee1b6225619..5dbd2cac470c 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -1979,7 +1979,7 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon) } spin_unlock(&ses->chan_lock); - close_cached_dir_lease(&tcon->cfid); + invalidate_all_cached_dirs(tcon); rc = smb2_plain_req_init(SMB2_TREE_DISCONNECT, tcon, ses->server, (void **) &req, From patchwork Tue Aug 9 02:11:50 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ronnie Sahlberg X-Patchwork-Id: 12939282 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 987DFC00140 for ; Tue, 9 Aug 2022 02:12:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229571AbiHICMQ (ORCPT ); Mon, 8 Aug 2022 22:12:16 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57226 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229561AbiHICMP (ORCPT ); Mon, 8 Aug 2022 22:12:15 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id C8F6918B09 for ; Mon, 8 Aug 2022 19:12:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1660011132; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=3vZN4//OuvwR+7MCkcThDbHj1pl2MXNlS2VTuZOBY0s=; b=UTuPrcYe3JPSNLWHpebBO1jsC/g3qRgsQLrH8nr4rimVNOC6gacNQc8DcRsFX8oUgWfcRd SboZUlXCqCYQbWbZgEA57HIIcHBUtDmVBd32Mar60a0XzLCATEvokyIkabCC8FpwtEuIDa ELf35fqU1ixEeplaOJAu9/Ppu3ent2M= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-231-it5lNo13MjaBQoKwT2SERg-1; Mon, 08 Aug 2022 22:12:11 -0400 X-MC-Unique: it5lNo13MjaBQoKwT2SERg-1 Received: from smtp.corp.redhat.com (int-mx10.intmail.prod.int.rdu2.redhat.com [10.11.54.10]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id BB6DE811E84; Tue, 9 Aug 2022 02:12:10 +0000 (UTC) Received: from localhost.localdomain (vpn2-52-16.bne.redhat.com [10.64.52.16]) by smtp.corp.redhat.com (Postfix) with ESMTP id 65CE7492C3B; Tue, 9 Aug 2022 02:12:09 +0000 (UTC) From: Ronnie Sahlberg To: linux-cifs Cc: Steve French , Ronnie Sahlberg Subject: [PATCH 3/9] cifs: Add constructor/destructors for tcon->cfid Date: Tue, 9 Aug 2022 12:11:50 +1000 Message-Id: <20220809021156.3086869-4-lsahlber@redhat.com> In-Reply-To: <20220809021156.3086869-1-lsahlber@redhat.com> References: <20220809021156.3086869-1-lsahlber@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.85 on 10.11.54.10 Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org and move the structure definitions into cached_dir.h Signed-off-by: Ronnie Sahlberg Reviewed-by: Paulo Alcantara (SUSE) --- fs/cifs/cached_dir.c | 114 ++++++++++++++++++++++++++----------------- fs/cifs/cached_dir.h | 38 +++++++++++++++ fs/cifs/cifsglob.h | 38 +-------------- fs/cifs/misc.c | 20 ++++---- fs/cifs/smb2inode.c | 4 +- fs/cifs/smb2ops.c | 8 +-- 6 files changed, 123 insertions(+), 99 deletions(-) diff --git a/fs/cifs/cached_dir.c b/fs/cifs/cached_dir.c index f2e17c1d5196..7ca085299890 100644 --- a/fs/cifs/cached_dir.c +++ b/fs/cifs/cached_dir.c @@ -18,7 +18,7 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, const char *path, struct cifs_sb_info *cifs_sb, - struct cached_fid **cfid) + struct cached_fid **ret_cfid) { struct cifs_ses *ses; struct TCP_Server_Info *server; @@ -35,7 +35,8 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, u8 oplock = SMB2_OPLOCK_LEVEL_II; struct cifs_fid *pfid; struct dentry *dentry; - + struct cached_fid *cfid; + if (tcon == NULL || tcon->nohandlecache || is_smb1_server(tcon->ses->server)) return -ENOTSUPP; @@ -51,12 +52,13 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, dentry = cifs_sb->root; - mutex_lock(&tcon->cfid.fid_mutex); - if (tcon->cfid.is_valid) { + cfid = tcon->cfid; + mutex_lock(&cfid->fid_mutex); + if (cfid->is_valid) { cifs_dbg(FYI, "found a cached root file handle\n"); - *cfid = &tcon->cfid; - kref_get(&tcon->cfid.refcount); - mutex_unlock(&tcon->cfid.fid_mutex); + *ret_cfid = cfid; + kref_get(&cfid->refcount); + mutex_unlock(&cfid->fid_mutex); return 0; } @@ -67,7 +69,7 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, * thus causing a deadlock */ - mutex_unlock(&tcon->cfid.fid_mutex); + mutex_unlock(&cfid->fid_mutex); if (smb3_encryption_required(tcon)) flags |= CIFS_TRANSFORM_REQ; @@ -75,7 +77,7 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, if (!server->ops->new_lease_key) return -EIO; - pfid = tcon->cfid.fid; + pfid = &cfid->fid; server->ops->new_lease_key(pfid); memset(rqst, 0, sizeof(rqst)); @@ -118,14 +120,14 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, rc = compound_send_recv(xid, ses, server, flags, 2, rqst, resp_buftype, rsp_iov); - mutex_lock(&tcon->cfid.fid_mutex); + mutex_lock(&cfid->fid_mutex); /* * Now we need to check again as the cached root might have * been successfully re-opened from a concurrent process */ - if (tcon->cfid.is_valid) { + if (cfid->is_valid) { /* work was already done */ /* stash fids for close() later */ @@ -138,9 +140,9 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, * caller expects this func to set the fid in cfid to valid * cached root, so increment the refcount. */ - kref_get(&tcon->cfid.refcount); + kref_get(&cfid->refcount); - mutex_unlock(&tcon->cfid.fid_mutex); + mutex_unlock(&cfid->fid_mutex); if (rc == 0) { /* close extra handle outside of crit sec */ @@ -170,11 +172,11 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, oparms.fid->mid = le64_to_cpu(o_rsp->hdr.MessageId); #endif /* CIFS_DEBUG2 */ - tcon->cfid.tcon = tcon; - tcon->cfid.is_valid = true; - tcon->cfid.dentry = dentry; + cfid->tcon = tcon; + cfid->is_valid = true; + cfid->dentry = dentry; dget(dentry); - kref_init(&tcon->cfid.refcount); + kref_init(&cfid->refcount); /* BB TBD check to see if oplock level check can be removed below */ if (o_rsp->OplockLevel == SMB2_OPLOCK_LEVEL_LEASE) { @@ -182,8 +184,8 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, * See commit 2f94a3125b87. Increment the refcount when we * get a lease for root, release it if lease break occurs */ - kref_get(&tcon->cfid.refcount); - tcon->cfid.has_lease = true; + kref_get(&cfid->refcount); + cfid->has_lease = true; smb2_parse_contexts(server, o_rsp, &oparms.fid->epoch, oparms.fid->lease_key, &oplock, @@ -198,37 +200,41 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, le16_to_cpu(qi_rsp->OutputBufferOffset), sizeof(struct smb2_file_all_info), &rsp_iov[1], sizeof(struct smb2_file_all_info), - (char *)&tcon->cfid.file_all_info)) - tcon->cfid.file_all_info_is_valid = true; - tcon->cfid.time = jiffies; + (char *)&cfid->file_all_info)) + cfid->file_all_info_is_valid = true; + cfid->time = jiffies; oshr_exit: - mutex_unlock(&tcon->cfid.fid_mutex); + mutex_unlock(&cfid->fid_mutex); oshr_free: SMB2_open_free(&rqst[0]); 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->cfid; -} + *ret_cfid = cfid; + } return rc; } int open_cached_dir_by_dentry(struct cifs_tcon *tcon, struct dentry *dentry, - struct cached_fid **cfid) + struct cached_fid **ret_cfid) { - mutex_lock(&tcon->cfid.fid_mutex); - if (tcon->cfid.dentry == dentry) { + struct cached_fid *cfid; + + cfid = tcon->cfid; + + mutex_lock(&cfid->fid_mutex); + if (cfid->dentry == dentry) { cifs_dbg(FYI, "found a cached root file handle by dentry\n"); - *cfid = &tcon->cfid; - kref_get(&tcon->cfid.refcount); - mutex_unlock(&tcon->cfid.fid_mutex); + *ret_cfid = cfid; + kref_get(&cfid->refcount); + mutex_unlock(&cfid->fid_mutex); return 0; } - mutex_unlock(&tcon->cfid.fid_mutex); + mutex_unlock(&cfid->fid_mutex); return -ENOENT; } @@ -241,8 +247,8 @@ smb2_close_cached_fid(struct kref *ref) if (cfid->is_valid) { cifs_dbg(FYI, "clear cached root file handle\n"); - SMB2_close(0, cfid->tcon, cfid->fid->persistent_fid, - cfid->fid->volatile_fid); + SMB2_close(0, cfid->tcon, cfid->fid.persistent_fid, + cfid->fid.volatile_fid); } /* @@ -312,7 +318,7 @@ void close_all_cached_dirs(struct cifs_sb_info *cifs_sb) tcon = tlink_tcon(tlink); if (IS_ERR(tcon)) continue; - cfid = &tcon->cfid; + cfid = tcon->cfid; mutex_lock(&cfid->fid_mutex); if (cfid->dentry) { dput(cfid->dentry); @@ -328,12 +334,12 @@ void close_all_cached_dirs(struct cifs_sb_info *cifs_sb) */ void invalidate_all_cached_dirs(struct cifs_tcon *tcon) { - mutex_lock(&tcon->cfid.fid_mutex); - tcon->cfid.is_valid = false; + mutex_lock(&tcon->cfid->fid_mutex); + tcon->cfid->is_valid = false; /* cached handle is not valid, so SMB2_CLOSE won't be sent below */ - close_cached_dir_lease_locked(&tcon->cfid); - memset(tcon->cfid.fid, 0, sizeof(struct cifs_fid)); - mutex_unlock(&tcon->cfid.fid_mutex); + close_cached_dir_lease_locked(tcon->cfid); + memset(&tcon->cfid->fid, 0, sizeof(struct cifs_fid)); + mutex_unlock(&tcon->cfid->fid_mutex); } static void @@ -347,17 +353,35 @@ smb2_cached_lease_break(struct work_struct *work) int cached_dir_lease_break(struct cifs_tcon *tcon, __u8 lease_key[16]) { - if (tcon->cfid.is_valid && + if (tcon->cfid->is_valid && !memcmp(lease_key, - tcon->cfid.fid->lease_key, + tcon->cfid->fid.lease_key, SMB2_LEASE_KEY_SIZE)) { - tcon->cfid.time = 0; - INIT_WORK(&tcon->cfid.lease_break, + tcon->cfid->time = 0; + INIT_WORK(&tcon->cfid->lease_break, smb2_cached_lease_break); queue_work(cifsiod_wq, - &tcon->cfid.lease_break); + &tcon->cfid->lease_break); spin_unlock(&cifs_tcp_ses_lock); return true; } return false; } + +struct cached_fid *init_cached_dir(void) +{ + struct cached_fid *cfid; + + cfid = kzalloc(sizeof(*cfid), GFP_KERNEL); + if (!cfid) + return NULL; + INIT_LIST_HEAD(&cfid->dirents.entries); + mutex_init(&cfid->dirents.de_mutex); + mutex_init(&cfid->fid_mutex); + return cfid; +} + +void free_cached_dir(struct cifs_tcon *tcon) +{ + kfree(tcon->cfid); +} diff --git a/fs/cifs/cached_dir.h b/fs/cifs/cached_dir.h index 3731c755eea5..b44edfbd8e1a 100644 --- a/fs/cifs/cached_dir.h +++ b/fs/cifs/cached_dir.h @@ -9,6 +9,44 @@ #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 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; + bool has_lease:1; + unsigned long time; /* jiffies of when lease was taken */ + struct kref refcount; + struct cifs_fid fid; + struct mutex fid_mutex; + struct cifs_tcon *tcon; + struct dentry *dentry; + struct work_struct lease_break; + struct smb2_file_all_info file_all_info; + struct cached_dirents dirents; +}; + +extern struct cached_fid *init_cached_dir(void); +extern void free_cached_dir(struct cifs_tcon *tcon); extern int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, const char *path, struct cifs_sb_info *cifs_sb, diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 657fabb9067b..d3b233a2737d 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -1125,42 +1125,6 @@ struct cifs_fattr { u32 cf_cifstag; }; -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 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; - bool has_lease:1; - unsigned long time; /* jiffies of when lease was taken */ - struct kref refcount; - struct cifs_fid *fid; - struct mutex fid_mutex; - struct cifs_tcon *tcon; - struct dentry *dentry; - struct work_struct lease_break; - struct smb2_file_all_info file_all_info; - struct cached_dirents dirents; -}; - /* * there is one of these for each connection to a resource on a particular * session @@ -1253,7 +1217,7 @@ struct cifs_tcon { struct fscache_volume *fscache; /* cookie for share */ #endif struct list_head pending_opens; /* list of incomplete opens */ - struct cached_fid cfid; /* Cached root fid */ + struct cached_fid *cfid; /* Cached root fid */ /* BB add field for back pointer to sb struct(s)? */ #ifdef CONFIG_CIFS_DFS_UPCALL struct list_head ulist; /* cache update list */ diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index fa1a03ddbbe2..4e2e3b557591 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -23,6 +23,7 @@ #include "dns_resolve.h" #endif #include "fs_context.h" +#include "cached_dir.h" extern mempool_t *cifs_sm_req_poolp; extern mempool_t *cifs_req_poolp; @@ -115,13 +116,11 @@ tconInfoAlloc(void) ret_buf = kzalloc(sizeof(*ret_buf), GFP_KERNEL); if (!ret_buf) return NULL; - ret_buf->cfid.fid = kzalloc(sizeof(*ret_buf->cfid.fid), GFP_KERNEL); - if (!ret_buf->cfid.fid) { + ret_buf->cfid = init_cached_dir(); + if (!ret_buf->cfid) { kfree(ret_buf); return NULL; } - INIT_LIST_HEAD(&ret_buf->cfid.dirents.entries); - mutex_init(&ret_buf->cfid.dirents.de_mutex); atomic_inc(&tconInfoAllocCount); ret_buf->status = TID_NEW; @@ -129,7 +128,6 @@ tconInfoAlloc(void) INIT_LIST_HEAD(&ret_buf->openFileList); INIT_LIST_HEAD(&ret_buf->tcon_list); spin_lock_init(&ret_buf->open_file_lock); - mutex_init(&ret_buf->cfid.fid_mutex); spin_lock_init(&ret_buf->stat_lock); atomic_set(&ret_buf->num_local_opens, 0); atomic_set(&ret_buf->num_remote_opens, 0); @@ -138,17 +136,17 @@ tconInfoAlloc(void) } void -tconInfoFree(struct cifs_tcon *buf_to_free) +tconInfoFree(struct cifs_tcon *tcon) { - if (buf_to_free == NULL) { + if (tcon == NULL) { cifs_dbg(FYI, "Null buffer passed to tconInfoFree\n"); return; } + free_cached_dir(tcon); atomic_dec(&tconInfoAllocCount); - kfree(buf_to_free->nativeFileSystem); - kfree_sensitive(buf_to_free->password); - kfree(buf_to_free->cfid.fid); - kfree(buf_to_free); + kfree(tcon->nativeFileSystem); + kfree_sensitive(tcon->password); + kfree(tcon); } struct smb_hdr * diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c index 09f01f70e020..9696184a09e3 100644 --- a/fs/cifs/smb2inode.c +++ b/fs/cifs/smb2inode.c @@ -524,8 +524,8 @@ smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, &cfid->file_all_info); } else { rc = SMB2_query_info(xid, tcon, - cfid->fid->persistent_fid, - cfid->fid->volatile_fid, smb2_data); + cfid->fid.persistent_fid, + cfid->fid.volatile_fid, smb2_data); if (!rc) move_smb2_info_to_cifs(data, smb2_data); } diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 01aafedc477e..e50b6ef309e1 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -722,7 +722,7 @@ smb3_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon, rc = open_cached_dir(xid, tcon, "", cifs_sb, &cfid); if (rc == 0) - memcpy(&fid, cfid->fid, sizeof(struct cifs_fid)); + memcpy(&fid, &cfid->fid, sizeof(struct cifs_fid)); else rc = SMB2_open(xid, &oparms, &srch_path, &oplock, NULL, NULL, NULL, NULL); @@ -784,7 +784,7 @@ smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon, struct cifs_open_parms oparms; struct cifs_fid fid; - if ((*full_path == 0) && tcon->cfid.is_valid) + if ((*full_path == 0) && tcon->cfid->is_valid) return 0; utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb); @@ -2458,8 +2458,8 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon, if (cfid) { rc = SMB2_query_info_init(tcon, server, &rqst[1], - cfid->fid->persistent_fid, - cfid->fid->volatile_fid, + cfid->fid.persistent_fid, + cfid->fid.volatile_fid, class, type, 0, output_len, 0, NULL); From patchwork Tue Aug 9 02:11:51 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ronnie Sahlberg X-Patchwork-Id: 12939284 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5270CC25B08 for ; Tue, 9 Aug 2022 02:12:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229674AbiHICMZ (ORCPT ); Mon, 8 Aug 2022 22:12:25 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57284 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229561AbiHICMY (ORCPT ); Mon, 8 Aug 2022 22:12:24 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 483A2186F5 for ; Mon, 8 Aug 2022 19:12:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1660011141; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=NQ9BJ8EoZd8LprfXCrSZNvOZ/gbqrpMhQFq6Vm2fCd4=; b=dYtuXBEevCkZODqs8qbTvLkCRngFq6lOTNR5yt9Y4laOwkqBG7a6EX2qkxZrO3SoJ1ladq UhsgF/UWdHstvWKI6582UuRqpp34g0QGkv74LgX9t/cy0espfySHO1huwnpgkgZV3I/K6+ ujJfxZRruFT4Yw7ENao+MWhybjsVhiM= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-587-FyRbd0EsPHeXXcV58kUAdQ-1; Mon, 08 Aug 2022 22:12:18 -0400 X-MC-Unique: FyRbd0EsPHeXXcV58kUAdQ-1 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 087CA804196; Tue, 9 Aug 2022 02:12:18 +0000 (UTC) Received: from localhost.localdomain (vpn2-52-16.bne.redhat.com [10.64.52.16]) by smtp.corp.redhat.com (Postfix) with ESMTP id 1B9BB9459C; Tue, 9 Aug 2022 02:12:16 +0000 (UTC) From: Ronnie Sahlberg To: linux-cifs Cc: Steve French , Ronnie Sahlberg Subject: [PATCH 4/9] cifs: Make tcon contain a wrapper structure cached_fids instead of cached_fid Date: Tue, 9 Aug 2022 12:11:51 +1000 Message-Id: <20220809021156.3086869-5-lsahlber@redhat.com> In-Reply-To: <20220809021156.3086869-1-lsahlber@redhat.com> References: <20220809021156.3086869-1-lsahlber@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.11.54.5 Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org This wrapper structure will later be expanded to contain a list of fids that are cached and not just the root fid. Signed-off-by: Ronnie Sahlberg Reviewed-by: Paulo Alcantara (SUSE) --- fs/cifs/cached_dir.c | 50 ++++++++++++++++++++++++-------------------- fs/cifs/cached_dir.h | 8 +++++-- fs/cifs/cifsglob.h | 2 +- fs/cifs/misc.c | 6 +++--- fs/cifs/smb2ops.c | 2 +- 5 files changed, 38 insertions(+), 30 deletions(-) diff --git a/fs/cifs/cached_dir.c b/fs/cifs/cached_dir.c index 7ca085299890..604ac444ad25 100644 --- a/fs/cifs/cached_dir.c +++ b/fs/cifs/cached_dir.c @@ -52,7 +52,7 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, dentry = cifs_sb->root; - cfid = tcon->cfid; + cfid = &tcon->cfids->cfid; mutex_lock(&cfid->fid_mutex); if (cfid->is_valid) { cifs_dbg(FYI, "found a cached root file handle\n"); @@ -224,7 +224,7 @@ int open_cached_dir_by_dentry(struct cifs_tcon *tcon, { struct cached_fid *cfid; - cfid = tcon->cfid; + cfid = &tcon->cfids->cfid; mutex_lock(&cfid->fid_mutex); if (cfid->dentry == dentry) { @@ -318,7 +318,7 @@ void close_all_cached_dirs(struct cifs_sb_info *cifs_sb) tcon = tlink_tcon(tlink); if (IS_ERR(tcon)) continue; - cfid = tcon->cfid; + cfid = &tcon->cfids->cfid; mutex_lock(&cfid->fid_mutex); if (cfid->dentry) { dput(cfid->dentry); @@ -334,12 +334,14 @@ void close_all_cached_dirs(struct cifs_sb_info *cifs_sb) */ void invalidate_all_cached_dirs(struct cifs_tcon *tcon) { - mutex_lock(&tcon->cfid->fid_mutex); - tcon->cfid->is_valid = false; + struct cached_fid *cfid = &tcon->cfids->cfid; + + mutex_lock(&cfid->fid_mutex); + cfid->is_valid = false; /* cached handle is not valid, so SMB2_CLOSE won't be sent below */ - close_cached_dir_lease_locked(tcon->cfid); - memset(&tcon->cfid->fid, 0, sizeof(struct cifs_fid)); - mutex_unlock(&tcon->cfid->fid_mutex); + close_cached_dir_lease_locked(cfid); + memset(&cfid->fid, 0, sizeof(struct cifs_fid)); + mutex_unlock(&cfid->fid_mutex); } static void @@ -353,35 +355,37 @@ smb2_cached_lease_break(struct work_struct *work) int cached_dir_lease_break(struct cifs_tcon *tcon, __u8 lease_key[16]) { - if (tcon->cfid->is_valid && + struct cached_fid *cfid = &tcon->cfids->cfid; + + if (cfid->is_valid && !memcmp(lease_key, - tcon->cfid->fid.lease_key, + cfid->fid.lease_key, SMB2_LEASE_KEY_SIZE)) { - tcon->cfid->time = 0; - INIT_WORK(&tcon->cfid->lease_break, + cfid->time = 0; + INIT_WORK(&cfid->lease_break, smb2_cached_lease_break); queue_work(cifsiod_wq, - &tcon->cfid->lease_break); + &cfid->lease_break); spin_unlock(&cifs_tcp_ses_lock); return true; } return false; } -struct cached_fid *init_cached_dir(void) +struct cached_fids *init_cached_dirs(void) { - struct cached_fid *cfid; + struct cached_fids *cfids; - cfid = kzalloc(sizeof(*cfid), GFP_KERNEL); - if (!cfid) + cfids = kzalloc(sizeof(*cfids), GFP_KERNEL); + if (!cfids) return NULL; - INIT_LIST_HEAD(&cfid->dirents.entries); - mutex_init(&cfid->dirents.de_mutex); - mutex_init(&cfid->fid_mutex); - return cfid; + INIT_LIST_HEAD(&cfids->cfid.dirents.entries); + mutex_init(&cfids->cfid.dirents.de_mutex); + mutex_init(&cfids->cfid.fid_mutex); + return cfids; } -void free_cached_dir(struct cifs_tcon *tcon) +void free_cached_dirs(struct cached_fids *cfids) { - kfree(tcon->cfid); + kfree(cfids); } diff --git a/fs/cifs/cached_dir.h b/fs/cifs/cached_dir.h index b44edfbd8e1a..4ea30a5ba4e7 100644 --- a/fs/cifs/cached_dir.h +++ b/fs/cifs/cached_dir.h @@ -45,8 +45,12 @@ struct cached_fid { struct cached_dirents dirents; }; -extern struct cached_fid *init_cached_dir(void); -extern void free_cached_dir(struct cifs_tcon *tcon); +struct cached_fids { + struct cached_fid cfid; +}; + +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, diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index d3b233a2737d..edee34011ffc 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -1217,7 +1217,7 @@ struct cifs_tcon { struct fscache_volume *fscache; /* cookie for share */ #endif struct list_head pending_opens; /* list of incomplete opens */ - struct cached_fid *cfid; /* Cached root fid */ + struct cached_fids *cfids; /* Cached root fid */ /* BB add field for back pointer to sb struct(s)? */ #ifdef CONFIG_CIFS_DFS_UPCALL struct list_head ulist; /* cache update list */ diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 4e2e3b557591..d193c6242366 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -116,8 +116,8 @@ tconInfoAlloc(void) ret_buf = kzalloc(sizeof(*ret_buf), GFP_KERNEL); if (!ret_buf) return NULL; - ret_buf->cfid = init_cached_dir(); - if (!ret_buf->cfid) { + ret_buf->cfids = init_cached_dirs(); + if (!ret_buf->cfids) { kfree(ret_buf); return NULL; } @@ -142,7 +142,7 @@ tconInfoFree(struct cifs_tcon *tcon) cifs_dbg(FYI, "Null buffer passed to tconInfoFree\n"); return; } - free_cached_dir(tcon); + free_cached_dirs(tcon->cfids); atomic_dec(&tconInfoAllocCount); kfree(tcon->nativeFileSystem); kfree_sensitive(tcon->password); diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index e50b6ef309e1..780ada4d8f6e 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -784,7 +784,7 @@ smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon, struct cifs_open_parms oparms; struct cifs_fid fid; - if ((*full_path == 0) && tcon->cfid->is_valid) + if ((*full_path == 0) && tcon->cfids->cfid.is_valid) return 0; utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb); From patchwork Tue Aug 9 02:11:52 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ronnie Sahlberg X-Patchwork-Id: 12939289 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id C65A7C00140 for ; Tue, 9 Aug 2022 02:12:41 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229853AbiHICMl (ORCPT ); Mon, 8 Aug 2022 22:12:41 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57444 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229801AbiHICMk (ORCPT ); Mon, 8 Aug 2022 22:12:40 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 576551BE93 for ; Mon, 8 Aug 2022 19:12:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1660011158; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=+h50wU5RQ6/zzwJy17RkrmDX+z5AvHJoEch7yXgB3U4=; b=QQraWZWOcTXYYhUTSA5KBLn9QdAzpKgpzajwKFdG1jcqUozLblDQQIz87o2uUUX2KA4cxR UK+Y53ULbWuFBIxuTP9IHEARM8mrHKfbkBhunEupppKEFUwSC0l4aAO4PzIh1rASiVYHQ/ A3ndg7mZDSMHbH3ySxJMUi1O9w6kTAM= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-549-Gz_3IJSvP7-S6wD8NcnOlA-1; Mon, 08 Aug 2022 22:12:37 -0400 X-MC-Unique: Gz_3IJSvP7-S6wD8NcnOlA-1 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.rdu2.redhat.com [10.11.54.8]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id B9B9A1019E1D; Tue, 9 Aug 2022 02:12:36 +0000 (UTC) Received: from localhost.localdomain (vpn2-52-16.bne.redhat.com [10.64.52.16]) by smtp.corp.redhat.com (Postfix) with ESMTP id CE49DC15BA1; Tue, 9 Aug 2022 02:12:35 +0000 (UTC) From: Ronnie Sahlberg To: linux-cifs Cc: Steve French , Ronnie Sahlberg Subject: [PATCH 5/9] cifs: Do not access tcon->cfids->cfid directly from is_path_accessible Date: Tue, 9 Aug 2022 12:11:52 +1000 Message-Id: <20220809021156.3086869-6-lsahlber@redhat.com> In-Reply-To: <20220809021156.3086869-1-lsahlber@redhat.com> References: <20220809021156.3086869-1-lsahlber@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.85 on 10.11.54.8 Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org cfids will soon keep a list of cached fids so we should not access this directly from outside of cached_dir.c Signed-off-by: Ronnie Sahlberg Reviewed-by: Paulo Alcantara (SUSE) --- fs/cifs/cached_dir.c | 10 ++++++---- fs/cifs/cached_dir.h | 2 +- fs/cifs/readdir.c | 4 ++-- fs/cifs/smb2inode.c | 2 +- fs/cifs/smb2ops.c | 18 ++++++++++++++---- 5 files changed, 24 insertions(+), 12 deletions(-) diff --git a/fs/cifs/cached_dir.c b/fs/cifs/cached_dir.c index 604ac444ad25..1fb80b23bbeb 100644 --- a/fs/cifs/cached_dir.c +++ b/fs/cifs/cached_dir.c @@ -16,9 +16,9 @@ * If error then *cfid is not initialized. */ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, - const char *path, - struct cifs_sb_info *cifs_sb, - struct cached_fid **ret_cfid) + const char *path, + struct cifs_sb_info *cifs_sb, + bool lookup_only, struct cached_fid **ret_cfid) { struct cifs_ses *ses; struct TCP_Server_Info *server; @@ -68,9 +68,11 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, * cifs_mark_open_files_invalid() which takes the lock again * thus causing a deadlock */ - mutex_unlock(&cfid->fid_mutex); + if (lookup_only) + return -ENOENT; + if (smb3_encryption_required(tcon)) flags |= CIFS_TRANSFORM_REQ; diff --git a/fs/cifs/cached_dir.h b/fs/cifs/cached_dir.h index 4ea30a5ba4e7..5a384fad2432 100644 --- a/fs/cifs/cached_dir.h +++ b/fs/cifs/cached_dir.h @@ -54,7 +54,7 @@ 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, - struct cached_fid **cfid); + 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); diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index a06072ae6c7e..2eece8a07c11 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -1072,7 +1072,7 @@ int cifs_readdir(struct file *file, struct dir_context *ctx) tcon = tlink_tcon(cifsFile->tlink); } - rc = open_cached_dir(xid, tcon, full_path, cifs_sb, &cfid); + rc = open_cached_dir(xid, tcon, full_path, cifs_sb, false, &cfid); cifs_put_tlink(tlink); if (rc) goto cache_not_found; @@ -1143,7 +1143,7 @@ int cifs_readdir(struct file *file, struct dir_context *ctx) tcon = tlink_tcon(cifsFile->tlink); rc = find_cifs_entry(xid, tcon, ctx->pos, file, full_path, ¤t_entry, &num_to_fill); - open_cached_dir(xid, tcon, full_path, cifs_sb, &cfid); + open_cached_dir(xid, tcon, full_path, cifs_sb, false, &cfid); if (rc) { cifs_dbg(FYI, "fce error %d\n", rc); goto rddir2_exit; diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c index 9696184a09e3..b83f59051b26 100644 --- a/fs/cifs/smb2inode.c +++ b/fs/cifs/smb2inode.c @@ -516,7 +516,7 @@ smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, if (strcmp(full_path, "")) rc = -ENOENT; else - rc = open_cached_dir(xid, tcon, full_path, cifs_sb, &cfid); + rc = open_cached_dir(xid, tcon, full_path, cifs_sb, false, &cfid); /* If it is a root and its handle is cached then use it */ if (!rc) { if (cfid->file_all_info_is_valid) { diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 780ada4d8f6e..4727ee537f11 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -720,7 +720,7 @@ smb3_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon, oparms.fid = &fid; oparms.reconnect = false; - rc = open_cached_dir(xid, tcon, "", cifs_sb, &cfid); + rc = open_cached_dir(xid, tcon, "", cifs_sb, false, &cfid); if (rc == 0) memcpy(&fid, &cfid->fid, sizeof(struct cifs_fid)); else @@ -783,9 +783,16 @@ smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon, __u8 oplock = SMB2_OPLOCK_LEVEL_NONE; struct cifs_open_parms oparms; struct cifs_fid fid; + struct cached_fid *cfid; - if ((*full_path == 0) && tcon->cfids->cfid.is_valid) - return 0; + rc = open_cached_dir(xid, tcon, full_path, cifs_sb, true, &cfid); + if (!rc) { + if (cfid->is_valid) { + close_cached_dir(cfid); + return 0; + } + close_cached_dir(cfid); + } utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb); if (!utf16_path) @@ -2431,8 +2438,11 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon, resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER; memset(rsp_iov, 0, sizeof(rsp_iov)); + /* + * We can only call this for things we know are directories. + */ if (!strcmp(path, "")) - open_cached_dir(xid, tcon, path, cifs_sb, &cfid); /* cfid null if open dir failed */ + open_cached_dir(xid, tcon, path, cifs_sb, false, &cfid); /* cfid null if open dir failed */ memset(&open_iov, 0, sizeof(open_iov)); rqst[0].rq_iov = open_iov; From patchwork Tue Aug 9 02:11:53 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ronnie Sahlberg X-Patchwork-Id: 12939288 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 59D0FC25B08 for ; Tue, 9 Aug 2022 02:12:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229561AbiHICMh (ORCPT ); Mon, 8 Aug 2022 22:12:37 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57412 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229801AbiHICMh (ORCPT ); Mon, 8 Aug 2022 22:12:37 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 5C8FD1AD8A for ; Mon, 8 Aug 2022 19:12:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1660011155; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=JJSeaEmGZLdxqyPihWfcdZRcNML4br9XwqmzH7hM79Y=; b=QSV4FChWnVHWyxpRlGeqTbrGBZ5QuLvGjTivImpHsl00dHVc8fA7RG7R8i0E+xEQUF9Moc cqvvWaMZsm8NPvYffFdwVRdycx8CLmvnNtf+EVG6C3Xh6K1rwVs2N8GwbD/qpwZeRtZZTH 4gZ/p59xCG1WIo1HwaeAMjoLUyeuTpE= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-493-bX8OmvV-NbqyAdgC7FZAIA-1; Mon, 08 Aug 2022 22:12:34 -0400 X-MC-Unique: bX8OmvV-NbqyAdgC7FZAIA-1 Received: from smtp.corp.redhat.com (int-mx09.intmail.prod.int.rdu2.redhat.com [10.11.54.9]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id AB75F1884983; Tue, 9 Aug 2022 02:12:33 +0000 (UTC) Received: from localhost.localdomain (vpn2-52-16.bne.redhat.com [10.64.52.16]) by smtp.corp.redhat.com (Postfix) with ESMTP id 1A567492C3B; Tue, 9 Aug 2022 02:12:32 +0000 (UTC) From: Ronnie Sahlberg To: linux-cifs Cc: Steve French , Ronnie Sahlberg Subject: [PATCH 6/9] cifs: cifs: handlecache, only track the dentry for the root handle Date: Tue, 9 Aug 2022 12:11:53 +1000 Message-Id: <20220809021156.3086869-7-lsahlber@redhat.com> In-Reply-To: <20220809021156.3086869-1-lsahlber@redhat.com> References: <20220809021156.3086869-1-lsahlber@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.85 on 10.11.54.9 Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org Signed-off-by: Ronnie Sahlberg --- fs/cifs/cached_dir.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/fs/cifs/cached_dir.c b/fs/cifs/cached_dir.c index 1fb80b23bbeb..9423fee378f4 100644 --- a/fs/cifs/cached_dir.c +++ b/fs/cifs/cached_dir.c @@ -47,11 +47,12 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, if (cifs_sb->root == NULL) return -ENOENT; + if (!strlen(path)) + dentry = cifs_sb->root; + if (strlen(path)) return -ENOENT; - dentry = cifs_sb->root; - cfid = &tcon->cfids->cfid; mutex_lock(&cfid->fid_mutex); if (cfid->is_valid) { @@ -177,7 +178,8 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, cfid->tcon = tcon; cfid->is_valid = true; cfid->dentry = dentry; - dget(dentry); + if (dentry) + dget(dentry); kref_init(&cfid->refcount); /* BB TBD check to see if oplock level check can be removed below */ From patchwork Tue Aug 9 02:11:54 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ronnie Sahlberg X-Patchwork-Id: 12939290 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 43DEBC00140 for ; Tue, 9 Aug 2022 02:12:47 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229992AbiHICMq (ORCPT ); Mon, 8 Aug 2022 22:12:46 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57496 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230040AbiHICMp (ORCPT ); Mon, 8 Aug 2022 22:12:45 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id BE04A1BE98 for ; Mon, 8 Aug 2022 19:12:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1660011162; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=/TriPXjo/igwExy9roXWGRmwBhIx1FeSyqgk96SMukI=; b=NaA/xWwsU5y66mKm4S3AXvzaUUTpImP7wkpF6ESYELlX39i/2KLGHwtJO9Mnvnc+bOyh4D Jry7L38L9Rd7RhlYgEWNek8lIwRU1aYVuYFEMPcxi3+X6BDa8PfXL87dSeAVCKvlNuFN+3 nivUVOvhT6DKoE4m1RNN57gq+xWG0q8= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-104-LVXHBgFkM9GW6xjETse9vw-1; Mon, 08 Aug 2022 22:12:39 -0400 X-MC-Unique: LVXHBgFkM9GW6xjETse9vw-1 Received: from smtp.corp.redhat.com (int-mx09.intmail.prod.int.rdu2.redhat.com [10.11.54.9]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 804488041B5; Tue, 9 Aug 2022 02:12:39 +0000 (UTC) Received: from localhost.localdomain (vpn2-52-16.bne.redhat.com [10.64.52.16]) by smtp.corp.redhat.com (Postfix) with ESMTP id 92B27492C3B; Tue, 9 Aug 2022 02:12:38 +0000 (UTC) From: Ronnie Sahlberg To: linux-cifs Cc: Steve French , Ronnie Sahlberg Subject: [PATCH 7/9] cifs: store a pointer to a fid in the cfid structure instead of the struct Date: Tue, 9 Aug 2022 12:11:54 +1000 Message-Id: <20220809021156.3086869-8-lsahlber@redhat.com> In-Reply-To: <20220809021156.3086869-1-lsahlber@redhat.com> References: <20220809021156.3086869-1-lsahlber@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.85 on 10.11.54.9 Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org also create a constructor that takes a path name and stores it in the fid. Signed-off-by: Ronnie Sahlberg Reviewed-by: Paulo Alcantara (SUSE) --- fs/cifs/cached_dir.c | 63 ++++++++++++++++++++++++++++++++++++++------ fs/cifs/cached_dir.h | 4 ++- 2 files changed, 58 insertions(+), 9 deletions(-) diff --git a/fs/cifs/cached_dir.c b/fs/cifs/cached_dir.c index 9423fee378f4..5f2d01833f1e 100644 --- a/fs/cifs/cached_dir.c +++ b/fs/cifs/cached_dir.c @@ -11,6 +11,8 @@ #include "smb2proto.h" #include "cached_dir.h" +struct cached_fid *init_cached_dir(const char *path); + /* * Open the and cache a directory handle. * If error then *cfid is not initialized. @@ -53,7 +55,14 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, if (strlen(path)) return -ENOENT; - cfid = &tcon->cfids->cfid; + cfid = tcon->cfids->cfid; + if (cfid == NULL) { + cfid = init_cached_dir(path); + tcon->cfids->cfid = cfid; + } + if (cfid == NULL) + return -ENOMEM; + mutex_lock(&cfid->fid_mutex); if (cfid->is_valid) { cifs_dbg(FYI, "found a cached root file handle\n"); @@ -228,7 +237,9 @@ int open_cached_dir_by_dentry(struct cifs_tcon *tcon, { struct cached_fid *cfid; - cfid = &tcon->cfids->cfid; + cfid = tcon->cfids->cfid; + if (cfid == NULL) + return -ENOENT; mutex_lock(&cfid->fid_mutex); if (cfid->dentry == dentry) { @@ -322,7 +333,9 @@ void close_all_cached_dirs(struct cifs_sb_info *cifs_sb) tcon = tlink_tcon(tlink); if (IS_ERR(tcon)) continue; - cfid = &tcon->cfids->cfid; + cfid = tcon->cfids->cfid; + if (cfid == NULL) + continue; mutex_lock(&cfid->fid_mutex); if (cfid->dentry) { dput(cfid->dentry); @@ -338,7 +351,10 @@ void close_all_cached_dirs(struct cifs_sb_info *cifs_sb) */ void invalidate_all_cached_dirs(struct cifs_tcon *tcon) { - struct cached_fid *cfid = &tcon->cfids->cfid; + struct cached_fid *cfid = tcon->cfids->cfid; + + if (cfid == NULL) + return; mutex_lock(&cfid->fid_mutex); cfid->is_valid = false; @@ -359,7 +375,10 @@ smb2_cached_lease_break(struct work_struct *work) int cached_dir_lease_break(struct cifs_tcon *tcon, __u8 lease_key[16]) { - struct cached_fid *cfid = &tcon->cfids->cfid; + struct cached_fid *cfid = tcon->cfids->cfid; + + if (cfid == NULL) + return false; if (cfid->is_valid && !memcmp(lease_key, @@ -376,6 +395,32 @@ int cached_dir_lease_break(struct cifs_tcon *tcon, __u8 lease_key[16]) return false; } +struct cached_fid *init_cached_dir(const char *path) +{ + struct cached_fid *cfid; + + cfid = kzalloc(sizeof(*cfid), GFP_KERNEL); + if (!cfid) + return NULL; + cfid->path = kstrdup(path, GFP_KERNEL); + if (!cfid->path) { + kfree(cfid); + return NULL; + } + + INIT_LIST_HEAD(&cfid->dirents.entries); + mutex_init(&cfid->dirents.de_mutex); + mutex_init(&cfid->fid_mutex); + return cfid; +} + +void free_cached_dir(struct cached_fid *cfid) +{ + kfree(cfid->path); + cfid->path = NULL; + kfree(cfid); +} + struct cached_fids *init_cached_dirs(void) { struct cached_fids *cfids; @@ -383,13 +428,15 @@ struct cached_fids *init_cached_dirs(void) cfids = kzalloc(sizeof(*cfids), GFP_KERNEL); if (!cfids) return NULL; - INIT_LIST_HEAD(&cfids->cfid.dirents.entries); - mutex_init(&cfids->cfid.dirents.de_mutex); - mutex_init(&cfids->cfid.fid_mutex); + mutex_init(&cfids->cfid_list_mutex); return cfids; } void free_cached_dirs(struct cached_fids *cfids) { + if (cfids->cfid) { + free_cached_dir(cfids->cfid); + cfids->cfid = NULL; + } kfree(cfids); } diff --git a/fs/cifs/cached_dir.h b/fs/cifs/cached_dir.h index 5a384fad2432..d34ff3e31488 100644 --- a/fs/cifs/cached_dir.h +++ b/fs/cifs/cached_dir.h @@ -31,6 +31,7 @@ struct cached_dirents { }; struct cached_fid { + const char *path; bool is_valid:1; /* Do we have a useable root fid */ bool file_all_info_is_valid:1; bool has_lease:1; @@ -46,7 +47,8 @@ struct cached_fid { }; struct cached_fids { - struct cached_fid cfid; + struct mutex cfid_list_mutex; + struct cached_fid *cfid; }; extern struct cached_fids *init_cached_dirs(void); From patchwork Tue Aug 9 02:11:55 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ronnie Sahlberg X-Patchwork-Id: 12939287 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A1E72C25B0C for ; Tue, 9 Aug 2022 02:12:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229978AbiHICMh (ORCPT ); Mon, 8 Aug 2022 22:12:37 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57396 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229561AbiHICMg (ORCPT ); Mon, 8 Aug 2022 22:12:36 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 7696918B09 for ; Mon, 8 Aug 2022 19:12:35 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1660011154; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=L9pb8XpAZo2T2JOXX4BO8Nz9PSwDrlA0iAyjtKJ6KSE=; b=FbW4RcS3SncS2Ve3FSzR1mO35TXtpwtyVR6zRlR1JWTQ6imQxU4DjbW5T0fn5clG6u/QPt N7dydmDmV4erv6fJtyY4yMlfSYzP42AfoUV8q7McfupfoCkyIZQZ76yqrRI3JEJVm4H1Gg YerNANyeZ7nej9yIGAbJInIE4JcouKA= Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-617-jAkWa0_jNMy7GgwK_j362A-1; Mon, 08 Aug 2022 22:12:31 -0400 X-MC-Unique: jAkWa0_jNMy7GgwK_j362A-1 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id EE6C128084EC; Tue, 9 Aug 2022 02:12:30 +0000 (UTC) Received: from localhost.localdomain (vpn2-52-16.bne.redhat.com [10.64.52.16]) by smtp.corp.redhat.com (Postfix) with ESMTP id 4B17294585; Tue, 9 Aug 2022 02:12:29 +0000 (UTC) From: Ronnie Sahlberg To: linux-cifs Cc: Steve French , Ronnie Sahlberg Subject: [PATCH 8/9] cifs: don't unlock cifs_tcp_ses_lock in cached_dir_lease_break() Date: Tue, 9 Aug 2022 12:11:55 +1000 Message-Id: <20220809021156.3086869-9-lsahlber@redhat.com> In-Reply-To: <20220809021156.3086869-1-lsahlber@redhat.com> References: <20220809021156.3086869-1-lsahlber@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.11.54.5 Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org Unlock it from the caller, which is also where the lock is taken. Signed-off-by: Ronnie Sahlberg Reviewed-by: Paulo Alcantara (SUSE) --- fs/cifs/cached_dir.c | 1 - fs/cifs/smb2misc.c | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/cifs/cached_dir.c b/fs/cifs/cached_dir.c index 5f2d01833f1e..9d221f0bf976 100644 --- a/fs/cifs/cached_dir.c +++ b/fs/cifs/cached_dir.c @@ -389,7 +389,6 @@ int cached_dir_lease_break(struct cifs_tcon *tcon, __u8 lease_key[16]) smb2_cached_lease_break); queue_work(cifsiod_wq, &cfid->lease_break); - spin_unlock(&cifs_tcp_ses_lock); return true; } return false; diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c index d3d9174ddd7c..2cc038aca5bc 100644 --- a/fs/cifs/smb2misc.c +++ b/fs/cifs/smb2misc.c @@ -640,8 +640,10 @@ smb2_is_valid_lease_break(char *buffer) } spin_unlock(&tcon->open_file_lock); - if (cached_dir_lease_break(tcon, rsp->LeaseKey)) + if (cached_dir_lease_break(tcon, rsp->LeaseKey)) { + spin_unlock(&cifs_tcp_ses_lock); return true; + } } } } From patchwork Tue Aug 9 02:11:56 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ronnie Sahlberg X-Patchwork-Id: 12939286 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A5157C00140 for ; Tue, 9 Aug 2022 02:12:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229793AbiHICMg (ORCPT ); Mon, 8 Aug 2022 22:12:36 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57380 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229561AbiHICMe (ORCPT ); Mon, 8 Aug 2022 22:12:34 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 9F3AB18B09 for ; Mon, 8 Aug 2022 19:12:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1660011151; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=PXM1d8Uok41O48+K5amnx6mdUbG4W4xv3HefM2tivX8=; b=BuJzn86QJHUf1PI/zv50EmS4uuodgNdKeg9V/UCxPysUj+IUUBlXA2xWH8aTjvinshe17M QYzJz5idjKE7C2InMNP+T9GiY/K9I1SANrTtmUbAJYi2esmkcA9v7DUbppYdjbpgVf+CwI eg+NGx8pxxJ6XUwaCJBupHhz+l4mpo8= Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-536-eLZNSmluMnesjuKb8BkupQ-1; Mon, 08 Aug 2022 22:12:28 -0400 X-MC-Unique: eLZNSmluMnesjuKb8BkupQ-1 Received: from smtp.corp.redhat.com (int-mx10.intmail.prod.int.rdu2.redhat.com [10.11.54.10]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id ECCA83804535; Tue, 9 Aug 2022 02:12:27 +0000 (UTC) Received: from localhost.localdomain (vpn2-52-16.bne.redhat.com [10.64.52.16]) by smtp.corp.redhat.com (Postfix) with ESMTP id A1C21400F36; Tue, 9 Aug 2022 02:12:26 +0000 (UTC) From: Ronnie Sahlberg To: linux-cifs Cc: Steve French , Ronnie Sahlberg Subject: [PATCH 9/9] cifs: start caching all directories we open and get a lease for Date: Tue, 9 Aug 2022 12:11:56 +1000 Message-Id: <20220809021156.3086869-10-lsahlber@redhat.com> In-Reply-To: <20220809021156.3086869-1-lsahlber@redhat.com> References: <20220809021156.3086869-1-lsahlber@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.85 on 10.11.54.10 Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org Signed-off-by: Ronnie Sahlberg --- fs/cifs/cached_dir.c | 396 ++++++++++++++++++++++++------------------- fs/cifs/cached_dir.h | 18 +- fs/cifs/inode.c | 7 +- fs/cifs/smb2ops.c | 2 +- 4 files changed, 240 insertions(+), 183 deletions(-) diff --git a/fs/cifs/cached_dir.c b/fs/cifs/cached_dir.c index 9d221f0bf976..4ae9c897eeae 100644 --- a/fs/cifs/cached_dir.c +++ b/fs/cifs/cached_dir.c @@ -11,7 +11,55 @@ #include "smb2proto.h" #include "cached_dir.h" -struct cached_fid *init_cached_dir(const char *path); +static struct cached_fid *init_cached_dir(const char *path); +static void smb2_close_cached_fid(struct kref *ref); +static void smb2_drop_cached_fid_locked(struct kref *ref); +static void free_cached_dir(struct cached_fid *cfid); + +static struct cached_fid *find_or_create_cached_dir(struct cached_fids *cfids, + const char *path, + bool lookup_only) +{ + struct cached_fid *cfid; + + spin_lock(&cfids->cfid_list_lock); + list_for_each_entry(cfid, &cfids->entries, entry) { + if (!strcmp(cfid->path, path)) { + /* + * If it doesn't have a lease it is either not yet + * fully cached or it may be in the process of + * being deleted due to a lease break. + */ + if (!cfid->has_lease) { + spin_unlock(&cfids->cfid_list_lock); + return NULL; + } + kref_get(&cfid->refcount); + spin_unlock(&cfids->cfid_list_lock); + return cfid; + } + } + if (lookup_only) { + spin_unlock(&cfids->cfid_list_lock); + return NULL; + } + if (cfids->num_entries >= MAX_CACHED_FIDS) { + spin_unlock(&cfids->cfid_list_lock); + return NULL; + } + cfid = init_cached_dir(path); + if (cfid == NULL) { + spin_unlock(&cfids->cfid_list_lock); + return NULL; + } + cfid->cfids = cfids; + cfids->num_entries++; + list_add(&cfid->entry, &cfids->entries); + /* should we do this get in open_cached_dir() instead ? */ + kref_get(&cfid->refcount); + spin_unlock(&cfids->cfid_list_lock); + return cfid; +} /* * Open the and cache a directory handle. @@ -33,42 +81,45 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, struct kvec open_iov[SMB2_CREATE_IOV_SIZE]; struct kvec qi_iov[1]; int rc, flags = 0; - __le16 utf16_path = 0; /* Null - since an open of top of share */ + __le16 *utf16_path = NULL; u8 oplock = SMB2_OPLOCK_LEVEL_II; struct cifs_fid *pfid; - struct dentry *dentry; + struct dentry *dentry = NULL; struct cached_fid *cfid; + struct cached_fids *cfids; - if (tcon == NULL || tcon->nohandlecache || + + if (tcon == NULL || tcon->cfids == NULL || tcon->nohandlecache || is_smb1_server(tcon->ses->server)) return -ENOTSUPP; ses = tcon->ses; server = ses->server; + cfids = tcon->cfids; if (cifs_sb->root == NULL) return -ENOENT; + /* + * TODO: for better caching we need to find and use the dentry also + * for non-root directories. + */ if (!strlen(path)) dentry = cifs_sb->root; - if (strlen(path)) - return -ENOENT; + utf16_path = cifs_convert_path_to_utf16(path, cifs_sb); + if (!utf16_path) + return -ENOMEM; - cfid = tcon->cfids->cfid; + cfid = find_or_create_cached_dir(cfids, path, lookup_only); if (cfid == NULL) { - cfid = init_cached_dir(path); - tcon->cfids->cfid = cfid; + kfree(utf16_path); + return -ENOENT; } - if (cfid == NULL) - return -ENOMEM; - - mutex_lock(&cfid->fid_mutex); - if (cfid->is_valid) { + if (cfid->has_lease) { cifs_dbg(FYI, "found a cached root file handle\n"); *ret_cfid = cfid; - kref_get(&cfid->refcount); - mutex_unlock(&cfid->fid_mutex); + kfree(utf16_path); return 0; } @@ -78,17 +129,13 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, * cifs_mark_open_files_invalid() which takes the lock again * thus causing a deadlock */ - mutex_unlock(&cfid->fid_mutex); - - if (lookup_only) - return -ENOENT; - if (smb3_encryption_required(tcon)) flags |= CIFS_TRANSFORM_REQ; - if (!server->ops->new_lease_key) + if (!server->ops->new_lease_key) { + kfree(utf16_path); return -EIO; - + } pfid = &cfid->fid; server->ops->new_lease_key(pfid); @@ -109,7 +156,7 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, oparms.reconnect = false; rc = SMB2_open_init(tcon, server, - &rqst[0], &oplock, &oparms, &utf16_path); + &rqst[0], &oplock, &oparms, utf16_path); if (rc) goto oshr_free; smb2_set_next_command(tcon, &rqst[0]); @@ -132,47 +179,13 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, rc = compound_send_recv(xid, ses, server, flags, 2, rqst, resp_buftype, rsp_iov); - mutex_lock(&cfid->fid_mutex); - - /* - * Now we need to check again as the cached root might have - * been successfully re-opened from a concurrent process - */ - - if (cfid->is_valid) { - /* work was already done */ - - /* stash fids for close() later */ - struct cifs_fid fid = { - .persistent_fid = pfid->persistent_fid, - .volatile_fid = pfid->volatile_fid, - }; - - /* - * caller expects this func to set the fid in cfid to valid - * cached root, so increment the refcount. - */ - kref_get(&cfid->refcount); - - mutex_unlock(&cfid->fid_mutex); - - if (rc == 0) { - /* close extra handle outside of crit sec */ - SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid); - } - rc = 0; - goto oshr_free; - } - - /* Cached root is still invalid, continue normaly */ - if (rc) { if (rc == -EREMCHG) { tcon->need_reconnect = true; pr_warn_once("server share %s deleted\n", tcon->treeName); } - goto oshr_exit; + goto oshr_free; } atomic_inc(&tcon->num_remote_opens); @@ -185,30 +198,23 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, #endif /* CIFS_DEBUG2 */ cfid->tcon = tcon; - cfid->is_valid = true; - cfid->dentry = dentry; - if (dentry) + if (dentry) { + cfid->dentry = dentry; dget(dentry); - kref_init(&cfid->refcount); - + } /* BB TBD check to see if oplock level check can be removed below */ - if (o_rsp->OplockLevel == SMB2_OPLOCK_LEVEL_LEASE) { - /* - * See commit 2f94a3125b87. Increment the refcount when we - * get a lease for root, release it if lease break occurs - */ - kref_get(&cfid->refcount); - cfid->has_lease = true; - smb2_parse_contexts(server, o_rsp, - &oparms.fid->epoch, - oparms.fid->lease_key, &oplock, - NULL, NULL); - } else - goto oshr_exit; + if (o_rsp->OplockLevel != SMB2_OPLOCK_LEVEL_LEASE) { + goto oshr_free; + } + smb2_parse_contexts(server, o_rsp, + &oparms.fid->epoch, + oparms.fid->lease_key, &oplock, + NULL, NULL); + qi_rsp = (struct smb2_query_info_rsp *)rsp_iov[1].iov_base; if (le32_to_cpu(qi_rsp->OutputBufferLength) < sizeof(struct smb2_file_all_info)) - goto oshr_exit; + goto oshr_free; if (!smb2_validate_and_copy_iov( le16_to_cpu(qi_rsp->OutputBufferOffset), sizeof(struct smb2_file_all_info), @@ -216,15 +222,23 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, (char *)&cfid->file_all_info)) cfid->file_all_info_is_valid = true; cfid->time = jiffies; + cfid->has_lease = true; -oshr_exit: - mutex_unlock(&cfid->fid_mutex); oshr_free: + kfree(utf16_path); SMB2_open_free(&rqst[0]); 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 (!cfid->has_lease) { + spin_lock(&cfids->cfid_list_lock); + cfids->num_entries--; + list_del_init(&cfid->entry); + spin_unlock(&cfids->cfid_list_lock); + free_cached_dir(cfid); + rc = -ENOENT; + } if (rc == 0) { *ret_cfid = cfid; } @@ -236,85 +250,90 @@ int open_cached_dir_by_dentry(struct cifs_tcon *tcon, struct cached_fid **ret_cfid) { struct cached_fid *cfid; + struct cached_fids *cfids = tcon->cfids; - cfid = tcon->cfids->cfid; - if (cfid == NULL) + if (cfids == NULL) return -ENOENT; - mutex_lock(&cfid->fid_mutex); - if (cfid->dentry == dentry) { - cifs_dbg(FYI, "found a cached root file handle by dentry\n"); - *ret_cfid = cfid; - kref_get(&cfid->refcount); - mutex_unlock(&cfid->fid_mutex); - return 0; + spin_lock(&cfids->cfid_list_lock); + list_for_each_entry(cfid, &cfids->entries, entry) { + if (dentry && cfid->dentry == dentry) { + cifs_dbg(FYI, "found a cached root file handle by dentry\n"); + kref_get(&cfid->refcount); + *ret_cfid = cfid; + spin_unlock(&cfids->cfid_list_lock); + return 0; + } } - mutex_unlock(&cfid->fid_mutex); + spin_unlock(&cfids->cfid_list_lock); return -ENOENT; } static void -smb2_close_cached_fid(struct kref *ref) +smb2_close_cached_fid_internal(struct kref *ref, bool locked) { struct cached_fid *cfid = container_of(ref, struct cached_fid, refcount); - struct cached_dirent *dirent, *q; - if (cfid->is_valid) { + if (!locked) + spin_lock(&cfid->cfids->cfid_list_lock); + cfid->cfids->num_entries--; + list_del_init(&cfid->entry); + if (cfid->dentry) + dput(cfid->dentry); + if (!locked) + spin_unlock(&cfid->cfids->cfid_list_lock); + + if (cfid->has_lease) { cifs_dbg(FYI, "clear cached root file handle\n"); SMB2_close(0, cfid->tcon, cfid->fid.persistent_fid, cfid->fid.volatile_fid); } + free_cached_dir(cfid); +} + +static void +smb2_close_cached_fid(struct kref *ref) +{ + smb2_close_cached_fid_internal(ref, false); +} + +static void +smb2_drop_cached_fid_locked(struct kref *ref) +{ + struct cached_fid *cfid = container_of(ref, struct cached_fid, + refcount); /* - * We only check validity above to send SMB2_close, - * but we still need to invalidate these entries - * when this function is called + * If the caller already holds cfid_list_lock we must force have_lease + * to be false in order to avoid calling the blocking function + * SMB2_close(). This could leave the file open on the server so we + * must only call smb2_drop_cached_fid_locked IFF + * - we know all handles are closed becase we are about to disconnect + * the share during umount. + * - we have lost the session so all open files are implicitely closed + * anyway. */ - cfid->is_valid = false; - cfid->file_all_info_is_valid = false; cfid->has_lease = false; - if (cfid->dentry) { - dput(cfid->dentry); - cfid->dentry = NULL; - } - /* - * Delete all cached dirent names - */ - mutex_lock(&cfid->dirents.de_mutex); - list_for_each_entry_safe(dirent, q, &cfid->dirents.entries, entry) { - list_del(&dirent->entry); - 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); - + smb2_close_cached_fid_internal(ref, true); } void close_cached_dir(struct cached_fid *cfid) { - mutex_lock(&cfid->fid_mutex); kref_put(&cfid->refcount, smb2_close_cached_fid); - mutex_unlock(&cfid->fid_mutex); -} - -void close_cached_dir_lease_locked(struct cached_fid *cfid) -{ - if (cfid->has_lease) { - cfid->has_lease = false; - kref_put(&cfid->refcount, smb2_close_cached_fid); - } } -void close_cached_dir_lease(struct cached_fid *cfid) +static void close_cached_dir_lease(struct cached_fid *cfid) { - mutex_lock(&cfid->fid_mutex); - close_cached_dir_lease_locked(cfid); - mutex_unlock(&cfid->fid_mutex); + /* + * TODO: If this is not the last reference then we + * we must send a lease break ack and flag this dir as not + * being cached. + * This is to handle the situation where an app holds opendir() + * open for a long time during which we get a lease break from the + * server. + */ + kref_put(&cfid->refcount, smb2_close_cached_fid); } /* @@ -327,41 +346,41 @@ void close_all_cached_dirs(struct cifs_sb_info *cifs_sb) struct cached_fid *cfid; struct cifs_tcon *tcon; struct tcon_link *tlink; + struct cached_fids *cfids; for (node = rb_first(root); node; node = rb_next(node)) { tlink = rb_entry(node, struct tcon_link, tl_rbnode); tcon = tlink_tcon(tlink); if (IS_ERR(tcon)) continue; - cfid = tcon->cfids->cfid; - if (cfid == NULL) + cfids = tcon->cfids; + if (cfids == NULL) continue; - mutex_lock(&cfid->fid_mutex); - if (cfid->dentry) { - dput(cfid->dentry); - cfid->dentry = NULL; + list_for_each_entry(cfid, &cfids->entries, entry) { + if (cfid->dentry) { + dput(cfid->dentry); + cfid->dentry = NULL; + } } - mutex_unlock(&cfid->fid_mutex); } } /* - * Invalidate and close all cached dirs when a TCON has been reset + * Invalidate all cached dirs when a TCON has been reset * due to a session loss. */ void invalidate_all_cached_dirs(struct cifs_tcon *tcon) { - struct cached_fid *cfid = tcon->cfids->cfid; - - if (cfid == NULL) - return; - - mutex_lock(&cfid->fid_mutex); - cfid->is_valid = false; - /* cached handle is not valid, so SMB2_CLOSE won't be sent below */ - close_cached_dir_lease_locked(cfid); - memset(&cfid->fid, 0, sizeof(struct cifs_fid)); - mutex_unlock(&cfid->fid_mutex); + struct cached_fids *cfids = tcon->cfids; + struct cached_fid *cfid, *q; + + spin_lock(&cfids->cfid_list_lock); + list_for_each_entry_safe(cfid, q, &cfids->entries, entry) { + cfids->num_entries--; + list_del_init(&cfid->entry); + kref_put(&cfid->refcount, smb2_drop_cached_fid_locked); + } + spin_unlock(&cfids->cfid_list_lock); } static void @@ -375,33 +394,39 @@ smb2_cached_lease_break(struct work_struct *work) int cached_dir_lease_break(struct cifs_tcon *tcon, __u8 lease_key[16]) { - struct cached_fid *cfid = tcon->cfids->cfid; + struct cached_fids *cfids = tcon->cfids; + struct cached_fid *cfid; - if (cfid == NULL) + if (cfids == NULL) return false; - if (cfid->is_valid && - !memcmp(lease_key, - cfid->fid.lease_key, - SMB2_LEASE_KEY_SIZE)) { - cfid->time = 0; - INIT_WORK(&cfid->lease_break, - smb2_cached_lease_break); - queue_work(cifsiod_wq, - &cfid->lease_break); - return true; + spin_lock(&cfids->cfid_list_lock); + list_for_each_entry(cfid, &cfids->entries, entry) { + if (cfid->has_lease && + !memcmp(lease_key, + cfid->fid.lease_key, + SMB2_LEASE_KEY_SIZE)) { + cfid->time = 0; + INIT_WORK(&cfid->lease_break, + smb2_cached_lease_break); + queue_work(cifsiod_wq, + &cfid->lease_break); + spin_unlock(&cfids->cfid_list_lock); + return true; + } } + spin_unlock(&cfids->cfid_list_lock); return false; } -struct cached_fid *init_cached_dir(const char *path) +static struct cached_fid *init_cached_dir(const char *path) { struct cached_fid *cfid; - cfid = kzalloc(sizeof(*cfid), GFP_KERNEL); + cfid = kzalloc(sizeof(*cfid), GFP_ATOMIC); if (!cfid) return NULL; - cfid->path = kstrdup(path, GFP_KERNEL); + cfid->path = kstrdup(path, GFP_ATOMIC); if (!cfid->path) { kfree(cfid); return NULL; @@ -409,12 +434,29 @@ struct cached_fid *init_cached_dir(const char *path) INIT_LIST_HEAD(&cfid->dirents.entries); mutex_init(&cfid->dirents.de_mutex); - mutex_init(&cfid->fid_mutex); + spin_lock_init(&cfid->fid_lock); + kref_init(&cfid->refcount); return cfid; } -void free_cached_dir(struct cached_fid *cfid) +static void free_cached_dir(struct cached_fid *cfid) { + struct cached_dirent *dirent, *q; + + if (cfid->dentry) { + dput(cfid->dentry); + cfid->dentry = NULL; + } + + /* + * Delete all cached dirent names + */ + list_for_each_entry_safe(dirent, q, &cfid->dirents.entries, entry) { + list_del(&dirent->entry); + kfree(dirent->name); + kfree(dirent); + } + kfree(cfid->path); cfid->path = NULL; kfree(cfid); @@ -427,15 +469,25 @@ struct cached_fids *init_cached_dirs(void) cfids = kzalloc(sizeof(*cfids), GFP_KERNEL); if (!cfids) return NULL; - mutex_init(&cfids->cfid_list_mutex); + spin_lock_init(&cfids->cfid_list_lock); + INIT_LIST_HEAD(&cfids->entries); return cfids; } +/* + * Called from tconInfoFree when we are tearing down the tcon. + * There are no active users or open files/directories at this point. + */ void free_cached_dirs(struct cached_fids *cfids) { - if (cfids->cfid) { - free_cached_dir(cfids->cfid); - cfids->cfid = NULL; + struct cached_fid *cfid, *q; + + spin_lock(&cfids->cfid_list_lock); + list_for_each_entry_safe(cfid, q, &cfids->entries, entry) { + cfids->num_entries--; + list_del_init(&cfid->entry); + free_cached_dir(cfid); } - kfree(cfids); + spin_unlock(&cfids->cfid_list_lock); + kfree(cfids); } diff --git a/fs/cifs/cached_dir.h b/fs/cifs/cached_dir.h index d34ff3e31488..c6df8804afb4 100644 --- a/fs/cifs/cached_dir.h +++ b/fs/cifs/cached_dir.h @@ -31,14 +31,15 @@ struct cached_dirents { }; struct cached_fid { + struct list_head entry; + struct cached_fids *cfids; const char *path; - bool is_valid:1; /* Do we have a useable root fid */ - bool file_all_info_is_valid:1; bool has_lease:1; + bool file_all_info_is_valid:1; unsigned long time; /* jiffies of when lease was taken */ struct kref refcount; struct cifs_fid fid; - struct mutex fid_mutex; + spinlock_t fid_lock; struct cifs_tcon *tcon; struct dentry *dentry; struct work_struct lease_break; @@ -46,9 +47,14 @@ struct cached_fid { struct cached_dirents dirents; }; +#define MAX_CACHED_FIDS 16 struct cached_fids { - struct mutex cfid_list_mutex; - struct cached_fid *cfid; + /* Must be held when: + * - accessing the cfids->entries list + */ + spinlock_t cfid_list_lock; + int num_entries; + struct list_head entries; }; extern struct cached_fids *init_cached_dirs(void); @@ -61,8 +67,6 @@ 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 close_cached_dir_lease(struct cached_fid *cfid); -extern void close_cached_dir_lease_locked(struct cached_fid *cfid); 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]); diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 7714f47d199b..7d17d20502ca 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -2225,15 +2225,16 @@ cifs_dentry_needs_reval(struct dentry *dentry) return true; if (!open_cached_dir_by_dentry(tcon, dentry->d_parent, &cfid)) { - mutex_lock(&cfid->fid_mutex); + spin_lock(&cfid->fid_lock); if (cfid->time && cifs_i->time > cfid->time) { - mutex_unlock(&cfid->fid_mutex); + spin_unlock(&cfid->fid_lock); close_cached_dir(cfid); return false; } - mutex_unlock(&cfid->fid_mutex); + spin_unlock(&cfid->fid_lock); close_cached_dir(cfid); } + /* * depending on inode type, check if attribute caching disabled for * files or directories diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 4727ee537f11..2204a19517cd 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -787,7 +787,7 @@ smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon, rc = open_cached_dir(xid, tcon, full_path, cifs_sb, true, &cfid); if (!rc) { - if (cfid->is_valid) { + if (cfid->has_lease) { close_cached_dir(cfid); return 0; }