From patchwork Thu Mar 28 16:58:02 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Howells X-Patchwork-Id: 13609181 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 kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id B6A83CD1283 for ; Thu, 28 Mar 2024 17:00:43 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 484EA6B0083; Thu, 28 Mar 2024 13:00:43 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 3E6FD6B00C0; Thu, 28 Mar 2024 13:00:43 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 213996B00C6; Thu, 28 Mar 2024 13:00:43 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0010.hostedemail.com [216.40.44.10]) by kanga.kvack.org (Postfix) with ESMTP id F347E6B0083 for ; Thu, 28 Mar 2024 13:00:42 -0400 (EDT) Received: from smtpin24.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay06.hostedemail.com (Postfix) with ESMTP id 7D562A161F for ; Thu, 28 Mar 2024 17:00:42 +0000 (UTC) X-FDA: 81947061924.24.FDD0B9D Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by imf13.hostedemail.com (Postfix) with ESMTP id 9D2EA20025 for ; Thu, 28 Mar 2024 17:00:39 +0000 (UTC) Authentication-Results: imf13.hostedemail.com; dkim=pass header.d=redhat.com header.s=mimecast20190719 header.b=VF0+UorN; dmarc=pass (policy=none) header.from=redhat.com; spf=pass (imf13.hostedemail.com: domain of dhowells@redhat.com designates 170.10.129.124 as permitted sender) smtp.mailfrom=dhowells@redhat.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1711645239; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=OTSLBmDT3ajEjbQN8Mhbrt3qwYOXMWxKvZgVJwWAFPE=; b=3t1BYJkUzrB66jFEbR0xMwkhPkX7/oL51VrTAivGBc4UuxTBD3OeuyxoNboYWh6q1FyBl8 pDfhvbh9zTKFv5fThbsuS+LImXJQKy3TJl7hz+rB2pvwd1wbTVmSg3tnqguef8iKmaLKY6 qTLC50O/8S4FMPGtdCVTvgLv9F6/iAE= ARC-Authentication-Results: i=1; imf13.hostedemail.com; dkim=pass header.d=redhat.com header.s=mimecast20190719 header.b=VF0+UorN; dmarc=pass (policy=none) header.from=redhat.com; spf=pass (imf13.hostedemail.com: domain of dhowells@redhat.com designates 170.10.129.124 as permitted sender) smtp.mailfrom=dhowells@redhat.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1711645239; a=rsa-sha256; cv=none; b=IDmYgvyqDmtHaSHAcPLSmtUQsYbQvUzL/nPOUXxFJdTRc8j8RsVBJoMAZ0HmTp7TeioeoC rtgAkFzalB716doTuyyqNz1fkxkZ2mOwF+PH9IK2FcG3dQ6jQMUsHH8SJDFtyq0dtw+z4e B19nE1yTfkJ7yqkfpw3lGSVUNN33D0A= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1711645239; 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=OTSLBmDT3ajEjbQN8Mhbrt3qwYOXMWxKvZgVJwWAFPE=; b=VF0+UorNrJfNd9TcmcGSzGA8b11Wb+NjXGaVDXd6tNrNkaYEQsFK86KnVeqpt/FrQSyrRB jzbAIAlmA+pLrptDZHbGgOYbfqk8LGpH0+AVz1ka2BR5wC2cUtf/Lt8ahOCFNfxTgEqcI3 kzfejoec3+OSNoQjvzfmRPqu/YIFXKM= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-393-8zEC4T1bPh2F6CVGOhvMiQ-1; Thu, 28 Mar 2024 13:00:36 -0400 X-MC-Unique: 8zEC4T1bPh2F6CVGOhvMiQ-1 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.rdu2.redhat.com [10.11.54.2]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id E275E18F34A0; Thu, 28 Mar 2024 17:00:34 +0000 (UTC) Received: from warthog.procyon.org.com (unknown [10.42.28.146]) by smtp.corp.redhat.com (Postfix) with ESMTP id A927040C6CB1; Thu, 28 Mar 2024 17:00:32 +0000 (UTC) From: David Howells To: Steve French Cc: David Howells , Jeff Layton , Matthew Wilcox , Paulo Alcantara , Shyam Prasad N , Tom Talpey , Christian Brauner , netfs@lists.linux.dev, linux-cifs@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-mm@kvack.org, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, Steve French , Shyam Prasad N , Rohith Surabattula Subject: [PATCH v6 11/15] cifs: When caching, try to open O_WRONLY file rdwr on server Date: Thu, 28 Mar 2024 16:58:02 +0000 Message-ID: <20240328165845.2782259-12-dhowells@redhat.com> In-Reply-To: <20240328165845.2782259-1-dhowells@redhat.com> References: <20240328165845.2782259-1-dhowells@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.2 X-Rspam-User: X-Stat-Signature: fztat4b9y1i3k5diisunhc91rtrtxy75 X-Rspamd-Server: rspam07 X-Rspamd-Queue-Id: 9D2EA20025 X-HE-Tag: 1711645239-707048 X-HE-Meta: U2FsdGVkX19oyz47ScLAqOFZ/NO0V2psEKAegJmURmsAb2nC8UKbACmv3Feaq2pDBUw+n9rTIDXU4Pdf5Sf4nIEpLE6fkIclCa3K1vTpM3eUE+iJG5jgmIaPqFdlDncakDz0zM3wz/WCYaKTZ2/WIRfX69UoZBmICNuI4+WRUxEoK0NdCbnfWA/DmB7pkC+2hnAJQymT8DqbzEfz5ZqLEuCTQfYbnAA6H2QQku0Viqgi4kRrF1mH/ADGSDSmaHSiSxdsc8h0WPCqUXjLeJVBTnh4jqnOxqewEWLZrpWlgs3uYR65ol0/qkO2R8a198NsPWV0OOraOHLwQX8w+ihgMqoGMUYArmZVrnPoioG4GBlqlaeh5dJkgR4T3gIy958stCjvQKzXE+GS1UY3OatHKpCPwEmjGVJwSwPRdLEXXabcRKEf0v0f/VX5E/8Hl85c8lzicGqHwdcLJrBxLOvYEmbsNWpnKHw7akIkSUqYd7xJU9w6S4Qpt5UJnGdCXlPeqKr6SOce0P3WNCqXiLKrwuZCpBOpoYneFtNdT+RRM8nFLttOdpsaAhrnCd0a33DHzACPKHrZs07RKjcNeKjpdCnMNZ1cSn0BD6DjxZ1x/ZdsPy0I8/Ru8XgfAPyEUj2XrVv93onoj+6J6RuZ08e4m1AcIu1DBYK6xzsS1nD6QwJiodBDAKpk0/Lt5hht2GriY1797CPREW4R8t8UzBDX0MPgMefWsGCucVWP3JAkFeMWqKOmVJA9RMinZdL0N6mNUeI5A4dCMJQVHt9e4yx2fqH8WKlZhI9TGdS6plPTvo+zUUfL1O/YB9aM/JR9iFaWbBfWkN/NI+jjz9mBdBul+Y1DhBZTYBoCtoGKJEAbc/scP7nm21Fsf/XL3qwNeSBovS16bpndLI331MSwvAgjBcbLL/Gn6NCbtbK+9wiKBB2xBco0QfDW8iehFVSrK+LIqsWXb6RK2Gr253uBQPm XFzz2cCJ LS2pkEhqgZgZyvKM+0hLQoaFHwmDxZ5sLgPljeJeqH5uIIZVMxMx7lhw+/rkGiRVim+riDz+jHKLTJIW0wMTYuVGgin3eW8fK9n49ikFUn1M+VrgpZ2fqGc1n4FsyUzxaHGkjA3e78H2Gw1sDPOkJQvf1ipXMVEYcQQ1JXqJz4cCWB/yLZ9P2567K8DCchuz8Tlf6F/I68ouQ1MTib7mbFZNDXDlg3bb2VJjws65UI6mgFK85oTZJYzvNZdfBAgPWh5ggDA3Ukcq2keEoPHmndUhdnFg7WjSUKxfKnH2KvU5E6QpxHMC5wvGNzatYlxFt91hMksXSe/BQLoc4U7bl5isfu7/jdnS8gSsUQ+EoqbiBNlgQ8ApIfY5cBn2FHFPgPz6qzh9lQURpL2Ak3Vs+rGC08h+GObPY8stpzuyhJqaSqwUv/u/v8VdP1PdLF1SeJxFpimnFevYrafNB20NtBVOSQ0i2ro8bsa/ZQxu53b/wba09PSqV6n5ojw== X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: When we're engaged in local caching of a cifs filesystem, we cannot perform caching of a partially written cache granule unless we can read the rest of the granule. To deal with this, if a file is opened O_WRONLY locally, but the mount was given the "-o fsc" flag, try first opening the remote file with GENERIC_READ|GENERIC_WRITE and if that returns -EACCES, try dropping the GENERIC_READ and doing the open again. If that last succeeds, invalidate the cache for that file as for O_DIRECT. Signed-off-by: David Howells cc: Steve French cc: Shyam Prasad N cc: Rohith Surabattula cc: Jeff Layton cc: linux-cifs@vger.kernel.org cc: netfs@lists.linux.dev cc: linux-fsdevel@vger.kernel.org cc: linux-mm@kvack.org --- fs/smb/client/dir.c | 15 ++++++++++++ fs/smb/client/file.c | 51 +++++++++++++++++++++++++++++++++-------- fs/smb/client/fscache.h | 6 +++++ 3 files changed, 62 insertions(+), 10 deletions(-) diff --git a/fs/smb/client/dir.c b/fs/smb/client/dir.c index 89333d9bce36..37897b919dd5 100644 --- a/fs/smb/client/dir.c +++ b/fs/smb/client/dir.c @@ -189,6 +189,7 @@ static int cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int disposition; struct TCP_Server_Info *server = tcon->ses->server; struct cifs_open_parms oparms; + int rdwr_for_fscache = 0; *oplock = 0; if (tcon->ses->server->oplocks) @@ -200,6 +201,10 @@ static int cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned return PTR_ERR(full_path); } + /* If we're caching, we need to be able to fill in around partial writes. */ + if (cifs_fscache_enabled(inode) && (oflags & O_ACCMODE) == O_WRONLY) + rdwr_for_fscache = 1; + #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY if (tcon->unix_ext && cap_unix(tcon->ses) && !tcon->broken_posix_open && (CIFS_UNIX_POSIX_PATH_OPS_CAP & @@ -276,6 +281,8 @@ static int cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned desired_access |= GENERIC_READ; /* is this too little? */ if (OPEN_FMODE(oflags) & FMODE_WRITE) desired_access |= GENERIC_WRITE; + if (rdwr_for_fscache == 1) + desired_access |= GENERIC_READ; disposition = FILE_OVERWRITE_IF; if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) @@ -304,6 +311,7 @@ static int cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned if (!tcon->unix_ext && (mode & S_IWUGO) == 0) create_options |= CREATE_OPTION_READONLY; +retry_open: oparms = (struct cifs_open_parms) { .tcon = tcon, .cifs_sb = cifs_sb, @@ -317,8 +325,15 @@ static int cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned rc = server->ops->open(xid, &oparms, oplock, buf); if (rc) { cifs_dbg(FYI, "cifs_create returned 0x%x\n", rc); + if (rc == -EACCES && rdwr_for_fscache == 1) { + desired_access &= ~GENERIC_READ; + rdwr_for_fscache = 2; + goto retry_open; + } goto out; } + if (rdwr_for_fscache == 2) + cifs_invalidate_cache(inode, FSCACHE_INVAL_DIO_WRITE); #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY /* diff --git a/fs/smb/client/file.c b/fs/smb/client/file.c index 73573dadf90e..761a80963f76 100644 --- a/fs/smb/client/file.c +++ b/fs/smb/client/file.c @@ -521,12 +521,12 @@ cifs_mark_open_files_invalid(struct cifs_tcon *tcon) */ } -static inline int cifs_convert_flags(unsigned int flags) +static inline int cifs_convert_flags(unsigned int flags, int rdwr_for_fscache) { if ((flags & O_ACCMODE) == O_RDONLY) return GENERIC_READ; else if ((flags & O_ACCMODE) == O_WRONLY) - return GENERIC_WRITE; + return rdwr_for_fscache == 1 ? (GENERIC_READ | GENERIC_WRITE) : GENERIC_WRITE; else if ((flags & O_ACCMODE) == O_RDWR) { /* GENERIC_ALL is too much permission to request can cause unnecessary access denied on create */ @@ -663,11 +663,16 @@ static int cifs_nt_open(const char *full_path, struct inode *inode, struct cifs_ int create_options = CREATE_NOT_DIR; struct TCP_Server_Info *server = tcon->ses->server; struct cifs_open_parms oparms; + int rdwr_for_fscache = 0; if (!server->ops->open) return -ENOSYS; - desired_access = cifs_convert_flags(f_flags); + /* If we're caching, we need to be able to fill in around partial writes. */ + if (cifs_fscache_enabled(inode) && (f_flags & O_ACCMODE) == O_WRONLY) + rdwr_for_fscache = 1; + + desired_access = cifs_convert_flags(f_flags, rdwr_for_fscache); /********************************************************************* * open flag mapping table: @@ -704,6 +709,7 @@ static int cifs_nt_open(const char *full_path, struct inode *inode, struct cifs_ if (f_flags & O_DIRECT) create_options |= CREATE_NO_BUFFER; +retry_open: oparms = (struct cifs_open_parms) { .tcon = tcon, .cifs_sb = cifs_sb, @@ -715,8 +721,16 @@ static int cifs_nt_open(const char *full_path, struct inode *inode, struct cifs_ }; rc = server->ops->open(xid, &oparms, oplock, buf); - if (rc) + if (rc) { + if (rc == -EACCES && rdwr_for_fscache == 1) { + desired_access = cifs_convert_flags(f_flags, 0); + rdwr_for_fscache = 2; + goto retry_open; + } return rc; + } + if (rdwr_for_fscache == 2) + cifs_invalidate_cache(inode, FSCACHE_INVAL_DIO_WRITE); /* TODO: Add support for calling posix query info but with passing in fid */ if (tcon->unix_ext) @@ -1149,11 +1163,14 @@ int cifs_open(struct inode *inode, struct file *file) use_cache: fscache_use_cookie(cifs_inode_cookie(file_inode(file)), file->f_mode & FMODE_WRITE); - if (file->f_flags & O_DIRECT && - (!((file->f_flags & O_ACCMODE) != O_RDONLY) || - file->f_flags & O_APPEND)) - cifs_invalidate_cache(file_inode(file), - FSCACHE_INVAL_DIO_WRITE); + //if ((file->f_flags & O_ACCMODE) == O_WRONLY) + // goto inval; + if (!(file->f_flags & O_DIRECT)) + goto out; + if ((file->f_flags & (O_ACCMODE | O_APPEND)) == O_RDONLY) + goto out; +//inval: + cifs_invalidate_cache(file_inode(file), FSCACHE_INVAL_DIO_WRITE); out: free_dentry_path(page); @@ -1218,6 +1235,7 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush) int disposition = FILE_OPEN; int create_options = CREATE_NOT_DIR; struct cifs_open_parms oparms; + int rdwr_for_fscache = 0; xid = get_xid(); mutex_lock(&cfile->fh_mutex); @@ -1281,7 +1299,11 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush) } #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ - desired_access = cifs_convert_flags(cfile->f_flags); + /* If we're caching, we need to be able to fill in around partial writes. */ + if (cifs_fscache_enabled(inode) && (cfile->f_flags & O_ACCMODE) == O_WRONLY) + rdwr_for_fscache = 1; + + desired_access = cifs_convert_flags(cfile->f_flags, rdwr_for_fscache); /* O_SYNC also has bit for O_DSYNC so following check picks up either */ if (cfile->f_flags & O_SYNC) @@ -1293,6 +1315,7 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush) if (server->ops->get_lease_key) server->ops->get_lease_key(inode, &cfile->fid); +retry_open: oparms = (struct cifs_open_parms) { .tcon = tcon, .cifs_sb = cifs_sb, @@ -1318,6 +1341,11 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush) /* indicate that we need to relock the file */ oparms.reconnect = true; } + if (rc == -EACCES && rdwr_for_fscache == 1) { + desired_access = cifs_convert_flags(cfile->f_flags, 0); + rdwr_for_fscache = 2; + goto retry_open; + } if (rc) { mutex_unlock(&cfile->fh_mutex); @@ -1326,6 +1354,9 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush) goto reopen_error_exit; } + if (rdwr_for_fscache == 2) + cifs_invalidate_cache(inode, FSCACHE_INVAL_DIO_WRITE); + #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY reopen_success: #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ diff --git a/fs/smb/client/fscache.h b/fs/smb/client/fscache.h index a3d73720914f..1f2ea9f5cc9a 100644 --- a/fs/smb/client/fscache.h +++ b/fs/smb/client/fscache.h @@ -109,6 +109,11 @@ static inline void cifs_readahead_to_fscache(struct inode *inode, __cifs_readahead_to_fscache(inode, pos, len); } +static inline bool cifs_fscache_enabled(struct inode *inode) +{ + return fscache_cookie_enabled(cifs_inode_cookie(inode)); +} + #else /* CONFIG_CIFS_FSCACHE */ static inline void cifs_fscache_fill_coherency(struct inode *inode, @@ -124,6 +129,7 @@ static inline void cifs_fscache_release_inode_cookie(struct inode *inode) {} static inline void cifs_fscache_unuse_inode_cookie(struct inode *inode, bool update) {} static inline struct fscache_cookie *cifs_inode_cookie(struct inode *inode) { return NULL; } static inline void cifs_invalidate_cache(struct inode *inode, unsigned int flags) {} +static inline bool cifs_fscache_enabled(struct inode *inode) { return false; } static inline int cifs_fscache_query_occupancy(struct inode *inode, pgoff_t first, unsigned int nr_pages,