Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/1.1/patches/2229730/?format=api
{ "id": 2229730, "url": "http://patchwork.ozlabs.org/api/1.1/patches/2229730/?format=api", "web_url": "http://patchwork.ozlabs.org/project/linux-cifs-client/patch/20260428160804.281745-8-sprasad@microsoft.com/", "project": { "id": 12, "url": "http://patchwork.ozlabs.org/api/1.1/projects/12/?format=api", "name": "Linux CIFS Client", "link_name": "linux-cifs-client", "list_id": "linux-cifs.vger.kernel.org", "list_email": "linux-cifs@vger.kernel.org", "web_url": "", "scm_url": "", "webscm_url": "" }, "msgid": "<20260428160804.281745-8-sprasad@microsoft.com>", "date": "2026-04-28T16:07:53", "name": "[v3,08/19] cifs: make cfid locks more granular", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "036c5c2442d0c833e1bdabb074aee32e3c967540", "submitter": { "id": 79368, "url": "http://patchwork.ozlabs.org/api/1.1/people/79368/?format=api", "name": "Shyam Prasad N", "email": "nspmangalore@gmail.com" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/linux-cifs-client/patch/20260428160804.281745-8-sprasad@microsoft.com/mbox/", "series": [ { "id": 501896, "url": "http://patchwork.ozlabs.org/api/1.1/series/501896/?format=api", "web_url": "http://patchwork.ozlabs.org/project/linux-cifs-client/list/?series=501896", "date": "2026-04-28T16:07:57", "name": "[v3,01/19] cifs: change_conf needs to be called for session setup", "version": 3, "mbox": "http://patchwork.ozlabs.org/series/501896/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2229730/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2229730/checks/", "tags": {}, "headers": { "Return-Path": "\n <linux-cifs+bounces-11245-incoming=patchwork.ozlabs.org@vger.kernel.org>", "X-Original-To": [ "incoming@patchwork.ozlabs.org", "linux-cifs@vger.kernel.org" ], "Delivered-To": "patchwork-incoming@legolas.ozlabs.org", "Authentication-Results": [ "legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256\n header.s=20251104 header.b=srlUEsiC;\n\tdkim-atps=neutral", "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org\n (client-ip=2600:3c04:e001:36c::12fc:5321; helo=tor.lore.kernel.org;\n envelope-from=linux-cifs+bounces-11245-incoming=patchwork.ozlabs.org@vger.kernel.org;\n receiver=patchwork.ozlabs.org)", "smtp.subspace.kernel.org;\n\tdkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com\n header.b=\"srlUEsiC\"", "smtp.subspace.kernel.org;\n arc=none smtp.client-ip=209.85.214.181", "smtp.subspace.kernel.org;\n dmarc=pass (p=none dis=none) header.from=gmail.com", "smtp.subspace.kernel.org;\n spf=pass smtp.mailfrom=gmail.com" ], "Received": [ "from tor.lore.kernel.org (tor.lore.kernel.org\n [IPv6:2600:3c04:e001:36c::12fc:5321])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g4mNc1sWRz1yJH\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 29 Apr 2026 02:39:12 +1000 (AEST)", "from smtp.subspace.kernel.org (conduit.subspace.kernel.org\n [100.90.174.1])\n\tby tor.lore.kernel.org (Postfix) with ESMTP id CD8793194C5F\n\tfor <incoming@patchwork.ozlabs.org>; Tue, 28 Apr 2026 16:14:37 +0000 (UTC)", "from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id 41D2B44D015;\n\tTue, 28 Apr 2026 16:08:30 +0000 (UTC)", "from mail-pl1-f181.google.com (mail-pl1-f181.google.com\n [209.85.214.181])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits))\n\t(No client certificate requested)\n\tby smtp.subspace.kernel.org (Postfix) with ESMTPS id 2B91644BCB6\n\tfor <linux-cifs@vger.kernel.org>; Tue, 28 Apr 2026 16:08:28 +0000 (UTC)", "by mail-pl1-f181.google.com with SMTP id\n d9443c01a7336-2ad617d5b80so70841705ad.1\n for <linux-cifs@vger.kernel.org>;\n Tue, 28 Apr 2026 09:08:28 -0700 (PDT)", "from sprasad-dev1.corp.microsoft.com ([167.220.110.216])\n by smtp.gmail.com with ESMTPSA id\n d9443c01a7336-2b97ac7894csm30864465ad.50.2026.04.28.09.08.25\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Tue, 28 Apr 2026 09:08:26 -0700 (PDT)" ], "ARC-Seal": "i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1777392510; cv=none;\n b=YzqFX3M48q8r4VujpYkdxQdBId2mQDJ/wWfenKp+9KRLopE3bTaRSEgzRlrHS1/dpnx2NwRiMdzh9pUtUH118yJoeF6FRSRA2dPzaAhgqXgixIvfhHe20IQcREmAi8MY4Hf7pM4GOO41GQal8pxX3iCrDvfnZQz1NkgtIzqF0Ws=", "ARC-Message-Signature": "i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1777392510; c=relaxed/simple;\n\tbh=u+MpqVgdB0XSJ4fjpKzAuMq3OK7F1knU2Vg6hZjp8T8=;\n\th=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References:\n\t MIME-Version;\n b=mLyPCVNuZ14ldnOo6mYpsZiHiQQzeBfvTX9PvE6vkHkp3rqMuzaZAehQomVRA45yeUC61N59KhYuV1KhH5Rs7RdWlrAvIoCpfBVfHthZuPE9H1B3u26G+sNzXhGISCKMm+rwQvvYQrdvlumD8b/vH+G3v6v3o//8M9CGbqGCf50=", "ARC-Authentication-Results": "i=1; smtp.subspace.kernel.org;\n dmarc=pass (p=none dis=none) header.from=gmail.com;\n spf=pass smtp.mailfrom=gmail.com;\n dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com\n header.b=srlUEsiC; arc=none smtp.client-ip=209.85.214.181", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=gmail.com; s=20251104; t=1777392507; x=1777997307;\n darn=vger.kernel.org;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:cc:to:from:from:to:cc:subject:date\n :message-id:reply-to;\n bh=r5/qzlozqLXx32LaLMX29vWWxo1OoGpelKukRnnwjFU=;\n b=srlUEsiC35nu5cr2oAU+mnDYUz3q/7uJB7jcC6Ye3XkyUubV4/BlWe38z8y4oRjOA6\n pOm8ivw5UzTPhWuuHkaMXxUvByMO+NPj4Wyu9s27+A5RtErdpmnssXBaWtjEKitLnmXx\n PO32OimuWf+POA/Tlwdf/StR3ni+XJCtxvo4QwiDGnbMC5SSa2D4xZMEjp4JBBQAwF6h\n b0jTy9WLEp05Z31PMjOamTvVHUGdp0FBzQVNdmAjappDdg1YuzlhNAFxsyEymoodcXcY\n Jy+nzjLhPWPFM9Qxq6dpqY2oTQtQmm8Cd6TE8XQ7lueV831ymTFyYKQe1N2V7ANiv10c\n VfyQ==", "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1777392507; x=1777997307;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from\n :to:cc:subject:date:message-id:reply-to;\n bh=r5/qzlozqLXx32LaLMX29vWWxo1OoGpelKukRnnwjFU=;\n b=r8MOb9pIoDQUWsFsS5cdpcV3EARYqhNeIghoUb8CWrEmCH8vczorGcjHhPrZPyGiqX\n Tstk+ZVjPZVUeaMw1qtsQmHEyB/KnWwlFYhbqQPrmSLHSlOGJ09Nnkt2Ivz+1cmGA8AL\n GoMxbeNYADUXAzYa+4uiEv45+4bewlJoEIfLxHDnZayLo2xcz5ZtlhEwnBkimhlBuz14\n LvpuOzUS7iUvtxNNaYuBPl9nhpdatUKGRIznzZCh9FkxW61LzV8zIDWhfYvmKXmT2sfQ\n ysEMjKZebJJv15p8W0oAjBIS9yLA+OplxlRUEu59pGEC/Q/TiQNLyewpVT0S7Cy9dcie\n oSPA==", "X-Gm-Message-State": "AOJu0YxGolQtgqzfijtat3E6yj3+TDxiReZDWpk5KY0F1i2xzu7RHwws\n\tNZFQEhoAqVqs7lreclVTpQEFYJLf6piPQplpUfGRXYlhQ0b+xUukAb54M/pJ4OIwcRg=", "X-Gm-Gg": "AeBDievSNkdx634fBmwUeTPoDq8vVa8vWzpdPRTeTsDJ6re44/PUpwRGKXoHK1kWjGC\n\tGLd1BJ826MOpTL4m+u+nrD9jse6iYIz4VR+uzKGO+lkGoJxXyoHwPN4UR8TQQXjJMRv6e9ejc9M\n\tzU1mAKR9buDjBtzUKVQ+xwR3mFKusVhi70ktbBFfcJD9dCSsP1U50rOs0FHbKC3eIcLsPt78z/3\n\tWcIwM2RbZ7DJuakDcYeOb6sCPvnEsDmkguWmJ5TEwqIk9HVTOigPkTiSI3hrPhGXpM6qD1Nf9uj\n\tbEsIkn0IYe9E5w+kl2XEyoRlhVSqsVRIH/4F3FUEjWU/qndyir858WZNDxFY12dCTWNcEC9q9B3\n\tFRFYB5CxbnddFaZlusWtYAmSHEnkEIL+mZ3Xr8+eTVqvVI0+pWdHI/+2MRf8SNvPSEIV51g01a4\n\txJrBiYHjvuLNKMnt0vFNkvbFXjLEW0ixau4RPVzjgPETqD2+09HkFMEi2N21tmVaFM", "X-Received": "by 2002:a17:903:2ac3:b0:2b0:6e4a:32d0 with SMTP id\n d9443c01a7336-2b97c4998d6mr39136405ad.35.1777392506563;\n Tue, 28 Apr 2026 09:08:26 -0700 (PDT)", "From": "nspmangalore@gmail.com", "X-Google-Original-From": "sprasad@microsoft.com", "To": "linux-cifs@vger.kernel.org,\n\tsmfrench@gmail.com,\n\tpc@manguebit.org,\n\tbharathsm@microsoft.com,\n\tdhowells@redhat.com,\n\thenrique.carvalho@suse.com,\n\tematsumiya@suse.de", "Cc": "Shyam Prasad N <sprasad@microsoft.com>", "Subject": "[PATCH v3 08/19] cifs: make cfid locks more granular", "Date": "Tue, 28 Apr 2026 21:37:53 +0530", "Message-ID": "<20260428160804.281745-8-sprasad@microsoft.com>", "X-Mailer": "git-send-email 2.43.0", "In-Reply-To": "<20260428160804.281745-1-sprasad@microsoft.com>", "References": "<20260428160804.281745-1-sprasad@microsoft.com>", "Precedence": "bulk", "X-Mailing-List": "linux-cifs@vger.kernel.org", "List-Id": "<linux-cifs.vger.kernel.org>", "List-Subscribe": "<mailto:linux-cifs+subscribe@vger.kernel.org>", "List-Unsubscribe": "<mailto:linux-cifs+unsubscribe@vger.kernel.org>", "MIME-Version": "1.0", "Content-Transfer-Encoding": "8bit" }, "content": "From: Shyam Prasad N <sprasad@microsoft.com>\n\nToday all synchronization of cfid related data structures are done\nusing cfid_list_lock. This can serialize caching of different dirs\nunnecessarily.\n\nThis change introduces two new locks to provide finer locking.\nEvery cfid will now have a cfid_lock. This is designed to protect\neverything inside a cfid that is not related to list operations.\n\nEvery cfid will now also have a cfid_open_mutex. This is designed to\nprotect parallel open calls to the same dir.\n\nAdditionally, this change will now make accesses to cfid->dentries\nmore stringent using the de_mutex.\n\nSigned-off-by: Shyam Prasad N <sprasad@microsoft.com>\n---\n fs/smb/client/cached_dir.c | 155 +++++++++++++++++++++++++------------\n fs/smb/client/cached_dir.h | 13 +++-\n fs/smb/client/cifs_debug.c | 7 +-\n fs/smb/client/cifsglob.h | 2 +\n fs/smb/client/dir.c | 34 ++++++--\n 5 files changed, 149 insertions(+), 62 deletions(-)", "diff": "diff --git a/fs/smb/client/cached_dir.c b/fs/smb/client/cached_dir.c\nindex a9bc0c81868c8..ad2439856a1fe 100644\n--- a/fs/smb/client/cached_dir.c\n+++ b/fs/smb/client/cached_dir.c\n@@ -16,13 +16,29 @@ static struct cached_fid *init_cached_dir(const char *path);\n static void free_cached_dir(struct cached_fid *cfid);\n static void smb2_close_cached_fid(struct kref *ref);\n static void cfids_laundromat_worker(struct work_struct *work);\n-static void close_cached_dir_locked(struct cached_fid *cfid);\n \n struct cached_dir_dentry {\n \tstruct list_head entry;\n \tstruct dentry *dentry;\n };\n \n+bool cached_dir_copy_lease_key(struct cached_fid *cfid,\n+\t\t\t __u8 lease_key[SMB2_LEASE_KEY_SIZE])\n+{\n+\tbool valid;\n+\n+\tif (!cfid)\n+\t\treturn false;\n+\n+\tspin_lock(&cfid->cfid_lock);\n+\tvalid = is_valid_cached_dir(cfid);\n+\tif (valid)\n+\t\tmemcpy(lease_key, cfid->fid.lease_key, SMB2_LEASE_KEY_SIZE);\n+\tspin_unlock(&cfid->cfid_lock);\n+\n+\treturn valid;\n+}\n+\n static bool emit_cached_dirents(struct cached_dirents *cde,\n \t\t\t\tstruct dir_context *ctx)\n {\n@@ -244,9 +260,13 @@ static struct cached_fid *find_or_create_cached_dir(struct cached_fids *cfids,\n \t\t\t * fully cached or it may be in the process of\n \t\t\t * being deleted due to a lease break.\n \t\t\t */\n-\t\t\tif (!is_valid_cached_dir(cfid))\n+\t\t\tspin_lock(&cfid->cfid_lock);\n+\t\t\tif (!is_valid_cached_dir(cfid)) {\n+\t\t\t\tspin_unlock(&cfid->cfid_lock);\n \t\t\t\treturn NULL;\n+\t\t\t}\n \t\t\tkref_get(&cfid->refcount);\n+\t\t\tspin_unlock(&cfid->cfid_lock);\n \t\t\treturn cfid;\n \t\t}\n \t}\n@@ -273,7 +293,9 @@ static struct cached_fid *find_or_create_cached_dir(struct cached_fids *cfids,\n \t * Concurrent processes won't be to use it yet due to @cfid->time being\n \t * zero.\n \t */\n+\tspin_lock(&cfid->cfid_lock);\n \tcfid->has_lease = true;\n+\tspin_unlock(&cfid->cfid_lock);\n \n \treturn cfid;\n }\n@@ -396,19 +418,23 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,\n \t\tkfree(utf16_path);\n \t\treturn -ENOENT;\n \t}\n+\tspin_unlock(&cfids->cfid_list_lock);\n+\n \t/*\n \t * Return cached fid if it is valid (has a lease and has a time).\n \t * Otherwise, it is either a new entry or laundromat worker removed it\n \t * from @cfids->entries. Caller will put last reference if the latter.\n \t */\n+\n+\tspin_lock(&cfid->cfid_lock);\n \tif (is_valid_cached_dir(cfid)) {\n \t\tcfid->last_access_time = jiffies;\n-\t\tspin_unlock(&cfids->cfid_list_lock);\n+\t\tspin_unlock(&cfid->cfid_lock);\n \t\t*ret_cfid = cfid;\n \t\tkfree(utf16_path);\n \t\treturn 0;\n \t}\n-\tspin_unlock(&cfids->cfid_list_lock);\n+\tspin_unlock(&cfid->cfid_lock);\n \n \tpfid = &cfid->fid;\n \n@@ -438,6 +464,7 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,\n \n \t\t\tspin_lock(&cfids->cfid_list_lock);\n \t\t\tlist_for_each_entry(parent_cfid, &cfids->entries, entry) {\n+\t\t\t\tspin_lock(&parent_cfid->cfid_lock);\n \t\t\t\tif (parent_cfid->dentry == dentry->d_parent) {\n \t\t\t\t\tcifs_dbg(FYI, \"found a parent cached file handle\\n\");\n \t\t\t\t\tif (is_valid_cached_dir(parent_cfid)) {\n@@ -447,8 +474,10 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,\n \t\t\t\t\t\t parent_cfid->fid.lease_key,\n \t\t\t\t\t\t SMB2_LEASE_KEY_SIZE);\n \t\t\t\t\t}\n+\t\t\t\t\tspin_unlock(&parent_cfid->cfid_lock);\n \t\t\t\t\tbreak;\n \t\t\t\t}\n+\t\t\t\tspin_unlock(&parent_cfid->cfid_lock);\n \t\t\t}\n \t\t\tspin_unlock(&cfids->cfid_list_lock);\n \t\t}\n@@ -527,10 +556,13 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,\n \t\tsmb2_set_replay(server, &rqst[1]);\n \t}\n \n+\tmutex_lock(&cfid->cfid_open_mutex);\n+\n \trc = compound_send_recv(xid, ses, server,\n \t\t\t\tflags, 2, rqst,\n \t\t\t\tresp_buftype, rsp_iov);\n \tif (rc) {\n+\t\tmutex_unlock(&cfid->cfid_open_mutex);\n \t\tif (rc == -EREMCHG) {\n \t\t\ttcon->need_reconnect = true;\n \t\t\tpr_warn_once(\"server share %s deleted\\n\",\n@@ -538,10 +570,9 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,\n \t\t}\n \t\tgoto oshr_free;\n \t}\n+\tspin_lock(&cfid->cfid_lock);\n \tcfid->is_open = true;\n \n-\tspin_lock(&cfids->cfid_list_lock);\n-\n \to_rsp = (struct smb2_create_rsp *)rsp_iov[0].iov_base;\n \toparms.fid->persistent_fid = o_rsp->PersistentFileId;\n \toparms.fid->volatile_fid = o_rsp->VolatileFileId;\n@@ -551,8 +582,9 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,\n \n \n \tif (o_rsp->OplockLevel != SMB2_OPLOCK_LEVEL_LEASE) {\n-\t\tspin_unlock(&cfids->cfid_list_lock);\n \t\trc = -EINVAL;\n+\t\tspin_unlock(&cfid->cfid_lock);\n+\t\tmutex_unlock(&cfid->cfid_open_mutex);\n \t\tgoto oshr_free;\n \t}\n \n@@ -561,18 +593,21 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,\n \t\t\t\t oparms.fid->lease_key,\n \t\t\t\t &oplock, NULL, NULL);\n \tif (rc) {\n-\t\tspin_unlock(&cfids->cfid_list_lock);\n+\t\tspin_unlock(&cfid->cfid_lock);\n+\t\tmutex_unlock(&cfid->cfid_open_mutex);\n \t\tgoto oshr_free;\n \t}\n \n \trc = -EINVAL;\n \tif (!(oplock & SMB2_LEASE_READ_CACHING_HE)) {\n-\t\tspin_unlock(&cfids->cfid_list_lock);\n+\t\tspin_unlock(&cfid->cfid_lock);\n+\t\tmutex_unlock(&cfid->cfid_open_mutex);\n \t\tgoto oshr_free;\n \t}\n \tqi_rsp = (struct smb2_query_info_rsp *)rsp_iov[1].iov_base;\n \tif (le32_to_cpu(qi_rsp->OutputBufferLength) < sizeof(struct smb2_file_all_info)) {\n-\t\tspin_unlock(&cfids->cfid_list_lock);\n+\t\tspin_unlock(&cfid->cfid_lock);\n+\t\tmutex_unlock(&cfid->cfid_open_mutex);\n \t\tgoto oshr_free;\n \t}\n \tif (!smb2_validate_and_copy_iov(\n@@ -584,7 +619,8 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,\n \n \tcfid->time = jiffies;\n \tcfid->last_access_time = jiffies;\n-\tspin_unlock(&cfids->cfid_list_lock);\n+\tspin_unlock(&cfid->cfid_lock);\n+\tmutex_unlock(&cfid->cfid_open_mutex);\n \t/* At this point the directory handle is fully cached */\n \trc = 0;\n \n@@ -595,23 +631,24 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,\n \tfree_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);\n out:\n \tif (rc) {\n+\t\tbool drop_lease_ref = false;\n+\n \t\tspin_lock(&cfids->cfid_list_lock);\n \t\tif (cfid->on_list) {\n \t\t\tlist_del(&cfid->entry);\n \t\t\tcfid->on_list = false;\n \t\t\tcfids->num_entries--;\n \t\t}\n+\t\tspin_lock(&cfid->cfid_lock);\n \t\tif (cfid->has_lease) {\n-\t\t\t/*\n-\t\t\t * We are guaranteed to have two references at this\n-\t\t\t * point. One for the caller and one for a potential\n-\t\t\t * lease. Release one here, and the second below.\n-\t\t\t */\n \t\t\tcfid->has_lease = false;\n-\t\t\tclose_cached_dir_locked(cfid);\n+\t\t\tdrop_lease_ref = true;\n \t\t}\n+\t\tspin_unlock(&cfid->cfid_lock);\n \t\tspin_unlock(&cfids->cfid_list_lock);\n \n+\t\tif (drop_lease_ref)\n+\t\t\tclose_cached_dir(cfid);\n \t\tclose_cached_dir(cfid);\n \t} else {\n \t\t*ret_cfid = cfid;\n@@ -642,12 +679,16 @@ int open_cached_dir_by_dentry(struct cifs_tcon *tcon,\n \tspin_lock(&cfids->cfid_list_lock);\n \tlist_for_each_entry(cfid, &cfids->entries, entry) {\n \t\tif (cfid->dentry == dentry) {\n-\t\t\tif (!is_valid_cached_dir(cfid))\n+\t\t\tspin_lock(&cfid->cfid_lock);\n+\t\t\tif (!is_valid_cached_dir(cfid)) {\n+\t\t\t\tspin_unlock(&cfid->cfid_lock);\n \t\t\t\tbreak;\n+\t\t\t}\n \t\t\tcifs_dbg(FYI, \"found a cached file handle by dentry\\n\");\n \t\t\tkref_get(&cfid->refcount);\n \t\t\t*ret_cfid = cfid;\n \t\t\tcfid->last_access_time = jiffies;\n+\t\t\tspin_unlock(&cfid->cfid_lock);\n \t\t\tspin_unlock(&cfids->cfid_list_lock);\n \t\t\treturn 0;\n \t\t}\n@@ -662,6 +703,8 @@ __releases(&cfid->cfids->cfid_list_lock)\n {\n \tstruct cached_fid *cfid = container_of(ref, struct cached_fid,\n \t\t\t\t\t refcount);\n+\tu64 persistent_fid = 0, volatile_fid = 0;\n+\tbool is_open;\n \tint rc;\n \n \tlockdep_assert_held(&cfid->cfids->cfid_list_lock);\n@@ -676,9 +719,17 @@ __releases(&cfid->cfids->cfid_list_lock)\n \tdput(cfid->dentry);\n \tcfid->dentry = NULL;\n \n-\tif (cfid->is_open) {\n-\t\trc = SMB2_close(0, cfid->tcon, cfid->fid.persistent_fid,\n-\t\t\t cfid->fid.volatile_fid);\n+\tspin_lock(&cfid->cfid_lock);\n+\tis_open = cfid->is_open;\n+\tif (is_open) {\n+\t\tpersistent_fid = cfid->fid.persistent_fid;\n+\t\tvolatile_fid = cfid->fid.volatile_fid;\n+\t\tcfid->is_open = false;\n+\t}\n+\tspin_unlock(&cfid->cfid_lock);\n+\n+\tif (is_open) {\n+\t\trc = SMB2_close(0, cfid->tcon, persistent_fid, volatile_fid);\n \t\tif (rc) /* should we retry on -EBUSY or -EAGAIN? */\n \t\t\tcifs_dbg(VFS, \"close cached dir rc %d\\n\", rc);\n \t}\n@@ -691,6 +742,7 @@ void drop_cached_dir_by_name(const unsigned int xid, struct cifs_tcon *tcon,\n {\n \tstruct cached_fid *cfid = NULL;\n \tint rc;\n+\tbool drop_lease_ref = false;\n \n \trc = open_cached_dir(xid, tcon, name, cifs_sb, true, &cfid);\n \tif (rc) {\n@@ -698,11 +750,16 @@ void drop_cached_dir_by_name(const unsigned int xid, struct cifs_tcon *tcon,\n \t\treturn;\n \t}\n \tspin_lock(&cfid->cfids->cfid_list_lock);\n+\tspin_lock(&cfid->cfid_lock);\n \tif (cfid->has_lease) {\n \t\tcfid->has_lease = false;\n-\t\tclose_cached_dir_locked(cfid);\n+\t\tdrop_lease_ref = true;\n \t}\n+\tspin_unlock(&cfid->cfid_lock);\n \tspin_unlock(&cfid->cfids->cfid_list_lock);\n+\n+\tif (drop_lease_ref)\n+\t\tclose_cached_dir(cfid);\n \tclose_cached_dir(cfid);\n }\n \n@@ -711,8 +768,7 @@ void drop_cached_dir_by_name(const unsigned int xid, struct cifs_tcon *tcon,\n *\n * The release function will be called with cfid_list_lock held to remove the\n * cached dirs from the list before any other thread can take another @cfid\n- * ref. Must not be called with cfid_list_lock held; use\n- * close_cached_dir_locked() called instead.\n+ * ref. Must not be called with cfid_list_lock held.\n *\n * @cfid: cached dir\n */\n@@ -722,30 +778,6 @@ void close_cached_dir(struct cached_fid *cfid)\n \tkref_put_lock(&cfid->refcount, smb2_close_cached_fid, &cfid->cfids->cfid_list_lock);\n }\n \n-/**\n- * close_cached_dir_locked - put a reference of a cached dir with\n- * cfid_list_lock held\n- *\n- * Calling close_cached_dir() with cfid_list_lock held has the potential effect\n- * of causing a deadlock if the invariant of refcount >= 2 is false.\n- *\n- * This function is used in paths that hold cfid_list_lock and expect at least\n- * two references. If that invariant is violated, WARNs and returns without\n- * dropping a reference; the final put must still go through\n- * close_cached_dir().\n- *\n- * @cfid: cached dir\n- */\n-static void close_cached_dir_locked(struct cached_fid *cfid)\n-{\n-\tlockdep_assert_held(&cfid->cfids->cfid_list_lock);\n-\n-\tif (WARN_ON(kref_read(&cfid->refcount) < 2))\n-\t\treturn;\n-\n-\tkref_put(&cfid->refcount, smb2_close_cached_fid);\n-}\n-\n /*\n * Called from cifs_kill_sb when we unmount a share\n */\n@@ -784,8 +816,10 @@ void close_all_cached_dirs(struct cifs_sb_info *cifs_sb)\n \t\t\t\tgoto done;\n \t\t\t}\n \n+\t\t\tspin_lock(&cfid->cfid_lock);\n \t\t\ttmp_list->dentry = cfid->dentry;\n \t\t\tcfid->dentry = NULL;\n+\t\t\tspin_unlock(&cfid->cfid_lock);\n \n \t\t\tlist_add_tail(&tmp_list->entry, &entry);\n \t\t}\n@@ -825,16 +859,20 @@ void invalidate_all_cached_dirs(struct cifs_tcon *tcon)\n \tlist_for_each_entry_safe(cfid, q, &cfids->entries, entry) {\n \t\tlist_move(&cfid->entry, &cfids->dying);\n \t\tcfids->num_entries--;\n+\t\tspin_lock(&cfid->cfid_lock);\n \t\tcfid->is_open = false;\n-\t\tcfid->on_list = false;\n \t\tif (cfid->has_lease) {\n \t\t\t/*\n \t\t\t * The lease was never cancelled from the server,\n \t\t\t * so steal that reference.\n \t\t\t */\n \t\t\tcfid->has_lease = false;\n-\t\t} else\n+\t\t\tspin_unlock(&cfid->cfid_lock);\n+\t\t} else {\n+\t\t\tspin_unlock(&cfid->cfid_lock);\n \t\t\tkref_get(&cfid->refcount);\n+\t\t}\n+\t\tcfid->on_list = false;\n \t}\n \tspin_unlock(&cfids->cfid_list_lock);\n \n@@ -883,12 +921,14 @@ bool cached_dir_lease_break(struct cifs_tcon *tcon, __u8 lease_key[16])\n \n \tspin_lock(&cfids->cfid_list_lock);\n \tlist_for_each_entry(cfid, &cfids->entries, entry) {\n+\t\tspin_lock(&cfid->cfid_lock);\n \t\tif (cfid->has_lease &&\n \t\t !memcmp(lease_key,\n \t\t\t cfid->fid.lease_key,\n \t\t\t SMB2_LEASE_KEY_SIZE)) {\n \t\t\tcfid->has_lease = false;\n \t\t\tcfid->time = 0;\n+\t\t\tspin_unlock(&cfid->cfid_lock);\n \t\t\t/*\n \t\t\t * We found a lease remove it from the list\n \t\t\t * so no threads can access it.\n@@ -904,6 +944,7 @@ bool cached_dir_lease_break(struct cifs_tcon *tcon, __u8 lease_key[16])\n \t\t\tspin_unlock(&cfids->cfid_list_lock);\n \t\t\treturn true;\n \t\t}\n+\t\tspin_unlock(&cfid->cfid_lock);\n \t}\n \tspin_unlock(&cfids->cfid_list_lock);\n \treturn false;\n@@ -927,6 +968,8 @@ static struct cached_fid *init_cached_dir(const char *path)\n \tINIT_LIST_HEAD(&cfid->entry);\n \tINIT_LIST_HEAD(&cfid->dirents.entries);\n \tmutex_init(&cfid->dirents.de_mutex);\n+\tmutex_init(&cfid->cfid_open_mutex);\n+\tspin_lock_init(&cfid->cfid_lock);\n \tkref_init(&cfid->refcount);\n \treturn cfid;\n }\n@@ -983,6 +1026,7 @@ static void cfids_laundromat_worker(struct work_struct *work)\n \tlist_cut_before(&entry, &cfids->dying, &cfids->dying);\n \n \tlist_for_each_entry_safe(cfid, q, &cfids->entries, entry) {\n+\t\tspin_lock(&cfid->cfid_lock);\n \t\tif (cfid->last_access_time &&\n \t\t time_after(jiffies, cfid->last_access_time + HZ * dir_cache_timeout)) {\n \t\t\tcfid->on_list = false;\n@@ -994,8 +1038,13 @@ static void cfids_laundromat_worker(struct work_struct *work)\n \t\t\t\t * server. Steal that reference.\n \t\t\t\t */\n \t\t\t\tcfid->has_lease = false;\n-\t\t\t} else\n+\t\t\t\tspin_unlock(&cfid->cfid_lock);\n+\t\t\t} else {\n+\t\t\t\tspin_unlock(&cfid->cfid_lock);\n \t\t\t\tkref_get(&cfid->refcount);\n+\t\t\t}\n+\t\t} else {\n+\t\t\tspin_unlock(&cfid->cfid_lock);\n \t\t}\n \t}\n \tspin_unlock(&cfids->cfid_list_lock);\n@@ -1062,12 +1111,16 @@ void free_cached_dirs(struct cached_fids *cfids)\n \tspin_lock(&cfids->cfid_list_lock);\n \tlist_for_each_entry_safe(cfid, q, &cfids->entries, entry) {\n \t\tcfid->on_list = false;\n+\t\tspin_lock(&cfid->cfid_lock);\n \t\tcfid->is_open = false;\n+\t\tspin_unlock(&cfid->cfid_lock);\n \t\tlist_move(&cfid->entry, &entry);\n \t}\n \tlist_for_each_entry_safe(cfid, q, &cfids->dying, entry) {\n \t\tcfid->on_list = false;\n+\t\tspin_lock(&cfid->cfid_lock);\n \t\tcfid->is_open = false;\n+\t\tspin_unlock(&cfid->cfid_lock);\n \t\tlist_move(&cfid->entry, &entry);\n \t}\n \tspin_unlock(&cfids->cfid_list_lock);\ndiff --git a/fs/smb/client/cached_dir.h b/fs/smb/client/cached_dir.h\nindex 09f1f488059c9..f82db6a7ca5b0 100644\n--- a/fs/smb/client/cached_dir.h\n+++ b/fs/smb/client/cached_dir.h\n@@ -48,6 +48,8 @@ struct cached_fid {\n \tstruct work_struct put_work;\n \tstruct work_struct close_work;\n \tstruct cached_dirents dirents;\n+\tstruct mutex cfid_open_mutex; /* Serializes OPEN response processing and lease key population */\n+\tspinlock_t cfid_lock; /* Protects: has_lease, time, is_open, file_all_info_is_valid, last_access_time, fid.lease_key reads */\n \n \t/* Must be last as it ends in a flexible-array member. */\n \tstruct smb2_file_all_info file_all_info;\n@@ -56,8 +58,12 @@ struct cached_fid {\n /* default MAX_CACHED_FIDS is 16 */\n struct cached_fids {\n \t/* Must be held when:\n-\t * - accessing the cfids->entries list\n-\t * - accessing the cfids->dying list\n+\t * - modifying cfids->entries list (add/remove entries)\n+\t * - modifying cfids->dying list\n+\t * - modifying cfid->on_list or cfids->num_entries\n+\t *\n+\t * Lock ordering: if you need both cfid_list_lock and cfid_lock,\n+\t * acquire cfid_list_lock FIRST, then cfid_lock to avoid deadlock.\n \t */\n \tspinlock_t cfid_list_lock;\n \tint num_entries;\n@@ -78,6 +84,9 @@ is_valid_cached_dir(struct cached_fid *cfid)\n \treturn cfid->time && cfid->has_lease;\n }\n \n+bool cached_dir_copy_lease_key(struct cached_fid *cfid,\n+\t\t\t __u8 lease_key[SMB2_LEASE_KEY_SIZE]);\n+\n struct cached_fids *init_cached_dirs(void);\n void free_cached_dirs(struct cached_fids *cfids);\n int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, const char *path,\ndiff --git a/fs/smb/client/cifs_debug.c b/fs/smb/client/cifs_debug.c\nindex 217444e3e6d01..cc7d26a3917c5 100644\n--- a/fs/smb/client/cifs_debug.c\n+++ b/fs/smb/client/cifs_debug.c\n@@ -327,6 +327,7 @@ static int cifs_debug_dirs_proc_show(struct seq_file *m, void *v)\n \t\t\t\t\t\t(unsigned long)atomic_long_read(&cfids->total_dirents_entries),\n \t\t\t\t\t\t(unsigned long long)atomic64_read(&cfids->total_dirents_bytes));\n \t\t\t\tlist_for_each_entry(cfid, &cfids->entries, entry) {\n+\t\t\t\t\tspin_lock(&cfid->cfid_lock);\n \t\t\t\t\tseq_printf(m, \"0x%x 0x%llx 0x%llx \",\n \t\t\t\t\t\ttcon->tid,\n \t\t\t\t\t\tses->Suid,\n@@ -338,11 +339,13 @@ static int cifs_debug_dirs_proc_show(struct seq_file *m, void *v)\n \t\t\t\t\tseq_printf(m, \"%s\", cfid->path);\n \t\t\t\t\tif (cfid->file_all_info_is_valid)\n \t\t\t\t\t\tseq_printf(m, \"\\tvalid file info\");\n+\t\t\t\t\tspin_unlock(&cfid->cfid_lock);\n \t\t\t\t\tif (cfid->dirents.is_valid)\n \t\t\t\t\t\tseq_printf(m, \", valid dirents\");\n-\t\t\t\t\tif (!list_empty(&cfid->dirents.entries))\n+\t\t\t\t\tif (READ_ONCE(cfid->dirents.entries_count))\n \t\t\t\t\t\tseq_printf(m, \", dirents: %lu entries, %lu bytes\",\n-\t\t\t\t\t\tcfid->dirents.entries_count, cfid->dirents.bytes_used);\n+\t\t\t\t\t\tREAD_ONCE(cfid->dirents.entries_count),\n+\t\t\t\t\t\tREAD_ONCE(cfid->dirents.bytes_used));\n \t\t\t\t\tseq_printf(m, \"\\n\");\n \t\t\t\t}\n \t\t\t\tspin_unlock(&cfids->cfid_list_lock);\ndiff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h\nindex 38d5600efe2c8..a15971ffeee58 100644\n--- a/fs/smb/client/cifsglob.h\n+++ b/fs/smb/client/cifsglob.h\n@@ -2068,6 +2068,8 @@ require use of the stronger protocol */\n *\t\t\t\t->can_cache_brlcks\n * cifsInodeInfo->deferred_lock\tcifsInodeInfo->deferred_closes\tcifsInodeInfo_alloc\n * cached_fids->cfid_list_lock\tcifs_tcon->cfids->entries\tinit_cached_dirs\n+ * cached_fid->cfid_open_mutex\tcached_fid OPEN/lease serialization\talloc_cached_dir\n+ * cached_fid->cfid_lock\tcached_fid state\t\talloc_cached_dir\n * cached_fid->dirents.de_mutex\tcached_fid->dirents\t\talloc_cached_dir\n * cifsFileInfo->fh_mutex\tcifsFileInfo\t\t\tcifs_new_fileinfo\n * cifsFileInfo->file_info_lock\tcifsFileInfo->count\t\tcifs_new_fileinfo\ndiff --git a/fs/smb/client/dir.c b/fs/smb/client/dir.c\nindex 6d2378eeb7f68..4e5c580e4de0a 100644\n--- a/fs/smb/client/dir.c\n+++ b/fs/smb/client/dir.c\n@@ -194,6 +194,7 @@ static int cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned\n \tstruct cached_fid *parent_cfid = NULL;\n \tint rdwr_for_fscache = 0;\n \t__le32 lease_flags = 0;\n+\tbool found_parent_cfid;\n \n \t*oplock = 0;\n \tif (tcon->ses->server->oplocks)\n@@ -319,24 +320,33 @@ static int cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned\n \n retry_open:\n \tif (tcon->cfids && direntry->d_parent && server->dialect >= SMB30_PROT_ID) {\n+\t\tfound_parent_cfid = false;\n \t\tparent_cfid = NULL;\n \t\tspin_lock(&tcon->cfids->cfid_list_lock);\n \t\tlist_for_each_entry(parent_cfid, &tcon->cfids->entries, entry) {\n+\t\t\tspin_lock(&parent_cfid->cfid_lock);\n \t\t\tif (parent_cfid->dentry == direntry->d_parent) {\n+\t\t\t\tkref_get(&parent_cfid->refcount);\n+\t\t\t\tspin_unlock(&parent_cfid->cfid_lock);\n+\t\t\t\tspin_unlock(&tcon->cfids->cfid_list_lock);\n+\t\t\t\tfound_parent_cfid = true;\n \t\t\t\tcifs_dbg(FYI, \"found a parent cached file handle\\n\");\n-\t\t\t\tif (is_valid_cached_dir(parent_cfid)) {\n+\t\t\t\tif (cached_dir_copy_lease_key(parent_cfid,\n+\t\t\t\t\t\t fid->parent_lease_key)) {\n \t\t\t\t\tlease_flags\n \t\t\t\t\t\t|= SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET_LE;\n-\t\t\t\t\tmemcpy(fid->parent_lease_key,\n-\t\t\t\t\t parent_cfid->fid.lease_key,\n-\t\t\t\t\t SMB2_LEASE_KEY_SIZE);\n+\t\t\t\t\tmutex_lock(&parent_cfid->dirents.de_mutex);\n \t\t\t\t\tparent_cfid->dirents.is_valid = false;\n \t\t\t\t\tparent_cfid->dirents.is_failed = true;\n+\t\t\t\t\tmutex_unlock(&parent_cfid->dirents.de_mutex);\n \t\t\t\t}\n+\t\t\t\tclose_cached_dir(parent_cfid);\n \t\t\t\tbreak;\n \t\t\t}\n+\t\t\tspin_unlock(&parent_cfid->cfid_lock);\n \t\t}\n-\t\tspin_unlock(&tcon->cfids->cfid_list_lock);\n+\t\tif (!found_parent_cfid)\n+\t\t\tspin_unlock(&tcon->cfids->cfid_list_lock);\n \t}\n \n \toparms = (struct cifs_open_parms) {\n@@ -737,7 +747,12 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,\n \t\t\t * dentry is negative and parent is fully cached:\n \t\t\t * we can assume file does not exist\n \t\t\t */\n-\t\t\tif (cfid->dirents.is_valid) {\n+\t\t\tbool dirents_valid;\n+\n+\t\t\tmutex_lock(&cfid->dirents.de_mutex);\n+\t\t\tdirents_valid = cfid->dirents.is_valid;\n+\t\t\tmutex_unlock(&cfid->dirents.de_mutex);\n+\t\t\tif (dirents_valid) {\n \t\t\t\tclose_cached_dir(cfid);\n \t\t\t\tgoto out;\n \t\t\t}\n@@ -848,7 +863,12 @@ cifs_d_revalidate(struct inode *dir, const struct qstr *name,\n \t\t\t * dentry is negative and parent is fully cached:\n \t\t\t * we can assume file does not exist\n \t\t\t */\n-\t\t\tif (cfid->dirents.is_valid) {\n+\t\t\tbool dirents_valid;\n+\n+\t\t\tmutex_lock(&cfid->dirents.de_mutex);\n+\t\t\tdirents_valid = cfid->dirents.is_valid;\n+\t\t\tmutex_unlock(&cfid->dirents.de_mutex);\n+\t\t\tif (dirents_valid) {\n \t\t\t\tclose_cached_dir(cfid);\n \t\t\t\treturn 1;\n \t\t\t}\n", "prefixes": [ "v3", "08/19" ] }