From patchwork Mon Jul 13 16:37:07 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Howells X-Patchwork-Id: 11660625 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id ADCAA14DD for ; Mon, 13 Jul 2020 16:37:28 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 96BF3206F5 for ; Mon, 13 Jul 2020 16:37:28 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="T+2Xf2Re" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729027AbgGMQh1 (ORCPT ); Mon, 13 Jul 2020 12:37:27 -0400 Received: from us-smtp-2.mimecast.com ([207.211.31.81]:57517 "EHLO us-smtp-delivery-1.mimecast.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1730248AbgGMQh0 (ORCPT ); Mon, 13 Jul 2020 12:37:26 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1594658245; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=nkl9/v1z2n5oTxi5AR2lnE/ZboSNKokLUsnZ/l22yc8=; b=T+2Xf2ReSAV1RVMRMFdWlyUCFCuzI0HCiuS0vtFfQ4rXCHkw9COqsHbA3hlgmz50ftnW7g 9oOzxKNYwYNLJfWK8Lhfq3o7PAVg1mQcOlIHsD55QPyeBQSONzctWZ6P3mL0YtGQs9PGS5 b4smWybX9qyDpwuIMqCsxZGswosP24Y= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-45-T9ZeSXHxM2Grd9KFjb2RhA-1; Mon, 13 Jul 2020 12:37:15 -0400 X-MC-Unique: T9ZeSXHxM2Grd9KFjb2RhA-1 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id C4BCE1080; Mon, 13 Jul 2020 16:37:13 +0000 (UTC) Received: from warthog.procyon.org.uk (ovpn-112-113.rdu2.redhat.com [10.10.112.113]) by smtp.corp.redhat.com (Postfix) with ESMTP id 9B20760C87; Mon, 13 Jul 2020 16:37:08 +0000 (UTC) Organization: Red Hat UK Ltd. Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SI4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 3798903 Subject: [PATCH 01/13] afs: Fix interruption of operations From: David Howells To: Trond Myklebust , Anna Schumaker , Steve French , Alexander Viro , Matthew Wilcox Cc: Jeff Layton , Dave Wysochanski , dhowells@redhat.com, linux-cachefs@redhat.com, linux-afs@lists.infradead.org, linux-nfs@vger.kernel.org, linux-cifs@vger.kernel.org, ceph-devel@vger.kernel.org, v9fs-developer@lists.sourceforge.net, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Date: Mon, 13 Jul 2020 17:37:07 +0100 Message-ID: <159465822787.1377938.10874079234418111929.stgit@warthog.procyon.org.uk> In-Reply-To: <159465821598.1377938.2046362270225008168.stgit@warthog.procyon.org.uk> References: <159465821598.1377938.2046362270225008168.stgit@warthog.procyon.org.uk> User-Agent: StGit/0.22 MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 Sender: linux-nfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org The afs filesystem driver allows unstarted operations to be cancelled by signal, but most of these can easily be restarted (mkdir for example). The primary culprits for reproducing this are those applications that use SIGALRM to display a progress counter. File lock-extension operation is marked uninterruptible as we have a limited time in which to do it, and the release op is marked uninterruptible also as if we fail to unlock a file, we'll have to wait 20 mins before anyone can lock it again. The store operation logs a warning if it gets interruption, e.g.: kAFS: Unexpected error from FS.StoreData -4 because it's run from the background - but it can also be run from fdatasync()-type things. However, store options aren't marked interruptible at the moment. Fix this in the following ways: (1) Mark store operations as uninterruptible. It might make sense to relax this for certain situations, but I'm not sure how to make sure that background store ops aren't affected by signals to foreground processes that happen to trigger them. (2) In afs_get_io_locks(), where we're getting the serialisation lock for talking to the fileserver, return ERESTARTSYS rather than EINTR because a lot of the operations (e.g. mkdir) are restartable if we haven't yet started sending the op to the server. Fixes: e49c7b2f6de7 ("afs: Build an abstraction around an "operation" concept") Signed-off-by: David Howells --- fs/afs/fs_operation.c | 4 ++-- fs/afs/write.c | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/afs/fs_operation.c b/fs/afs/fs_operation.c index c264839b2fd0..24fd163c6323 100644 --- a/fs/afs/fs_operation.c +++ b/fs/afs/fs_operation.c @@ -71,7 +71,7 @@ static bool afs_get_io_locks(struct afs_operation *op) swap(vnode, vnode2); if (mutex_lock_interruptible(&vnode->io_lock) < 0) { - op->error = -EINTR; + op->error = -ERESTARTSYS; op->flags |= AFS_OPERATION_STOP; _leave(" = f [I 0]"); return false; @@ -80,7 +80,7 @@ static bool afs_get_io_locks(struct afs_operation *op) if (vnode2) { if (mutex_lock_interruptible_nested(&vnode2->io_lock, 1) < 0) { - op->error = -EINTR; + op->error = -ERESTARTSYS; op->flags |= AFS_OPERATION_STOP; mutex_unlock(&vnode->io_lock); op->flags &= ~AFS_OPERATION_LOCK_0; diff --git a/fs/afs/write.c b/fs/afs/write.c index abfc8d3dc20c..60918b80b729 100644 --- a/fs/afs/write.c +++ b/fs/afs/write.c @@ -449,6 +449,7 @@ static int afs_store_data(struct address_space *mapping, op->store.first_offset = offset; op->store.last_to = to; op->mtime = vnode->vfs_inode.i_mtime; + op->flags |= AFS_OPERATION_UNINTR; op->ops = &afs_store_data_operation; try_next_key: From patchwork Mon Jul 13 16:37:19 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Howells X-Patchwork-Id: 11660627 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 65ABF6C1 for ; Mon, 13 Jul 2020 16:37:36 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 4852D20773 for ; Mon, 13 Jul 2020 16:37:36 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="YHrMbOIC" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730000AbgGMQhe (ORCPT ); Mon, 13 Jul 2020 12:37:34 -0400 Received: from us-smtp-1.mimecast.com ([205.139.110.61]:26771 "EHLO us-smtp-delivery-1.mimecast.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1730291AbgGMQhe (ORCPT ); Mon, 13 Jul 2020 12:37:34 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1594658253; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=x9Ld4IzAJyD8bLDkZqlSlgwBwzWFeMTX5PUJ8HxDvvs=; b=YHrMbOIC0sF1QXTdc6B2mUOFYIRFkQUMjaD0BoOdF2Ll4xFjXtrqTXTSxvCgjXjRmet83H KQtGzbFP7QrME6vL6hUzX653sSKbPe9x2eGjfBlZHjNZ2QvVp8AyJZ6PGUCvZ2ofplprmP CW8BbXJtwXXijjaXv0Hcuf61IVTagVw= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-238-V3p2wwR2PciR5Zh3nu24RQ-1; Mon, 13 Jul 2020 12:37:27 -0400 X-MC-Unique: V3p2wwR2PciR5Zh3nu24RQ-1 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 62BAB107ACCA; Mon, 13 Jul 2020 16:37:25 +0000 (UTC) Received: from warthog.procyon.org.uk (ovpn-112-113.rdu2.redhat.com [10.10.112.113]) by smtp.corp.redhat.com (Postfix) with ESMTP id C33D572E40; Mon, 13 Jul 2020 16:37:19 +0000 (UTC) Organization: Red Hat UK Ltd. Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SI4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 3798903 Subject: [PATCH 02/13] afs: Move key to afs_read struct From: David Howells To: Trond Myklebust , Anna Schumaker , Steve French , Alexander Viro , Matthew Wilcox Cc: Jeff Layton , Dave Wysochanski , dhowells@redhat.com, linux-cachefs@redhat.com, linux-afs@lists.infradead.org, linux-nfs@vger.kernel.org, linux-cifs@vger.kernel.org, ceph-devel@vger.kernel.org, v9fs-developer@lists.sourceforge.net, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Date: Mon, 13 Jul 2020 17:37:19 +0100 Message-ID: <159465823899.1377938.11925978022348532049.stgit@warthog.procyon.org.uk> In-Reply-To: <159465821598.1377938.2046362270225008168.stgit@warthog.procyon.org.uk> References: <159465821598.1377938.2046362270225008168.stgit@warthog.procyon.org.uk> User-Agent: StGit/0.22 MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 Sender: linux-nfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org Stash the key used to authenticate read operations in the afs_read struct. This will be necessary to reissue the operation against the server if a read from the cache fails in upcoming cache changes. Signed-off-by: David Howells --- fs/afs/dir.c | 3 ++- fs/afs/file.c | 16 +++++++++------- fs/afs/internal.h | 3 ++- fs/afs/write.c | 12 ++++++------ 4 files changed, 19 insertions(+), 15 deletions(-) diff --git a/fs/afs/dir.c b/fs/afs/dir.c index 96757f3abd74..a32c9df6d4c4 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c @@ -241,6 +241,7 @@ static struct afs_read *afs_read_dir(struct afs_vnode *dvnode, struct key *key) return ERR_PTR(-ENOMEM); refcount_set(&req->usage, 1); + req->key = key_get(key); req->nr_pages = nr_pages; req->actual_len = i_size; /* May change */ req->len = nr_pages * PAGE_SIZE; /* We can ask for more than there is */ @@ -306,7 +307,7 @@ static struct afs_read *afs_read_dir(struct afs_vnode *dvnode, struct key *key) if (!test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) { trace_afs_reload_dir(dvnode); - ret = afs_fetch_data(dvnode, key, req); + ret = afs_fetch_data(dvnode, req); if (ret < 0) goto error_unlock; diff --git a/fs/afs/file.c b/fs/afs/file.c index 75058de366a1..3c2352dcf976 100644 --- a/fs/afs/file.c +++ b/fs/afs/file.c @@ -211,6 +211,7 @@ void afs_put_read(struct afs_read *req) if (req->pages != req->array) kfree(req->pages); } + key_put(req->key); kfree(req); } } @@ -241,7 +242,7 @@ static const struct afs_operation_ops afs_fetch_data_operation = { /* * Fetch file data from the volume. */ -int afs_fetch_data(struct afs_vnode *vnode, struct key *key, struct afs_read *req) +int afs_fetch_data(struct afs_vnode *vnode, struct afs_read *req) { struct afs_operation *op; @@ -250,9 +251,9 @@ int afs_fetch_data(struct afs_vnode *vnode, struct key *key, struct afs_read *re vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique, - key_serial(key)); + key_serial(req->key)); - op = afs_alloc_operation(key, vnode->volume); + op = afs_alloc_operation(req->key, vnode->volume); if (IS_ERR(op)) return PTR_ERR(op); @@ -291,6 +292,7 @@ int afs_page_filler(void *data, struct page *page) * unmarshalling code will clear the unfilled space. */ refcount_set(&req->usage, 1); + req->key = key_get(key); req->pos = (loff_t)page->index << PAGE_SHIFT; req->len = PAGE_SIZE; req->nr_pages = 1; @@ -300,7 +302,7 @@ int afs_page_filler(void *data, struct page *page) /* read the contents of the file from the server into the * page */ - ret = afs_fetch_data(vnode, key, req); + ret = afs_fetch_data(vnode, req); afs_put_read(req); if (ret < 0) { @@ -385,7 +387,6 @@ static int afs_readpages_one(struct file *file, struct address_space *mapping, struct afs_read *req; struct list_head *p; struct page *first, *page; - struct key *key = afs_file_key(file); pgoff_t index; int ret, n, i; @@ -409,6 +410,7 @@ static int afs_readpages_one(struct file *file, struct address_space *mapping, refcount_set(&req->usage, 1); req->vnode = vnode; + req->key = key_get(afs_file_key(file)); req->page_done = afs_readpages_page_done; req->pos = first->index; req->pos <<= PAGE_SHIFT; @@ -438,11 +440,11 @@ static int afs_readpages_one(struct file *file, struct address_space *mapping, } while (req->nr_pages < n); if (req->nr_pages == 0) { - kfree(req); + afs_put_read(req); return 0; } - ret = afs_fetch_data(vnode, key, req); + ret = afs_fetch_data(vnode, req); if (ret < 0) goto error; diff --git a/fs/afs/internal.h b/fs/afs/internal.h index 4ec6a463081f..644a04ce83a3 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -204,6 +204,7 @@ struct afs_read { loff_t actual_len; /* How much we're actually getting */ loff_t remain; /* Amount remaining */ loff_t file_size; /* File size returned by server */ + struct key *key; /* The key to use to reissue the read */ afs_dataversion_t data_version; /* Version number returned by server */ refcount_t usage; unsigned int index; /* Which page we're reading into */ @@ -969,7 +970,7 @@ extern int afs_cache_wb_key(struct afs_vnode *, struct afs_file *); extern void afs_put_wb_key(struct afs_wb_key *); extern int afs_open(struct inode *, struct file *); extern int afs_release(struct inode *, struct file *); -extern int afs_fetch_data(struct afs_vnode *, struct key *, struct afs_read *); +extern int afs_fetch_data(struct afs_vnode *, struct afs_read *); extern int afs_page_filler(void *, struct page *); extern void afs_put_read(struct afs_read *); diff --git a/fs/afs/write.c b/fs/afs/write.c index 60918b80b729..90dbe12353b6 100644 --- a/fs/afs/write.c +++ b/fs/afs/write.c @@ -25,9 +25,10 @@ int afs_set_page_dirty(struct page *page) /* * partly or wholly fill a page that's under preparation for writing */ -static int afs_fill_page(struct afs_vnode *vnode, struct key *key, +static int afs_fill_page(struct file *file, loff_t pos, unsigned int len, struct page *page) { + struct afs_vnode *vnode = AFS_FS_I(file_inode(file)); struct afs_read *req; size_t p; void *data; @@ -49,6 +50,7 @@ static int afs_fill_page(struct afs_vnode *vnode, struct key *key, return -ENOMEM; refcount_set(&req->usage, 1); + req->key = afs_file_key(file); req->pos = pos; req->len = len; req->nr_pages = 1; @@ -56,7 +58,7 @@ static int afs_fill_page(struct afs_vnode *vnode, struct key *key, req->pages[0] = page; get_page(page); - ret = afs_fetch_data(vnode, key, req); + ret = afs_fetch_data(vnode, req); afs_put_read(req); if (ret < 0) { if (ret == -ENOENT) { @@ -80,7 +82,6 @@ int afs_write_begin(struct file *file, struct address_space *mapping, { struct afs_vnode *vnode = AFS_FS_I(file_inode(file)); struct page *page; - struct key *key = afs_file_key(file); unsigned long priv; unsigned f, from = pos & (PAGE_SIZE - 1); unsigned t, to = from + len; @@ -100,7 +101,7 @@ int afs_write_begin(struct file *file, struct address_space *mapping, return -ENOMEM; if (!PageUptodate(page) && len != PAGE_SIZE) { - ret = afs_fill_page(vnode, key, pos & PAGE_MASK, PAGE_SIZE, page); + ret = afs_fill_page(file, pos & PAGE_MASK, PAGE_SIZE, page); if (ret < 0) { unlock_page(page); put_page(page); @@ -183,7 +184,6 @@ int afs_write_end(struct file *file, struct address_space *mapping, struct page *page, void *fsdata) { struct afs_vnode *vnode = AFS_FS_I(file_inode(file)); - struct key *key = afs_file_key(file); loff_t i_size, maybe_i_size; int ret; @@ -207,7 +207,7 @@ int afs_write_end(struct file *file, struct address_space *mapping, * unmarshalling routine will take care of clearing any * bits that are beyond the EOF. */ - ret = afs_fill_page(vnode, key, pos + copied, + ret = afs_fill_page(file, pos + copied, len - copied, page); if (ret < 0) goto out; From patchwork Mon Jul 13 16:37:30 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Howells X-Patchwork-Id: 11660637 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id B788814DD for ; Mon, 13 Jul 2020 16:37:46 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 9933C206F5 for ; Mon, 13 Jul 2020 16:37:46 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="iWhpoSFL" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730572AbgGMQhp (ORCPT ); Mon, 13 Jul 2020 12:37:45 -0400 Received: from us-smtp-delivery-1.mimecast.com ([207.211.31.120]:22278 "EHLO us-smtp-1.mimecast.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1729969AbgGMQho (ORCPT ); Mon, 13 Jul 2020 12:37:44 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1594658261; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=HTqELeE3psnsv4vKlzTz9cvjP0XhH36aOWb0J65Pzhs=; b=iWhpoSFLqla7dz7IfGLlKpFYW8Jz8qsrS7+C+OD93SUDZaW/YusQpTfl3eTJPYQaZjEbdC ydle7gjDFWAFBwn65FKbGKdGRG23KP/OaPV3w2JxleF+bAvVbk1o/GSaQNhS5nOG8nV0Ku qNXkMNXW7ZwnSdrYDCmf9qTJ+7vcS10= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-223-l2pKWbqAMGmKDNrbNj3G-g-1; Mon, 13 Jul 2020 12:37:39 -0400 X-MC-Unique: l2pKWbqAMGmKDNrbNj3G-g-1 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 4A720800FED; Mon, 13 Jul 2020 16:37:37 +0000 (UTC) Received: from warthog.procyon.org.uk (ovpn-112-113.rdu2.redhat.com [10.10.112.113]) by smtp.corp.redhat.com (Postfix) with ESMTP id 5ADE560C87; Mon, 13 Jul 2020 16:37:31 +0000 (UTC) Organization: Red Hat UK Ltd. Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SI4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 3798903 Subject: [PATCH 03/13] afs: Don't truncate iter during data fetch From: David Howells To: Trond Myklebust , Anna Schumaker , Steve French , Alexander Viro , Matthew Wilcox Cc: Jeff Layton , Dave Wysochanski , dhowells@redhat.com, linux-cachefs@redhat.com, linux-afs@lists.infradead.org, linux-nfs@vger.kernel.org, linux-cifs@vger.kernel.org, ceph-devel@vger.kernel.org, v9fs-developer@lists.sourceforge.net, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Date: Mon, 13 Jul 2020 17:37:30 +0100 Message-ID: <159465825061.1377938.14403904452300909320.stgit@warthog.procyon.org.uk> In-Reply-To: <159465821598.1377938.2046362270225008168.stgit@warthog.procyon.org.uk> References: <159465821598.1377938.2046362270225008168.stgit@warthog.procyon.org.uk> User-Agent: StGit/0.22 MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 Sender: linux-nfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org Don't truncate the iterator to correspond to the actual data size when fetching the data from the server - rather, pass the length we want to read to rxrpc. This will allow the clear-after-read code in future to simply clear the remaining iterator capacity rather than having to reinitialise the iterator. Signed-off-by: David Howells --- fs/afs/fsclient.c | 6 ++++-- fs/afs/internal.h | 6 ++++++ fs/afs/rxrpc.c | 13 +++++++++---- fs/afs/yfsclient.c | 6 ++++-- include/net/af_rxrpc.h | 2 +- net/rxrpc/recvmsg.c | 9 +++++---- 6 files changed, 29 insertions(+), 13 deletions(-) diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c index acb4d0ca2649..3ed95f3e47be 100644 --- a/fs/afs/fsclient.c +++ b/fs/afs/fsclient.c @@ -305,8 +305,9 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call) unsigned int size; int ret; - _enter("{%u,%zu/%llu}", - call->unmarshall, iov_iter_count(call->iter), req->actual_len); + _enter("{%u,%zu,%zu/%llu}", + call->unmarshall, call->iov_len, iov_iter_count(call->iter), + req->actual_len); switch (call->unmarshall) { case 0: @@ -343,6 +344,7 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call) size = PAGE_SIZE - req->offset; else size = req->remain; + call->iov_len = size; call->bvec[0].bv_len = size; call->bvec[0].bv_offset = req->offset; call->bvec[0].bv_page = req->pages[req->index]; diff --git a/fs/afs/internal.h b/fs/afs/internal.h index 644a04ce83a3..bf26fd28ccbd 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -104,6 +104,7 @@ struct afs_call { struct afs_server *server; /* The fileserver record if fs op (pins ref) */ struct afs_vlserver *vlserver; /* The vlserver record if vl op */ void *request; /* request data (first part) */ + size_t iov_len; /* Size of *iter to be used */ struct iov_iter def_iter; /* Default buffer/data iterator */ struct iov_iter *iter; /* Iterator currently in use */ union { /* Convenience for ->def_iter */ @@ -1194,6 +1195,7 @@ static inline void afs_make_op_call(struct afs_operation *op, struct afs_call *c static inline void afs_extract_begin(struct afs_call *call, void *buf, size_t size) { + call->iov_len = size; call->kvec[0].iov_base = buf; call->kvec[0].iov_len = size; iov_iter_kvec(&call->def_iter, READ, call->kvec, 1, size); @@ -1201,21 +1203,25 @@ static inline void afs_extract_begin(struct afs_call *call, void *buf, size_t si static inline void afs_extract_to_tmp(struct afs_call *call) { + call->iov_len = sizeof(call->tmp); afs_extract_begin(call, &call->tmp, sizeof(call->tmp)); } static inline void afs_extract_to_tmp64(struct afs_call *call) { + call->iov_len = sizeof(call->tmp64); afs_extract_begin(call, &call->tmp64, sizeof(call->tmp64)); } static inline void afs_extract_discard(struct afs_call *call, size_t size) { + call->iov_len = size; iov_iter_discard(&call->def_iter, READ, size); } static inline void afs_extract_to_buf(struct afs_call *call, size_t size) { + call->iov_len = size; afs_extract_begin(call, call->buffer, size); } diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c index 8fc8fb406a5a..3b90ecf7958d 100644 --- a/fs/afs/rxrpc.c +++ b/fs/afs/rxrpc.c @@ -363,6 +363,7 @@ void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp) struct rxrpc_call *rxcall; struct msghdr msg; struct kvec iov[1]; + size_t len; s64 tx_total_len; int ret; @@ -466,9 +467,10 @@ void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp) rxrpc_kernel_abort_call(call->net->socket, rxcall, RX_USER_ABORT, ret, "KSD"); } else { + len = 0; iov_iter_kvec(&msg.msg_iter, READ, NULL, 0, 0); rxrpc_kernel_recv_data(call->net->socket, rxcall, - &msg.msg_iter, false, + &msg.msg_iter, &len, false, &call->abort_code, &call->service_id); ac->abort_code = call->abort_code; ac->responded = true; @@ -504,6 +506,7 @@ void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp) static void afs_deliver_to_call(struct afs_call *call) { enum afs_call_state state; + size_t len; u32 abort_code, remote_abort = 0; int ret; @@ -516,10 +519,11 @@ static void afs_deliver_to_call(struct afs_call *call) state == AFS_CALL_SV_AWAIT_ACK ) { if (state == AFS_CALL_SV_AWAIT_ACK) { + len = 0; iov_iter_kvec(&call->def_iter, READ, NULL, 0, 0); ret = rxrpc_kernel_recv_data(call->net->socket, call->rxcall, &call->def_iter, - false, &remote_abort, + &len, false, &remote_abort, &call->service_id); trace_afs_receive_data(call, &call->def_iter, false, ret); @@ -929,10 +933,11 @@ int afs_extract_data(struct afs_call *call, bool want_more) u32 remote_abort = 0; int ret; - _enter("{%s,%zu},%d", call->type->name, iov_iter_count(iter), want_more); + _enter("{%s,%zu,%zu},%d", + call->type->name, call->iov_len, iov_iter_count(iter), want_more); ret = rxrpc_kernel_recv_data(net->socket, call->rxcall, iter, - want_more, &remote_abort, + &call->iov_len, want_more, &remote_abort, &call->service_id); if (ret == 0 || ret == -EAGAIN) return ret; diff --git a/fs/afs/yfsclient.c b/fs/afs/yfsclient.c index 8c24fdc899e3..a53bcea8740c 100644 --- a/fs/afs/yfsclient.c +++ b/fs/afs/yfsclient.c @@ -363,8 +363,9 @@ static int yfs_deliver_fs_fetch_data64(struct afs_call *call) unsigned int size; int ret; - _enter("{%u,%zu/%llu}", - call->unmarshall, iov_iter_count(call->iter), req->actual_len); + _enter("{%u,%zu, %zu/%llu}", + call->unmarshall, call->iov_len, iov_iter_count(call->iter), + req->actual_len); switch (call->unmarshall) { case 0: @@ -396,6 +397,7 @@ static int yfs_deliver_fs_fetch_data64(struct afs_call *call) size = PAGE_SIZE - req->offset; else size = req->remain; + call->iov_len = size; call->bvec[0].bv_len = size; call->bvec[0].bv_offset = req->offset; call->bvec[0].bv_page = req->pages[req->index]; diff --git a/include/net/af_rxrpc.h b/include/net/af_rxrpc.h index 91eacbdcf33d..076bf895be1d 100644 --- a/include/net/af_rxrpc.h +++ b/include/net/af_rxrpc.h @@ -53,7 +53,7 @@ int rxrpc_kernel_send_data(struct socket *, struct rxrpc_call *, struct msghdr *, size_t, rxrpc_notify_end_tx_t); int rxrpc_kernel_recv_data(struct socket *, struct rxrpc_call *, - struct iov_iter *, bool, u32 *, u16 *); + struct iov_iter *, size_t *, bool, u32 *, u16 *); bool rxrpc_kernel_abort_call(struct socket *, struct rxrpc_call *, u32, int, const char *); void rxrpc_kernel_end_call(struct socket *, struct rxrpc_call *); diff --git a/net/rxrpc/recvmsg.c b/net/rxrpc/recvmsg.c index 2989742a4aa1..ea3c42c417b3 100644 --- a/net/rxrpc/recvmsg.c +++ b/net/rxrpc/recvmsg.c @@ -703,6 +703,7 @@ int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, * @sock: The socket that the call exists on * @call: The call to send data through * @iter: The buffer to receive into + * @_len: The amount of data we want to receive (decreased on return) * @want_more: True if more data is expected to be read * @_abort: Where the abort code is stored if -ECONNABORTED is returned * @_service: Where to store the actual service ID (may be upgraded) @@ -718,7 +719,7 @@ int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, * *_abort should also be initialised to 0. */ int rxrpc_kernel_recv_data(struct socket *sock, struct rxrpc_call *call, - struct iov_iter *iter, + struct iov_iter *iter, size_t *_len, bool want_more, u32 *_abort, u16 *_service) { size_t offset = 0; @@ -726,7 +727,7 @@ int rxrpc_kernel_recv_data(struct socket *sock, struct rxrpc_call *call, _enter("{%d,%s},%zu,%d", call->debug_id, rxrpc_call_states[call->state], - iov_iter_count(iter), want_more); + *_len, want_more); ASSERTCMP(call->state, !=, RXRPC_CALL_SERVER_ACCEPTING); @@ -737,8 +738,8 @@ int rxrpc_kernel_recv_data(struct socket *sock, struct rxrpc_call *call, case RXRPC_CALL_SERVER_RECV_REQUEST: case RXRPC_CALL_SERVER_ACK_REQUEST: ret = rxrpc_recvmsg_data(sock, call, NULL, iter, - iov_iter_count(iter), 0, - &offset); + *_len, 0, &offset); + *_len -= offset; if (ret < 0) goto out; From patchwork Mon Jul 13 16:37:42 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Howells X-Patchwork-Id: 11660645 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 92AAA13B4 for ; Mon, 13 Jul 2020 16:37:55 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 7AF1E2067D for ; Mon, 13 Jul 2020 16:37:55 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="Lv9UQ2x+" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730526AbgGMQhy (ORCPT ); Mon, 13 Jul 2020 12:37:54 -0400 Received: from us-smtp-delivery-1.mimecast.com ([207.211.31.120]:36383 "EHLO us-smtp-1.mimecast.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1729764AbgGMQhy (ORCPT ); Mon, 13 Jul 2020 12:37:54 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1594658272; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=FFeMgMH6/qMZ3nIQyi9/O1g4FNmz8A5J8WnvntZKDog=; b=Lv9UQ2x+bwD9jkUJWCuPqQXsOs5/jx+4xdXNfUbpDHhC4q1D7+bbxcgZY6mKiDR5kGyzA2 hm6GGtV/AY6/ocpC3r1c68d6XirDYB2hwWHdJR+NOujm6kH5cCGtOH20wPZmTBbLJLGSzL SQwrc7fg5ofJCPmbXQ96EXiTVfg7DUQ= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-119-6AapF4vjMmSlnJOdYKoFXw-1; Mon, 13 Jul 2020 12:37:50 -0400 X-MC-Unique: 6AapF4vjMmSlnJOdYKoFXw-1 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id BC1EB100CCC0; Mon, 13 Jul 2020 16:37:48 +0000 (UTC) Received: from warthog.procyon.org.uk (ovpn-112-113.rdu2.redhat.com [10.10.112.113]) by smtp.corp.redhat.com (Postfix) with ESMTP id 52D155BAD5; Mon, 13 Jul 2020 16:37:43 +0000 (UTC) Organization: Red Hat UK Ltd. Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SI4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 3798903 Subject: [PATCH 04/13] afs: Log remote unmarshalling errors From: David Howells To: Trond Myklebust , Anna Schumaker , Steve French , Alexander Viro , Matthew Wilcox Cc: Jeff Layton , Dave Wysochanski , dhowells@redhat.com, linux-cachefs@redhat.com, linux-afs@lists.infradead.org, linux-nfs@vger.kernel.org, linux-cifs@vger.kernel.org, ceph-devel@vger.kernel.org, v9fs-developer@lists.sourceforge.net, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Date: Mon, 13 Jul 2020 17:37:42 +0100 Message-ID: <159465826250.1377938.16372395422217583913.stgit@warthog.procyon.org.uk> In-Reply-To: <159465821598.1377938.2046362270225008168.stgit@warthog.procyon.org.uk> References: <159465821598.1377938.2046362270225008168.stgit@warthog.procyon.org.uk> User-Agent: StGit/0.22 MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.15 Sender: linux-nfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org Log unmarshalling errors reported by the peer (ie. it can't parse what we sent it). Limit the maximum number of messages to 3. Signed-off-by: David Howells --- fs/afs/rxrpc.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c index 3b90ecf7958d..48361bbd4859 100644 --- a/fs/afs/rxrpc.c +++ b/fs/afs/rxrpc.c @@ -500,6 +500,39 @@ void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp) _leave(" = %d", ret); } +/* + * Log remote abort codes that indicate that we have a protocol disagreement + * with the server. + */ +static void afs_log_error(struct afs_call *call, s32 remote_abort) +{ + static int max = 0; + const char *msg; + int m; + + switch (remote_abort) { + case RX_EOF: msg = "unexpected EOF"; break; + case RXGEN_CC_MARSHAL: msg = "client marshalling"; break; + case RXGEN_CC_UNMARSHAL: msg = "client unmarshalling"; break; + case RXGEN_SS_MARSHAL: msg = "server marshalling"; break; + case RXGEN_SS_UNMARSHAL: msg = "server unmarshalling"; break; + case RXGEN_DECODE: msg = "opcode decode"; break; + case RXGEN_SS_XDRFREE: msg = "server XDR cleanup"; break; + case RXGEN_CC_XDRFREE: msg = "client XDR cleanup"; break; + case -32: msg = "insufficient data"; break; + default: + return; + } + + m = max; + if (m < 3) { + max = m + 1; + pr_notice("kAFS: Peer reported %s failure on %s [%pISp]\n", + msg, call->type->name, + &call->alist->addrs[call->addr_ix].transport); + } +} + /* * deliver messages to a call */ @@ -563,6 +596,7 @@ static void afs_deliver_to_call(struct afs_call *call) goto out; case -ECONNABORTED: ASSERTCMP(state, ==, AFS_CALL_COMPLETE); + afs_log_error(call, call->abort_code); goto done; case -ENOTSUPP: abort_code = RXGEN_OPCODE; From patchwork Mon Jul 13 16:37:54 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Howells X-Patchwork-Id: 11660657 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 690326C1 for ; Mon, 13 Jul 2020 16:38:13 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 2E5C620738 for ; Mon, 13 Jul 2020 16:38:13 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="fLNycn7G" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730206AbgGMQiM (ORCPT ); Mon, 13 Jul 2020 12:38:12 -0400 Received: from us-smtp-1.mimecast.com ([207.211.31.81]:27282 "EHLO us-smtp-delivery-1.mimecast.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1730453AbgGMQiK (ORCPT ); Mon, 13 Jul 2020 12:38:10 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1594658286; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=IGqxPeL8hsfySG5Qb/o4GvFBEpPLFRDV8qb2wSq1fU4=; b=fLNycn7Ge57s2yNo6aSyvv3j3Pd8zA6i9S/61x2lCZhEwIHA0IC0VHzedWgRKo0zQmdSXY 1E5RUTeP7DywqBER/t0aA3V3ubEH24sH1d/ArDT4uzq8tn8DoSgTxPmHDcvcUTDYuuNvJE TsgGKRmMptnhmLJVrccLi0oubZR90SE= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-243-eD0O30hMNTWqXs5UbONwvg-1; Mon, 13 Jul 2020 12:38:02 -0400 X-MC-Unique: eD0O30hMNTWqXs5UbONwvg-1 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id D0F62100CCCD; Mon, 13 Jul 2020 16:38:00 +0000 (UTC) Received: from warthog.procyon.org.uk (ovpn-112-113.rdu2.redhat.com [10.10.112.113]) by smtp.corp.redhat.com (Postfix) with ESMTP id C3A2860BF3; Mon, 13 Jul 2020 16:37:54 +0000 (UTC) Organization: Red Hat UK Ltd. Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SI4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 3798903 Subject: [PATCH 05/13] afs: Set up the iov_iter before calling afs_extract_data() From: David Howells To: Trond Myklebust , Anna Schumaker , Steve French , Alexander Viro , Matthew Wilcox Cc: Jeff Layton , Dave Wysochanski , dhowells@redhat.com, linux-cachefs@redhat.com, linux-afs@lists.infradead.org, linux-nfs@vger.kernel.org, linux-cifs@vger.kernel.org, ceph-devel@vger.kernel.org, v9fs-developer@lists.sourceforge.net, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Date: Mon, 13 Jul 2020 17:37:54 +0100 Message-ID: <159465827399.1377938.11181327349704960046.stgit@warthog.procyon.org.uk> In-Reply-To: <159465821598.1377938.2046362270225008168.stgit@warthog.procyon.org.uk> References: <159465821598.1377938.2046362270225008168.stgit@warthog.procyon.org.uk> User-Agent: StGit/0.22 MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 Sender: linux-nfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org afs_extract_data sets up a temporary iov_iter and passes it to AF_RXRPC each time it is called to describe the remaining buffer to be filled. Instead: (1) Put an iterator in the afs_call struct. (2) Set the iterator for each marshalling stage to load data into the appropriate places. A number of convenience functions are provided to this end (eg. afs_extract_to_buf()). This iterator is then passed to afs_extract_data(). (3) Use the new ITER_MAPPING iterator when reading data to load directly into the inode's pages without needing to create a list of them. This comes with a page-done callback that can be used to unlock pages as they are filled. This will allow O_DIRECT calls to be supported in future patches. Signed-off-by: David Howells --- fs/afs/dir.c | 223 +++++++++++++++++++++++++++++++++++----------------- fs/afs/file.c | 190 ++++++++++++++++++++++++++------------------ fs/afs/fsclient.c | 55 +++---------- fs/afs/internal.h | 16 ++-- fs/afs/write.c | 28 +++++-- fs/afs/yfsclient.c | 55 +++---------- 6 files changed, 317 insertions(+), 250 deletions(-) diff --git a/fs/afs/dir.c b/fs/afs/dir.c index a32c9df6d4c4..56991bb01f62 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c @@ -102,6 +102,35 @@ struct afs_lookup_cookie { struct afs_fid fids[50]; }; +/* + * Drop the refs that we're holding on the pages we were reading into. We've + * got refs on the first nr_pages pages. + */ +static void afs_dir_read_cleanup(struct afs_read *req) +{ + struct address_space *mapping = req->iter->mapping; + struct page *page; + pgoff_t last = req->nr_pages - 1; + + XA_STATE(xas, &mapping->i_pages, 0); + + if (unlikely(!req->nr_pages)) + return; + + rcu_read_lock(); + xas_for_each(&xas, page, last) { + if (xas_retry(&xas, page)) + continue; + BUG_ON(xa_is_value(page)); + BUG_ON(PageCompound(page)); + ASSERTCMP(page->mapping, ==, mapping); + + put_page(page); + } + + rcu_read_unlock(); +} + /* * check that a directory page is valid */ @@ -127,7 +156,7 @@ static bool afs_dir_check_page(struct afs_vnode *dvnode, struct page *page, qty /= sizeof(union afs_xdr_dir_block); /* check them */ - dbuf = kmap(page); + dbuf = kmap_atomic(page); for (tmp = 0; tmp < qty; tmp++) { if (dbuf->blocks[tmp].hdr.magic != AFS_DIR_MAGIC) { printk("kAFS: %s(%lx): bad magic %d/%d is %04hx\n", @@ -146,7 +175,7 @@ static bool afs_dir_check_page(struct afs_vnode *dvnode, struct page *page, ((u8 *)&dbuf->blocks[tmp])[AFS_DIR_BLOCK_SIZE - 1] = 0; } - kunmap(page); + kunmap_atomic(dbuf); checked: afs_stat_v(dvnode, n_read_dir); @@ -157,35 +186,74 @@ static bool afs_dir_check_page(struct afs_vnode *dvnode, struct page *page, } /* - * Check the contents of a directory that we've just read. + * Dump the contents of a directory. */ -static bool afs_dir_check_pages(struct afs_vnode *dvnode, struct afs_read *req) +static void afs_dir_dump(struct afs_vnode *dvnode, struct afs_read *req) { struct afs_xdr_dir_page *dbuf; - unsigned int i, j, qty = PAGE_SIZE / sizeof(union afs_xdr_dir_block); + struct address_space *mapping = dvnode->vfs_inode.i_mapping; + struct page *page; + unsigned int i, qty = PAGE_SIZE / sizeof(union afs_xdr_dir_block); + pgoff_t last = req->nr_pages - 1; - for (i = 0; i < req->nr_pages; i++) - if (!afs_dir_check_page(dvnode, req->pages[i], req->actual_len)) - goto bad; - return true; + XA_STATE(xas, &mapping->i_pages, 0); -bad: - pr_warn("DIR %llx:%llx f=%llx l=%llx al=%llx r=%llx\n", + pr_warn("DIR %llx:%llx f=%llx l=%llx al=%llx\n", dvnode->fid.vid, dvnode->fid.vnode, - req->file_size, req->len, req->actual_len, req->remain); - pr_warn("DIR %llx %x %x %x\n", - req->pos, req->index, req->nr_pages, req->offset); + req->file_size, req->len, req->actual_len); + pr_warn("DIR %llx %x %zx %zx\n", + req->pos, req->nr_pages, + req->iter->iov_offset, iov_iter_count(req->iter)); - for (i = 0; i < req->nr_pages; i++) { - dbuf = kmap(req->pages[i]); - for (j = 0; j < qty; j++) { - union afs_xdr_dir_block *block = &dbuf->blocks[j]; + xas_for_each(&xas, page, last) { + if (xas_retry(&xas, page)) + continue; + + BUG_ON(PageCompound(page)); + BUG_ON(page->mapping != mapping); + + dbuf = kmap_atomic(page); + for (i = 0; i < qty; i++) { + union afs_xdr_dir_block *block = &dbuf->blocks[i]; - pr_warn("[%02x] %32phN\n", i * qty + j, block); + pr_warn("[%02lx] %32phN\n", page->index * qty + i, block); } - kunmap(req->pages[i]); + kunmap_atomic(dbuf); } - return false; +} + +/* + * Check all the pages in a directory. All the pages are held pinned. + */ +static int afs_dir_check(struct afs_vnode *dvnode, struct afs_read *req) +{ + struct address_space *mapping = dvnode->vfs_inode.i_mapping; + struct page *page; + pgoff_t last = req->nr_pages - 1; + int ret = 0; + + XA_STATE(xas, &mapping->i_pages, 0); + + if (unlikely(!req->nr_pages)) + return 0; + + rcu_read_lock(); + xas_for_each(&xas, page, last) { + if (xas_retry(&xas, page)) + continue; + + BUG_ON(PageCompound(page)); + BUG_ON(page->mapping != mapping); + + ret = afs_dir_check_page(dvnode, page, req->file_size); + if (ret < 0) { + afs_dir_dump(dvnode, req); + break; + } + } + + rcu_read_unlock(); + return ret; } /* @@ -214,58 +282,56 @@ static struct afs_read *afs_read_dir(struct afs_vnode *dvnode, struct key *key) { struct afs_read *req; loff_t i_size; - int nr_pages, nr_inline, i, n; - int ret = -ENOMEM; + int nr_pages, i, n; + int ret; + + _enter(""); -retry: + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return ERR_PTR(-ENOMEM); + + refcount_set(&req->usage, 1); + req->key = key_get(key); + req->cleanup = afs_dir_read_cleanup; + +expand: i_size = i_size_read(&dvnode->vfs_inode); - if (i_size < 2048) - return ERR_PTR(afs_bad(dvnode, afs_file_error_dir_small)); + if (i_size < 2048) { + ret = afs_bad(dvnode, afs_file_error_dir_small); + goto error; + } if (i_size > 2048 * 1024) { trace_afs_file_error(dvnode, -EFBIG, afs_file_error_dir_big); - return ERR_PTR(-EFBIG); + ret = -EFBIG; + goto error; } _enter("%llu", i_size); - /* Get a request record to hold the page list. We want to hold it - * inline if we can, but we don't want to make an order 1 allocation. - */ nr_pages = (i_size + PAGE_SIZE - 1) / PAGE_SIZE; - nr_inline = nr_pages; - if (nr_inline > (PAGE_SIZE - sizeof(*req)) / sizeof(struct page *)) - nr_inline = 0; - req = kzalloc(struct_size(req, array, nr_inline), GFP_KERNEL); - if (!req) - return ERR_PTR(-ENOMEM); - - refcount_set(&req->usage, 1); - req->key = key_get(key); - req->nr_pages = nr_pages; req->actual_len = i_size; /* May change */ req->len = nr_pages * PAGE_SIZE; /* We can ask for more than there is */ req->data_version = dvnode->status.data_version; /* May change */ - if (nr_inline > 0) { - req->pages = req->array; - } else { - req->pages = kcalloc(nr_pages, sizeof(struct page *), - GFP_KERNEL); - if (!req->pages) - goto error; - } + iov_iter_mapping(&req->def_iter, READ, dvnode->vfs_inode.i_mapping, + 0, i_size); + req->iter = &req->def_iter; - /* Get a list of all the pages that hold or will hold the directory - * content. We need to fill in any gaps that we might find where the - * memory reclaimer has been at work. If there are any gaps, we will + /* Fill in any gaps that we might find where the memory reclaimer has + * been at work and pin all the pages. If there are any gaps, we will * need to reread the entire directory contents. */ - i = 0; - do { + i = req->nr_pages; + while (i < nr_pages) { + struct page *pages[8], *page; + n = find_get_pages_contig(dvnode->vfs_inode.i_mapping, i, - req->nr_pages - i, - req->pages + i); - _debug("find %u at %u/%u", n, i, req->nr_pages); + min_t(unsigned int, nr_pages - i, + ARRAY_SIZE(pages)), + pages); + _debug("find %u at %u/%u", n, i, nr_pages); + if (n == 0) { gfp_t gfp = dvnode->vfs_inode.i_mapping->gfp_mask; @@ -273,23 +339,25 @@ static struct afs_read *afs_read_dir(struct afs_vnode *dvnode, struct key *key) afs_stat_v(dvnode, n_inval); ret = -ENOMEM; - req->pages[i] = __page_cache_alloc(gfp); - if (!req->pages[i]) + page = __page_cache_alloc(gfp); + if (!page) goto error; - ret = add_to_page_cache_lru(req->pages[i], + ret = add_to_page_cache_lru(page, dvnode->vfs_inode.i_mapping, i, gfp); if (ret < 0) goto error; - set_page_private(req->pages[i], 1); - SetPagePrivate(req->pages[i]); - unlock_page(req->pages[i]); + set_page_private(page, 1); + SetPagePrivate(page); + unlock_page(page); + req->nr_pages++; i++; } else { + req->nr_pages += n; i += n; } - } while (i < req->nr_pages); + } /* If we're going to reload, we need to lock all the pages to prevent * races. @@ -313,12 +381,17 @@ static struct afs_read *afs_read_dir(struct afs_vnode *dvnode, struct key *key) task_io_account_read(PAGE_SIZE * req->nr_pages); - if (req->len < req->file_size) - goto content_has_grown; + if (req->len < req->file_size) { + /* The content has grown, so we need to expand the + * buffer. + */ + up_write(&dvnode->validate_lock); + goto expand; + } /* Validate the data we just read. */ - ret = -EIO; - if (!afs_dir_check_pages(dvnode, req)) + ret = afs_dir_check(dvnode, req); + if (ret < 0) goto error_unlock; // TODO: Trim excess pages @@ -336,11 +409,6 @@ static struct afs_read *afs_read_dir(struct afs_vnode *dvnode, struct key *key) afs_put_read(req); _leave(" = %d", ret); return ERR_PTR(ret); - -content_has_grown: - up_write(&dvnode->validate_lock); - afs_put_read(req); - goto retry; } /* @@ -447,6 +515,7 @@ static int afs_dir_iterate(struct inode *dir, struct dir_context *ctx, struct afs_read *req; struct page *page; unsigned blkoff, limit; + void __rcu **slot; int ret; _enter("{%lu},%u,,", dir->i_ino, (unsigned)ctx->pos); @@ -471,9 +540,15 @@ static int afs_dir_iterate(struct inode *dir, struct dir_context *ctx, blkoff = ctx->pos & ~(sizeof(union afs_xdr_dir_block) - 1); /* Fetch the appropriate page from the directory and re-add it - * to the LRU. + * to the LRU. We have all the pages pinned with an extra ref. */ - page = req->pages[blkoff / PAGE_SIZE]; + rcu_read_lock(); + page = NULL; + slot = radix_tree_lookup_slot(&dvnode->vfs_inode.i_mapping->i_pages, + blkoff / PAGE_SIZE); + if (slot) + page = radix_tree_deref_slot(slot); + rcu_read_unlock(); if (!page) { ret = afs_bad(dvnode, afs_file_error_dir_missing_page); break; diff --git a/fs/afs/file.c b/fs/afs/file.c index 3c2352dcf976..4a429b3a5f2f 100644 --- a/fs/afs/file.c +++ b/fs/afs/file.c @@ -196,21 +196,72 @@ int afs_release(struct inode *inode, struct file *file) return ret; } +/* + * Handle completion of a read operation. + */ +static void afs_file_read_done(struct afs_read *req) +{ + struct afs_vnode *vnode = req->vnode; + struct page *page; + pgoff_t index = req->pos >> PAGE_SHIFT; + pgoff_t last = index + req->nr_pages - 1; + + XA_STATE(xas, &vnode->vfs_inode.i_mapping->i_pages, index); + + if (iov_iter_count(req->iter) > 0) { + /* The read was short - clear the excess buffer. */ + _debug("afterclear %zx %zx %llx/%llx", + req->iter->iov_offset, + iov_iter_count(req->iter), + req->actual_len, req->len); + iov_iter_zero(iov_iter_count(req->iter), req->iter); + } + + rcu_read_lock(); + xas_for_each(&xas, page, last) { + page_endio(page, false, 0); + put_page(page); + } + rcu_read_unlock(); + + task_io_account_read(req->len); + req->cleanup = NULL; +} + +/* + * Dispose of our locks and refs on the pages if the read failed. + */ +static void afs_file_read_cleanup(struct afs_read *req) +{ + struct page *page; + pgoff_t index = req->pos >> PAGE_SHIFT; + pgoff_t last = index + req->nr_pages - 1; + + if (req->iter) { + XA_STATE(xas, &req->iter->mapping->i_pages, index); + + _enter("%lu,%u,%zu", index, req->nr_pages, iov_iter_count(req->iter)); + + rcu_read_lock(); + xas_for_each(&xas, page, last) { + BUG_ON(xa_is_value(page)); + BUG_ON(PageCompound(page)); + + page_endio(page, false, req->error); + put_page(page); + } + rcu_read_unlock(); + } +} + /* * Dispose of a ref to a read record. */ void afs_put_read(struct afs_read *req) { - int i; - if (refcount_dec_and_test(&req->usage)) { - if (req->pages) { - for (i = 0; i < req->nr_pages; i++) - if (req->pages[i]) - put_page(req->pages[i]); - if (req->pages != req->array) - kfree(req->pages); - } + if (req->cleanup) + req->cleanup(req); key_put(req->key); kfree(req); } @@ -228,6 +279,7 @@ static void afs_fetch_data_success(struct afs_operation *op) static void afs_fetch_data_put(struct afs_operation *op) { + op->fetch.req->error = op->error; afs_put_read(op->fetch.req); } @@ -267,12 +319,11 @@ int afs_fetch_data(struct afs_vnode *vnode, struct afs_read *req) /* * read page from file, directory or symlink, given a key to use */ -int afs_page_filler(void *data, struct page *page) +static int afs_page_filler(struct key *key, struct page *page) { struct inode *inode = page->mapping->host; struct afs_vnode *vnode = AFS_FS_I(inode); struct afs_read *req; - struct key *key = data; int ret; _enter("{%x},{%lu},{%lu}", key_serial(key), inode->i_ino, page->index); @@ -283,53 +334,52 @@ int afs_page_filler(void *data, struct page *page) if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) goto error; - req = kzalloc(struct_size(req, array, 1), GFP_KERNEL); + req = kzalloc(sizeof(struct afs_read), GFP_KERNEL); if (!req) goto enomem; - /* We request a full page. If the page is a partial one at the - * end of the file, the server will return a short read and the - * unmarshalling code will clear the unfilled space. - */ refcount_set(&req->usage, 1); - req->key = key_get(key); - req->pos = (loff_t)page->index << PAGE_SHIFT; - req->len = PAGE_SIZE; - req->nr_pages = 1; - req->pages = req->array; - req->pages[0] = page; + req->vnode = vnode; + req->key = key_get(key); + req->pos = (loff_t)page->index << PAGE_SHIFT; + req->len = PAGE_SIZE; + req->nr_pages = 1; + req->done = afs_file_read_done; + req->cleanup = afs_file_read_cleanup; + get_page(page); + iov_iter_mapping(&req->def_iter, READ, page->mapping, + req->pos, req->len); + req->iter = &req->def_iter; - /* read the contents of the file from the server into the - * page */ ret = afs_fetch_data(vnode, req); - afs_put_read(req); - - if (ret < 0) { - if (ret == -ENOENT) { - _debug("got NOENT from server" - " - marking file deleted and stale"); - set_bit(AFS_VNODE_DELETED, &vnode->flags); - ret = -ESTALE; - } - - if (ret == -EINTR || - ret == -ENOMEM || - ret == -ERESTARTSYS || - ret == -EAGAIN) - goto error; - goto io_error; - } - - SetPageUptodate(page); - unlock_page(page); + if (ret < 0) + goto fetch_error; + afs_put_read(req); _leave(" = 0"); return 0; -io_error: - SetPageError(page); - goto error; +fetch_error: + switch (ret) { + case -EINTR: + case -ENOMEM: + case -ERESTARTSYS: + case -EAGAIN: + afs_put_read(req); + goto error; + case -ENOENT: + _debug("got NOENT from server - marking file deleted and stale"); + set_bit(AFS_VNODE_DELETED, &vnode->flags); + ret = -ESTALE; + /* Fall through */ + default: + page_endio(page, false, ret); + afs_put_read(req); + _leave(" = %d", ret); + return ret; + } + enomem: ret = -ENOMEM; error: @@ -364,19 +414,6 @@ static int afs_readpage(struct file *file, struct page *page) return ret; } -/* - * Make pages available as they're filled. - */ -static void afs_readpages_page_done(struct afs_read *req) -{ - struct page *page = req->pages[req->index]; - - req->pages[req->index] = NULL; - SetPageUptodate(page); - unlock_page(page); - put_page(page); -} - /* * Read a contiguous set of pages. */ @@ -388,7 +425,7 @@ static int afs_readpages_one(struct file *file, struct address_space *mapping, struct list_head *p; struct page *first, *page; pgoff_t index; - int ret, n, i; + int ret, n; /* Count the number of contiguous pages at the front of the list. Note * that the list goes prev-wards rather than next-wards. @@ -404,21 +441,20 @@ static int afs_readpages_one(struct file *file, struct address_space *mapping, n++; } - req = kzalloc(struct_size(req, array, n), GFP_NOFS); + req = kzalloc(sizeof(struct afs_read), GFP_NOFS); if (!req) return -ENOMEM; refcount_set(&req->usage, 1); req->vnode = vnode; req->key = key_get(afs_file_key(file)); - req->page_done = afs_readpages_page_done; + req->done = afs_file_read_done; + req->cleanup = afs_file_read_cleanup; req->pos = first->index; req->pos <<= PAGE_SHIFT; - req->pages = req->array; - /* Transfer the pages to the request. We add them in until one fails - * to add to the LRU and then we stop (as that'll make a hole in the - * contiguous run. + /* Add pages to the LRU until it fails. We keep the pages ref'd and + * locked until the read is complete. * * Note that it's possible for the file size to change whilst we're * doing this, but we rely on the server returning less than we asked @@ -435,8 +471,7 @@ static int afs_readpages_one(struct file *file, struct address_space *mapping, break; } - req->pages[req->nr_pages++] = page; - req->len += PAGE_SIZE; + req->nr_pages++; } while (req->nr_pages < n); if (req->nr_pages == 0) { @@ -444,30 +479,25 @@ static int afs_readpages_one(struct file *file, struct address_space *mapping, return 0; } + req->len = req->nr_pages * PAGE_SIZE; + iov_iter_mapping(&req->def_iter, READ, file->f_mapping, + req->pos, req->len); + req->iter = &req->def_iter; + ret = afs_fetch_data(vnode, req); if (ret < 0) goto error; - task_io_account_read(PAGE_SIZE * req->nr_pages); afs_put_read(req); return 0; error: if (ret == -ENOENT) { - _debug("got NOENT from server" - " - marking file deleted and stale"); + _debug("got NOENT from server - marking file deleted and stale"); set_bit(AFS_VNODE_DELETED, &vnode->flags); ret = -ESTALE; } - for (i = 0; i < req->nr_pages; i++) { - page = req->pages[i]; - if (page) { - SetPageError(page); - unlock_page(page); - } - } - afs_put_read(req); return ret; } diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c index 3ed95f3e47be..677c7b31fb49 100644 --- a/fs/afs/fsclient.c +++ b/fs/afs/fsclient.c @@ -302,7 +302,6 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call) struct afs_vnode_param *vp = &op->file[0]; struct afs_read *req = op->fetch.req; const __be32 *bp; - unsigned int size; int ret; _enter("{%u,%zu,%zu/%llu}", @@ -312,8 +311,6 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call) switch (call->unmarshall) { case 0: req->actual_len = 0; - req->index = 0; - req->offset = req->pos & (PAGE_SIZE - 1); call->unmarshall++; if (call->operation_ID == FSFETCHDATA64) { afs_extract_to_tmp64(call); @@ -321,9 +318,13 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call) call->tmp_u = htonl(0); afs_extract_to_tmp(call); } + /* Fall through */ - /* extract the returned data length */ + /* Extract the returned data length into + * ->actual_len. This may indicate more or less data than was + * requested will be returned. + */ case 1: _debug("extract data length"); ret = afs_extract_data(call, true); @@ -332,45 +333,25 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call) req->actual_len = be64_to_cpu(call->tmp64); _debug("DATA length: %llu", req->actual_len); - req->remain = min(req->len, req->actual_len); - if (req->remain == 0) + + if (req->actual_len == 0) goto no_more_data; call->unmarshall++; - - begin_page: - ASSERTCMP(req->index, <, req->nr_pages); - if (req->remain > PAGE_SIZE - req->offset) - size = PAGE_SIZE - req->offset; - else - size = req->remain; - call->iov_len = size; - call->bvec[0].bv_len = size; - call->bvec[0].bv_offset = req->offset; - call->bvec[0].bv_page = req->pages[req->index]; - iov_iter_bvec(&call->def_iter, READ, call->bvec, 1, size); - ASSERTCMP(size, <=, PAGE_SIZE); + call->iter = req->iter; + call->iov_len = min(req->actual_len, req->len); /* Fall through */ /* extract the returned data */ case 2: _debug("extract data %zu/%llu", - iov_iter_count(call->iter), req->remain); + iov_iter_count(call->iter), req->actual_len); ret = afs_extract_data(call, true); if (ret < 0) return ret; - req->remain -= call->bvec[0].bv_len; - req->offset += call->bvec[0].bv_len; - ASSERTCMP(req->offset, <=, PAGE_SIZE); - if (req->offset == PAGE_SIZE) { - req->offset = 0; - req->index++; - if (req->remain > 0) - goto begin_page; - } - ASSERTCMP(req->remain, ==, 0); + call->iter = &call->def_iter; if (req->actual_len <= req->len) goto no_more_data; @@ -412,16 +393,8 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call) break; } - for (; req->index < req->nr_pages; req->index++) { - if (req->offset < PAGE_SIZE) - zero_user_segment(req->pages[req->index], - req->offset, PAGE_SIZE); - req->offset = 0; - } - - if (req->page_done) - for (req->index = 0; req->index < req->nr_pages; req->index++) - req->page_done(req); + if (req->done) + req->done(req); _leave(" = 0 [done]"); return 0; @@ -496,6 +469,8 @@ void afs_fs_fetch_data(struct afs_operation *op) if (!call) return afs_op_nomem(op); + req->call_debug_id = call->debug_id; + /* marshall the parameters */ bp = call->request; bp[0] = htonl(FSFETCHDATA); diff --git a/fs/afs/internal.h b/fs/afs/internal.h index bf26fd28ccbd..9d538df6aec8 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -31,6 +31,7 @@ struct pagevec; struct afs_call; +struct afs_vnode; /* * Partial file-locking emulation mode. (The problem being that AFS3 only @@ -203,18 +204,18 @@ struct afs_read { loff_t pos; /* Where to start reading */ loff_t len; /* How much we're asking for */ loff_t actual_len; /* How much we're actually getting */ - loff_t remain; /* Amount remaining */ loff_t file_size; /* File size returned by server */ struct key *key; /* The key to use to reissue the read */ + struct afs_vnode *vnode; /* The file being read into. */ afs_dataversion_t data_version; /* Version number returned by server */ refcount_t usage; - unsigned int index; /* Which page we're reading into */ + unsigned int call_debug_id; unsigned int nr_pages; - unsigned int offset; /* offset into current page */ - struct afs_vnode *vnode; - void (*page_done)(struct afs_read *); - struct page **pages; - struct page *array[]; + int error; + void (*done)(struct afs_read *); + void (*cleanup)(struct afs_read *); + struct iov_iter *iter; /* Iterator representing the buffer */ + struct iov_iter def_iter; /* Default iterator */ }; /* @@ -972,7 +973,6 @@ extern void afs_put_wb_key(struct afs_wb_key *); extern int afs_open(struct inode *, struct file *); extern int afs_release(struct inode *, struct file *); extern int afs_fetch_data(struct afs_vnode *, struct afs_read *); -extern int afs_page_filler(void *, struct page *); extern void afs_put_read(struct afs_read *); static inline struct afs_read *afs_get_read(struct afs_read *req) diff --git a/fs/afs/write.c b/fs/afs/write.c index 90dbe12353b6..484496a3d962 100644 --- a/fs/afs/write.c +++ b/fs/afs/write.c @@ -22,6 +22,16 @@ int afs_set_page_dirty(struct page *page) return __set_page_dirty_nobuffers(page); } +/* + * Handle completion of a read operation to fill a page. + */ +static void afs_fill_hole(struct afs_read *req) +{ + if (iov_iter_count(req->iter) > 0) + /* The read was short - clear the excess buffer. */ + iov_iter_zero(iov_iter_count(req->iter), req->iter); +} + /* * partly or wholly fill a page that's under preparation for writing */ @@ -45,18 +55,20 @@ static int afs_fill_page(struct file *file, return 0; } - req = kzalloc(struct_size(req, array, 1), GFP_KERNEL); + req = kzalloc(sizeof(struct afs_read), GFP_KERNEL); if (!req) return -ENOMEM; refcount_set(&req->usage, 1); - req->key = afs_file_key(file); - req->pos = pos; - req->len = len; - req->nr_pages = 1; - req->pages = req->array; - req->pages[0] = page; - get_page(page); + req->vnode = vnode; + req->done = afs_fill_hole; + req->key = afs_file_key(file); + req->pos = pos; + req->len = len; + req->nr_pages = 1; + req->iter = &req->def_iter; + iov_iter_mapping(&req->def_iter, READ, vnode->vfs_inode.i_mapping, + pos, len); ret = afs_fetch_data(vnode, req); afs_put_read(req); diff --git a/fs/afs/yfsclient.c b/fs/afs/yfsclient.c index a53bcea8740c..249d34e74913 100644 --- a/fs/afs/yfsclient.c +++ b/fs/afs/yfsclient.c @@ -360,7 +360,6 @@ static int yfs_deliver_fs_fetch_data64(struct afs_call *call) struct afs_vnode_param *vp = &op->file[0]; struct afs_read *req = op->fetch.req; const __be32 *bp; - unsigned int size; int ret; _enter("{%u,%zu, %zu/%llu}", @@ -370,13 +369,15 @@ static int yfs_deliver_fs_fetch_data64(struct afs_call *call) switch (call->unmarshall) { case 0: req->actual_len = 0; - req->index = 0; - req->offset = req->pos & (PAGE_SIZE - 1); afs_extract_to_tmp64(call); call->unmarshall++; + /* Fall through */ - /* extract the returned data length */ + /* Extract the returned data length into ->actual_len. This + * may indicate more or less data than was requested will be + * returned. + */ case 1: _debug("extract data length"); ret = afs_extract_data(call, true); @@ -385,45 +386,25 @@ static int yfs_deliver_fs_fetch_data64(struct afs_call *call) req->actual_len = be64_to_cpu(call->tmp64); _debug("DATA length: %llu", req->actual_len); - req->remain = min(req->len, req->actual_len); - if (req->remain == 0) + + if (req->actual_len == 0) goto no_more_data; call->unmarshall++; - - begin_page: - ASSERTCMP(req->index, <, req->nr_pages); - if (req->remain > PAGE_SIZE - req->offset) - size = PAGE_SIZE - req->offset; - else - size = req->remain; - call->iov_len = size; - call->bvec[0].bv_len = size; - call->bvec[0].bv_offset = req->offset; - call->bvec[0].bv_page = req->pages[req->index]; - iov_iter_bvec(&call->def_iter, READ, call->bvec, 1, size); - ASSERTCMP(size, <=, PAGE_SIZE); + call->iter = req->iter; + call->iov_len = min(req->actual_len, req->len); /* Fall through */ /* extract the returned data */ case 2: _debug("extract data %zu/%llu", - iov_iter_count(call->iter), req->remain); + iov_iter_count(call->iter), req->actual_len); ret = afs_extract_data(call, true); if (ret < 0) return ret; - req->remain -= call->bvec[0].bv_len; - req->offset += call->bvec[0].bv_len; - ASSERTCMP(req->offset, <=, PAGE_SIZE); - if (req->offset == PAGE_SIZE) { - req->offset = 0; - req->index++; - if (req->remain > 0) - goto begin_page; - } - ASSERTCMP(req->remain, ==, 0); + call->iter = &call->def_iter; if (req->actual_len <= req->len) goto no_more_data; @@ -469,16 +450,8 @@ static int yfs_deliver_fs_fetch_data64(struct afs_call *call) break; } - for (; req->index < req->nr_pages; req->index++) { - if (req->offset < PAGE_SIZE) - zero_user_segment(req->pages[req->index], - req->offset, PAGE_SIZE); - req->offset = 0; - } - - if (req->page_done) - for (req->index = 0; req->index < req->nr_pages; req->index++) - req->page_done(req); + if (req->done) + req->done(req); _leave(" = 0 [done]"); return 0; @@ -518,6 +491,8 @@ void yfs_fs_fetch_data(struct afs_operation *op) if (!call) return afs_op_nomem(op); + req->call_debug_id = call->debug_id; + /* marshall the parameters */ bp = call->request; bp = xdr_encode_u32(bp, YFSFETCHDATA64); From patchwork Mon Jul 13 16:38:06 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Howells X-Patchwork-Id: 11660665 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 3118E13B4 for ; Mon, 13 Jul 2020 16:38:36 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 0AC3A2067D for ; Mon, 13 Jul 2020 16:38:36 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="ff5eX23w" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730404AbgGMQi1 (ORCPT ); Mon, 13 Jul 2020 12:38:27 -0400 Received: from us-smtp-delivery-1.mimecast.com ([205.139.110.120]:43561 "EHLO us-smtp-1.mimecast.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1730351AbgGMQi0 (ORCPT ); Mon, 13 Jul 2020 12:38:26 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1594658302; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=7Lbe4L2FHTnJtid2pwFdUM8HAEiEFoxMYSAeQyB0jmE=; b=ff5eX23wQBgoSOoC3yQHB0dRrzdtd1QTYQTOJmAQ4Bbg14cg4eo86+U0dHslNJN0PMg7Bd 4PjfKkLZBGWySYaAYfqtCXaa1y5Q+Mt7QskD4wcdtKtA4fk7ZBKouBh5YPu7xteEtNLD4U 2Q+254/xqXx+NhWSIbTxsz1La6FXe/U= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-146-x-XPtuJVNAeTJvU7xjttzA-1; Mon, 13 Jul 2020 12:38:16 -0400 X-MC-Unique: x-XPtuJVNAeTJvU7xjttzA-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 628EC1902EA7; Mon, 13 Jul 2020 16:38:12 +0000 (UTC) Received: from warthog.procyon.org.uk (ovpn-112-113.rdu2.redhat.com [10.10.112.113]) by smtp.corp.redhat.com (Postfix) with ESMTP id CA5757621B; Mon, 13 Jul 2020 16:38:06 +0000 (UTC) Organization: Red Hat UK Ltd. Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SI4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 3798903 Subject: [PATCH 06/13] afs: Use ITER_MAPPING for writing From: David Howells To: Trond Myklebust , Anna Schumaker , Steve French , Alexander Viro , Matthew Wilcox Cc: Jeff Layton , Dave Wysochanski , dhowells@redhat.com, linux-cachefs@redhat.com, linux-afs@lists.infradead.org, linux-nfs@vger.kernel.org, linux-cifs@vger.kernel.org, ceph-devel@vger.kernel.org, v9fs-developer@lists.sourceforge.net, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Date: Mon, 13 Jul 2020 17:38:06 +0100 Message-ID: <159465828607.1377938.6903132788463419368.stgit@warthog.procyon.org.uk> In-Reply-To: <159465821598.1377938.2046362270225008168.stgit@warthog.procyon.org.uk> References: <159465821598.1377938.2046362270225008168.stgit@warthog.procyon.org.uk> User-Agent: StGit/0.22 MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 Sender: linux-nfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org Use a single ITER_MAPPING iterator to describe the portion of a file to be transmitted to the server rather than generating a series of small ITER_BVEC iterators on the fly. This will make it easier to implement AIO in afs. In theory we could maybe use one giant ITER_BVEC, but that means potentially allocating a huge array of bio_vec structs (max 256 per page) when in fact the pagecache already has a structure listing all the relevant pages (radix_tree/xarray) that can be walked over. Signed-off-by: David Howells --- fs/afs/fsclient.c | 50 +++++++++------------ fs/afs/internal.h | 13 +++--- fs/afs/rxrpc.c | 103 ++++++-------------------------------------- fs/afs/write.c | 102 +++++++++++++++++++++++++------------------- fs/afs/yfsclient.c | 25 +++-------- include/trace/events/afs.h | 51 ++++++++-------------- 6 files changed, 126 insertions(+), 218 deletions(-) diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c index 677c7b31fb49..c0c91079e76b 100644 --- a/fs/afs/fsclient.c +++ b/fs/afs/fsclient.c @@ -1056,8 +1056,7 @@ static const struct afs_call_type afs_RXFSStoreData64 = { /* * store a set of pages to a very large file */ -static void afs_fs_store_data64(struct afs_operation *op, - loff_t pos, loff_t size, loff_t i_size) +static void afs_fs_store_data64(struct afs_operation *op) { struct afs_vnode_param *vp = &op->file[0]; struct afs_call *call; @@ -1072,7 +1071,7 @@ static void afs_fs_store_data64(struct afs_operation *op, if (!call) return afs_op_nomem(op); - call->send_pages = true; + call->write_iter = op->store.write_iter; /* marshall the parameters */ bp = call->request; @@ -1088,47 +1087,38 @@ static void afs_fs_store_data64(struct afs_operation *op, *bp++ = 0; /* unix mode */ *bp++ = 0; /* segment size */ - *bp++ = htonl(upper_32_bits(pos)); - *bp++ = htonl(lower_32_bits(pos)); - *bp++ = htonl(upper_32_bits(size)); - *bp++ = htonl(lower_32_bits(size)); - *bp++ = htonl(upper_32_bits(i_size)); - *bp++ = htonl(lower_32_bits(i_size)); + *bp++ = htonl(upper_32_bits(op->store.pos)); + *bp++ = htonl(lower_32_bits(op->store.pos)); + *bp++ = htonl(upper_32_bits(op->store.size)); + *bp++ = htonl(lower_32_bits(op->store.size)); + *bp++ = htonl(upper_32_bits(op->store.i_size)); + *bp++ = htonl(lower_32_bits(op->store.i_size)); trace_afs_make_fs_call(call, &vp->fid); afs_make_op_call(op, call, GFP_NOFS); } /* - * store a set of pages + * Write data to a file on the server. */ void afs_fs_store_data(struct afs_operation *op) { struct afs_vnode_param *vp = &op->file[0]; struct afs_call *call; - loff_t size, pos, i_size; __be32 *bp; _enter(",%x,{%llx:%llu},,", key_serial(op->key), vp->fid.vid, vp->fid.vnode); - size = (loff_t)op->store.last_to - (loff_t)op->store.first_offset; - if (op->store.first != op->store.last) - size += (loff_t)(op->store.last - op->store.first) << PAGE_SHIFT; - pos = (loff_t)op->store.first << PAGE_SHIFT; - pos += op->store.first_offset; - - i_size = i_size_read(&vp->vnode->vfs_inode); - if (pos + size > i_size) - i_size = size + pos; - _debug("size %llx, at %llx, i_size %llx", - (unsigned long long) size, (unsigned long long) pos, - (unsigned long long) i_size); + (unsigned long long)op->store.size, + (unsigned long long)op->store.pos, + (unsigned long long)op->store.i_size); - if (upper_32_bits(pos) || upper_32_bits(i_size) || upper_32_bits(size) || - upper_32_bits(pos + size)) - return afs_fs_store_data64(op, pos, size, i_size); + if (upper_32_bits(op->store.pos) || + upper_32_bits(op->store.size) || + upper_32_bits(op->store.i_size)) + return afs_fs_store_data64(op); call = afs_alloc_flat_call(op->net, &afs_RXFSStoreData, (4 + 6 + 3) * 4, @@ -1136,7 +1126,7 @@ void afs_fs_store_data(struct afs_operation *op) if (!call) return afs_op_nomem(op); - call->send_pages = true; + call->write_iter = op->store.write_iter; /* marshall the parameters */ bp = call->request; @@ -1152,9 +1142,9 @@ void afs_fs_store_data(struct afs_operation *op) *bp++ = 0; /* unix mode */ *bp++ = 0; /* segment size */ - *bp++ = htonl(lower_32_bits(pos)); - *bp++ = htonl(lower_32_bits(size)); - *bp++ = htonl(lower_32_bits(i_size)); + *bp++ = htonl(lower_32_bits(op->store.pos)); + *bp++ = htonl(lower_32_bits(op->store.size)); + *bp++ = htonl(lower_32_bits(op->store.i_size)); trace_afs_make_fs_call(call, &vp->fid); afs_make_op_call(op, call, GFP_NOFS); diff --git a/fs/afs/internal.h b/fs/afs/internal.h index 9d538df6aec8..3d0aa1e46539 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -107,6 +107,7 @@ struct afs_call { void *request; /* request data (first part) */ size_t iov_len; /* Size of *iter to be used */ struct iov_iter def_iter; /* Default buffer/data iterator */ + struct iov_iter *write_iter; /* Iterator defining write to be made */ struct iov_iter *iter; /* Iterator currently in use */ union { /* Convenience for ->def_iter */ struct kvec kvec[1]; @@ -133,7 +134,6 @@ struct afs_call { unsigned char unmarshall; /* unmarshalling phase */ unsigned char addr_ix; /* Address in ->alist */ bool drop_ref; /* T if need to drop ref for incoming call */ - bool send_pages; /* T if data from mapping should be sent */ bool need_attention; /* T if RxRPC poked us */ bool async; /* T if asynchronous */ bool upgrade; /* T to request service upgrade */ @@ -805,11 +805,12 @@ struct afs_operation { afs_lock_type_t type; } lock; struct { - struct address_space *mapping; /* Pages being written from */ - pgoff_t first; /* first page in mapping to deal with */ - pgoff_t last; /* last page in mapping to deal with */ - unsigned first_offset; /* offset into mapping[first] */ - unsigned last_to; /* amount of mapping[last] */ + struct iov_iter *write_iter; + loff_t pos; + loff_t size; + loff_t i_size; + pgoff_t first; /* first page in mapping to deal with */ + pgoff_t last; /* last page in mapping to deal with */ } store; struct { struct iattr *attr; diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c index 48361bbd4859..6bbf6803e83e 100644 --- a/fs/afs/rxrpc.c +++ b/fs/afs/rxrpc.c @@ -271,40 +271,6 @@ void afs_flat_call_destructor(struct afs_call *call) call->buffer = NULL; } -#define AFS_BVEC_MAX 8 - -/* - * Load the given bvec with the next few pages. - */ -static void afs_load_bvec(struct afs_call *call, struct msghdr *msg, - struct bio_vec *bv, pgoff_t first, pgoff_t last, - unsigned offset) -{ - struct afs_operation *op = call->op; - struct page *pages[AFS_BVEC_MAX]; - unsigned int nr, n, i, to, bytes = 0; - - nr = min_t(pgoff_t, last - first + 1, AFS_BVEC_MAX); - n = find_get_pages_contig(op->store.mapping, first, nr, pages); - ASSERTCMP(n, ==, nr); - - msg->msg_flags |= MSG_MORE; - for (i = 0; i < nr; i++) { - to = PAGE_SIZE; - if (first + i >= last) { - to = op->store.last_to; - msg->msg_flags &= ~MSG_MORE; - } - bv[i].bv_page = pages[i]; - bv[i].bv_len = to - offset; - bv[i].bv_offset = offset; - bytes += to - offset; - offset = 0; - } - - iov_iter_bvec(&msg->msg_iter, WRITE, bv, nr, bytes); -} - /* * Advance the AFS call state when the RxRPC call ends the transmit phase. */ @@ -317,42 +283,6 @@ static void afs_notify_end_request_tx(struct sock *sock, afs_set_call_state(call, AFS_CALL_CL_REQUESTING, AFS_CALL_CL_AWAIT_REPLY); } -/* - * attach the data from a bunch of pages on an inode to a call - */ -static int afs_send_pages(struct afs_call *call, struct msghdr *msg) -{ - struct afs_operation *op = call->op; - struct bio_vec bv[AFS_BVEC_MAX]; - unsigned int bytes, nr, loop, offset; - pgoff_t first = op->store.first, last = op->store.last; - int ret; - - offset = op->store.first_offset; - op->store.first_offset = 0; - - do { - afs_load_bvec(call, msg, bv, first, last, offset); - trace_afs_send_pages(call, msg, first, last, offset); - - offset = 0; - bytes = msg->msg_iter.count; - nr = msg->msg_iter.nr_segs; - - ret = rxrpc_kernel_send_data(op->net->socket, call->rxcall, msg, - bytes, afs_notify_end_request_tx); - for (loop = 0; loop < nr; loop++) - put_page(bv[loop].bv_page); - if (ret < 0) - break; - - first += nr; - } while (first <= last); - - trace_afs_sent_pages(call, op->store.first, last, first, ret); - return ret; -} - /* * Initiate a call and synchronously queue up the parameters for dispatch. Any * error is stored into the call struct, which the caller must check for. @@ -384,21 +314,8 @@ void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp) * after the initial fixed part. */ tx_total_len = call->request_size; - if (call->send_pages) { - struct afs_operation *op = call->op; - - if (op->store.last == op->store.first) { - tx_total_len += op->store.last_to - op->store.first_offset; - } else { - /* It looks mathematically like you should be able to - * combine the following lines with the ones above, but - * unsigned arithmetic is fun when it wraps... - */ - tx_total_len += PAGE_SIZE - op->store.first_offset; - tx_total_len += op->store.last_to; - tx_total_len += (op->store.last - op->store.first - 1) * PAGE_SIZE; - } - } + if (call->write_iter) + tx_total_len += iov_iter_count(call->write_iter); /* If the call is going to be asynchronous, we need an extra ref for * the call to hold itself so the caller need not hang on to its ref. @@ -440,7 +357,7 @@ void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp) iov_iter_kvec(&msg.msg_iter, WRITE, iov, 1, call->request_size); msg.msg_control = NULL; msg.msg_controllen = 0; - msg.msg_flags = MSG_WAITALL | (call->send_pages ? MSG_MORE : 0); + msg.msg_flags = MSG_WAITALL | (call->write_iter ? MSG_MORE : 0); ret = rxrpc_kernel_send_data(call->net->socket, rxcall, &msg, call->request_size, @@ -448,8 +365,18 @@ void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp) if (ret < 0) goto error_do_abort; - if (call->send_pages) { - ret = afs_send_pages(call, &msg); + if (call->write_iter) { + msg.msg_iter = *call->write_iter; + msg.msg_flags &= ~MSG_MORE; + trace_afs_send_data(call, &msg); + + ret = rxrpc_kernel_send_data(call->net->socket, + call->rxcall, &msg, + iov_iter_count(&msg.msg_iter), + afs_notify_end_request_tx); + *call->write_iter = msg.msg_iter; + + trace_afs_sent_data(call, &msg, ret); if (ret < 0) goto error_do_abort; } diff --git a/fs/afs/write.c b/fs/afs/write.c index 484496a3d962..37c968b9c89b 100644 --- a/fs/afs/write.c +++ b/fs/afs/write.c @@ -323,38 +323,30 @@ static void afs_redirty_pages(struct writeback_control *wbc, /* * completion of write to server */ -static void afs_pages_written_back(struct afs_vnode *vnode, - pgoff_t first, pgoff_t last) +static void afs_pages_written_back(struct afs_vnode *vnode, pgoff_t start, pgoff_t last) { - struct pagevec pv; + struct address_space *mapping = vnode->vfs_inode.i_mapping; + struct page *page; unsigned long priv; - unsigned count, loop; + + XA_STATE(xas, &mapping->i_pages, start); _enter("{%llx:%llu},{%lx-%lx}", - vnode->fid.vid, vnode->fid.vnode, first, last); + vnode->fid.vid, vnode->fid.vnode, start, last); - pagevec_init(&pv); + rcu_read_lock(); - do { - _debug("done %lx-%lx", first, last); + xas_for_each(&xas, page, last) { + ASSERT(PageWriteback(page)); - count = last - first + 1; - if (count > PAGEVEC_SIZE) - count = PAGEVEC_SIZE; - pv.nr = find_get_pages_contig(vnode->vfs_inode.i_mapping, - first, count, pv.pages); - ASSERTCMP(pv.nr, ==, count); + priv = page_private(page); + trace_afs_page_dirty(vnode, tracepoint_string("clear"), + page->index, priv); + set_page_private(page, 0); + page_endio(page, true, 0); + } - for (loop = 0; loop < count; loop++) { - priv = page_private(pv.pages[loop]); - trace_afs_page_dirty(vnode, tracepoint_string("clear"), - pv.pages[loop]->index, priv); - set_page_private(pv.pages[loop], 0); - end_page_writeback(pv.pages[loop]); - } - first += count; - __pagevec_release(&pv); - } while (first <= last); + rcu_read_unlock(); afs_prune_wb_keys(vnode); _leave(""); @@ -410,9 +402,7 @@ static void afs_store_data_success(struct afs_operation *op) if (op->error == 0) { afs_pages_written_back(vnode, op->store.first, op->store.last); afs_stat_v(vnode, n_stores); - atomic_long_add((op->store.last * PAGE_SIZE + op->store.last_to) - - (op->store.first * PAGE_SIZE + op->store.first_offset), - &afs_v2net(vnode)->n_store_bytes); + atomic_long_add(op->store.size, &afs_v2net(vnode)->n_store_bytes); } } @@ -425,21 +415,20 @@ static const struct afs_operation_ops afs_store_data_operation = { /* * write to a file */ -static int afs_store_data(struct address_space *mapping, - pgoff_t first, pgoff_t last, - unsigned offset, unsigned to) +static int afs_store_data(struct afs_vnode *vnode, struct iov_iter *iter, + loff_t pos, pgoff_t first, pgoff_t last) { - struct afs_vnode *vnode = AFS_FS_I(mapping->host); struct afs_operation *op; struct afs_wb_key *wbk = NULL; - int ret; + loff_t size = iov_iter_count(iter), i_size; + int ret = -ENOKEY; - _enter("%s{%llx:%llu.%u},%lx,%lx,%x,%x", + _enter("%s{%llx:%llu.%u},%llx,%llx", vnode->volume->name, vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique, - first, last, offset, to); + size, pos); ret = afs_get_writeback_key(vnode, &wbk); if (ret) { @@ -453,13 +442,16 @@ static int afs_store_data(struct address_space *mapping, return -ENOMEM; } + i_size = i_size_read(&vnode->vfs_inode); + afs_op_set_vnode(op, 0, vnode); op->file[0].dv_delta = 1; - op->store.mapping = mapping; + op->store.write_iter = iter; + op->store.pos = pos; op->store.first = first; op->store.last = last; - op->store.first_offset = offset; - op->store.last_to = to; + op->store.size = size; + op->store.i_size = max(pos + size, i_size); op->mtime = vnode->vfs_inode.i_mtime; op->flags |= AFS_OPERATION_UNINTR; op->ops = &afs_store_data_operation; @@ -501,11 +493,12 @@ static int afs_write_back_from_locked_page(struct address_space *mapping, pgoff_t final_page) { struct afs_vnode *vnode = AFS_FS_I(mapping->host); + struct iov_iter iter; struct page *pages[8], *page; unsigned long count, priv; unsigned n, offset, to, f, t; pgoff_t start, first, last; - loff_t i_size, end; + loff_t i_size, pos, end; int loop, ret; _enter(",%lx", primary_page->index); @@ -605,15 +598,28 @@ static int afs_write_back_from_locked_page(struct address_space *mapping, first = primary_page->index; last = first + count - 1; + _debug("write back %lx[%u..] to %lx[..%u]", first, offset, last, to); - end = (loff_t)last * PAGE_SIZE + to; - i_size = i_size_read(&vnode->vfs_inode); + pos = first; + pos <<= PAGE_SHIFT; + pos += offset; + end = last; + end <<= PAGE_SHIFT; + end += to; - _debug("write back %lx[%u..] to %lx[..%u]", first, offset, last, to); + /* Trim the actual write down to the EOF */ + i_size = i_size_read(&vnode->vfs_inode); if (end > i_size) - to = i_size & ~PAGE_MASK; + end = i_size; + + if (pos < i_size) { + iov_iter_mapping(&iter, WRITE, mapping, pos, end - pos); + ret = afs_store_data(vnode, &iter, pos, first, last); + } else { + /* The dirty region was entirely beyond the EOF. */ + ret = 0; + } - ret = afs_store_data(mapping, first, last, offset, to); switch (ret) { case 0: ret = count; @@ -902,6 +908,8 @@ int afs_launder_page(struct page *page) { struct address_space *mapping = page->mapping; struct afs_vnode *vnode = AFS_FS_I(mapping->host); + struct iov_iter iter; + struct bio_vec bv[1]; unsigned long priv; unsigned int f, t; int ret = 0; @@ -917,9 +925,15 @@ int afs_launder_page(struct page *page) t = priv >> AFS_PRIV_SHIFT; } + bv[0].bv_page = page; + bv[0].bv_offset = f; + bv[0].bv_len = t - f; + iov_iter_bvec(&iter, WRITE, bv, 1, bv[0].bv_len); + trace_afs_page_dirty(vnode, tracepoint_string("launder"), page->index, priv); - ret = afs_store_data(mapping, page->index, page->index, t, f); + ret = afs_store_data(vnode, &iter, (loff_t)page->index << PAGE_SHIFT, + page->index, page->index); } trace_afs_page_dirty(vnode, tracepoint_string("laundered"), diff --git a/fs/afs/yfsclient.c b/fs/afs/yfsclient.c index 249d34e74913..ac3541773e7c 100644 --- a/fs/afs/yfsclient.c +++ b/fs/afs/yfsclient.c @@ -1079,25 +1079,15 @@ void yfs_fs_store_data(struct afs_operation *op) { struct afs_vnode_param *vp = &op->file[0]; struct afs_call *call; - loff_t size, pos, i_size; __be32 *bp; _enter(",%x,{%llx:%llu},,", key_serial(op->key), vp->fid.vid, vp->fid.vnode); - size = (loff_t)op->store.last_to - (loff_t)op->store.first_offset; - if (op->store.first != op->store.last) - size += (loff_t)(op->store.last - op->store.first) << PAGE_SHIFT; - pos = (loff_t)op->store.first << PAGE_SHIFT; - pos += op->store.first_offset; - - i_size = i_size_read(&vp->vnode->vfs_inode); - if (pos + size > i_size) - i_size = size + pos; - _debug("size %llx, at %llx, i_size %llx", - (unsigned long long)size, (unsigned long long)pos, - (unsigned long long)i_size); + (unsigned long long)op->store.size, + (unsigned long long)op->store.pos, + (unsigned long long)op->store.i_size); call = afs_alloc_flat_call(op->net, &yfs_RXYFSStoreData64, sizeof(__be32) + @@ -1110,8 +1100,7 @@ void yfs_fs_store_data(struct afs_operation *op) if (!call) return afs_op_nomem(op); - call->key = op->key; - call->send_pages = true; + call->write_iter = op->store.write_iter; /* marshall the parameters */ bp = call->request; @@ -1119,9 +1108,9 @@ void yfs_fs_store_data(struct afs_operation *op) bp = xdr_encode_u32(bp, 0); /* RPC flags */ bp = xdr_encode_YFSFid(bp, &vp->fid); bp = xdr_encode_YFSStoreStatus_mtime(bp, &op->mtime); - bp = xdr_encode_u64(bp, pos); - bp = xdr_encode_u64(bp, size); - bp = xdr_encode_u64(bp, i_size); + bp = xdr_encode_u64(bp, op->store.pos); + bp = xdr_encode_u64(bp, op->store.size); + bp = xdr_encode_u64(bp, op->store.i_size); yfs_check_req(call, bp); trace_afs_make_fs_call(call, &vp->fid); diff --git a/include/trace/events/afs.h b/include/trace/events/afs.h index 5f0c1cf1ea13..012dfbabfbbf 100644 --- a/include/trace/events/afs.h +++ b/include/trace/events/afs.h @@ -802,65 +802,52 @@ TRACE_EVENT(afs_call_done, __entry->rx_call) ); -TRACE_EVENT(afs_send_pages, - TP_PROTO(struct afs_call *call, struct msghdr *msg, - pgoff_t first, pgoff_t last, unsigned int offset), +TRACE_EVENT(afs_send_data, + TP_PROTO(struct afs_call *call, struct msghdr *msg), - TP_ARGS(call, msg, first, last, offset), + TP_ARGS(call, msg), TP_STRUCT__entry( __field(unsigned int, call ) - __field(pgoff_t, first ) - __field(pgoff_t, last ) - __field(unsigned int, nr ) - __field(unsigned int, bytes ) - __field(unsigned int, offset ) __field(unsigned int, flags ) + __field(loff_t, offset ) + __field(loff_t, count ) ), TP_fast_assign( __entry->call = call->debug_id; - __entry->first = first; - __entry->last = last; - __entry->nr = msg->msg_iter.nr_segs; - __entry->bytes = msg->msg_iter.count; - __entry->offset = offset; __entry->flags = msg->msg_flags; + __entry->offset = msg->msg_iter.iov_offset; + __entry->count = iov_iter_count(&msg->msg_iter); ), - TP_printk(" c=%08x %lx-%lx-%lx b=%x o=%x f=%x", - __entry->call, - __entry->first, __entry->first + __entry->nr - 1, __entry->last, - __entry->bytes, __entry->offset, + TP_printk(" c=%08x o=%llx c=%llx f=%x", + __entry->call, __entry->offset, __entry->count, __entry->flags) ); -TRACE_EVENT(afs_sent_pages, - TP_PROTO(struct afs_call *call, pgoff_t first, pgoff_t last, - pgoff_t cursor, int ret), +TRACE_EVENT(afs_sent_data, + TP_PROTO(struct afs_call *call, struct msghdr *msg, int ret), - TP_ARGS(call, first, last, cursor, ret), + TP_ARGS(call, msg, ret), TP_STRUCT__entry( __field(unsigned int, call ) - __field(pgoff_t, first ) - __field(pgoff_t, last ) - __field(pgoff_t, cursor ) __field(int, ret ) + __field(loff_t, offset ) + __field(loff_t, count ) ), TP_fast_assign( __entry->call = call->debug_id; - __entry->first = first; - __entry->last = last; - __entry->cursor = cursor; __entry->ret = ret; + __entry->offset = msg->msg_iter.iov_offset; + __entry->count = iov_iter_count(&msg->msg_iter); ), - TP_printk(" c=%08x %lx-%lx c=%lx r=%d", - __entry->call, - __entry->first, __entry->last, - __entry->cursor, __entry->ret) + TP_printk(" c=%08x o=%llx c=%llx r=%d", + __entry->call, __entry->offset, __entry->count, + __entry->ret) ); TRACE_EVENT(afs_dir_check_failed, From patchwork Mon Jul 13 16:38:17 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Howells X-Patchwork-Id: 11660671 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 9A38113B4 for ; Mon, 13 Jul 2020 16:38:41 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 75E4A20773 for ; Mon, 13 Jul 2020 16:38:41 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="NKeutwIz" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729784AbgGMQik (ORCPT ); Mon, 13 Jul 2020 12:38:40 -0400 Received: from us-smtp-delivery-1.mimecast.com ([205.139.110.120]:42974 "EHLO us-smtp-1.mimecast.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1730591AbgGMQif (ORCPT ); Mon, 13 Jul 2020 12:38:35 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1594658312; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=aqsuThQyrz5PWdn5FrEmtBoz4GkNq4lYhgOSsa46qsI=; b=NKeutwIzcS/T2TQ/9X7BSiGNjjftN0Bn3T28b1QFwgGRGFLR7yI4hDuP3qMwFp8oYsolEf ITj2wmxZxK8/nL8yq7wPffrwvj2LUq/Qb6/Bzzs0VM5DBcsoNzNDNiOlszfmcFUkE7G0mS TJj9gr9oi3eE+0g5ino41fJJndTsm+8= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-74-odU2Z691OkOWWnnbTqZgyw-1; Mon, 13 Jul 2020 12:38:29 -0400 X-MC-Unique: odU2Z691OkOWWnnbTqZgyw-1 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id AB46280183C; Mon, 13 Jul 2020 16:38:27 +0000 (UTC) Received: from warthog.procyon.org.uk (ovpn-112-113.rdu2.redhat.com [10.10.112.113]) by smtp.corp.redhat.com (Postfix) with ESMTP id 637785BAD5; Mon, 13 Jul 2020 16:38:18 +0000 (UTC) Organization: Red Hat UK Ltd. Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SI4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 3798903 Subject: [PATCH 07/13] afs: Interpose struct fscache_io_request into struct afs_read From: David Howells To: Trond Myklebust , Anna Schumaker , Steve French , Alexander Viro , Matthew Wilcox Cc: Jeff Layton , Dave Wysochanski , dhowells@redhat.com, linux-cachefs@redhat.com, linux-afs@lists.infradead.org, linux-nfs@vger.kernel.org, linux-cifs@vger.kernel.org, ceph-devel@vger.kernel.org, v9fs-developer@lists.sourceforge.net, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Date: Mon, 13 Jul 2020 17:38:17 +0100 Message-ID: <159465829760.1377938.2449766049160139188.stgit@warthog.procyon.org.uk> In-Reply-To: <159465821598.1377938.2046362270225008168.stgit@warthog.procyon.org.uk> References: <159465821598.1377938.2046362270225008168.stgit@warthog.procyon.org.uk> User-Agent: StGit/0.22 MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.15 Sender: linux-nfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org Embed an fscache_io_request struct into struct afs_read and remove some of the redundant members from the latter. Change all references to those removed members to use the fscache ones instead. Signed-off-by: David Howells --- fs/afs/dir.c | 38 ++++++++++++++++++++++++-------------- fs/afs/file.c | 48 +++++++++++++++++++++++++----------------------- fs/afs/fsclient.c | 28 ++++++++++++++-------------- fs/afs/internal.h | 12 ++++-------- fs/afs/write.c | 18 ++++++++++-------- fs/afs/yfsclient.c | 18 +++++++++--------- 6 files changed, 86 insertions(+), 76 deletions(-) diff --git a/fs/afs/dir.c b/fs/afs/dir.c index 56991bb01f62..9d47df15c790 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c @@ -108,13 +108,14 @@ struct afs_lookup_cookie { */ static void afs_dir_read_cleanup(struct afs_read *req) { - struct address_space *mapping = req->iter->mapping; + struct afs_vnode *vnode = req->vnode; + struct address_space *mapping = vnode->vfs_inode.i_mapping; struct page *page; - pgoff_t last = req->nr_pages - 1; + pgoff_t last = req->cache.nr_pages - 1; XA_STATE(xas, &mapping->i_pages, 0); - if (unlikely(!req->nr_pages)) + if (unlikely(!req->cache.nr_pages)) return; rcu_read_lock(); @@ -131,6 +132,13 @@ static void afs_dir_read_cleanup(struct afs_read *req) rcu_read_unlock(); } +/* + * Do nothing upon completion of the request. + */ +static void afs_dir_read_done(struct fscache_io_request *fsreq) +{ +} + /* * check that a directory page is valid */ @@ -194,15 +202,15 @@ static void afs_dir_dump(struct afs_vnode *dvnode, struct afs_read *req) struct address_space *mapping = dvnode->vfs_inode.i_mapping; struct page *page; unsigned int i, qty = PAGE_SIZE / sizeof(union afs_xdr_dir_block); - pgoff_t last = req->nr_pages - 1; + pgoff_t last = req->cache.nr_pages - 1; XA_STATE(xas, &mapping->i_pages, 0); pr_warn("DIR %llx:%llx f=%llx l=%llx al=%llx\n", dvnode->fid.vid, dvnode->fid.vnode, - req->file_size, req->len, req->actual_len); + req->file_size, req->cache.len, req->actual_len); pr_warn("DIR %llx %x %zx %zx\n", - req->pos, req->nr_pages, + req->cache.pos, req->cache.nr_pages, req->iter->iov_offset, iov_iter_count(req->iter)); xas_for_each(&xas, page, last) { @@ -229,12 +237,12 @@ static int afs_dir_check(struct afs_vnode *dvnode, struct afs_read *req) { struct address_space *mapping = dvnode->vfs_inode.i_mapping; struct page *page; - pgoff_t last = req->nr_pages - 1; + pgoff_t last = req->cache.nr_pages - 1; int ret = 0; XA_STATE(xas, &mapping->i_pages, 0); - if (unlikely(!req->nr_pages)) + if (unlikely(!req->cache.nr_pages)) return 0; rcu_read_lock(); @@ -293,7 +301,9 @@ static struct afs_read *afs_read_dir(struct afs_vnode *dvnode, struct key *key) refcount_set(&req->usage, 1); req->key = key_get(key); + req->vnode = dvnode; req->cleanup = afs_dir_read_cleanup; + req->cache.io_done = afs_dir_read_done; expand: i_size = i_size_read(&dvnode->vfs_inode); @@ -312,7 +322,7 @@ static struct afs_read *afs_read_dir(struct afs_vnode *dvnode, struct key *key) nr_pages = (i_size + PAGE_SIZE - 1) / PAGE_SIZE; req->actual_len = i_size; /* May change */ - req->len = nr_pages * PAGE_SIZE; /* We can ask for more than there is */ + req->cache.len = nr_pages * PAGE_SIZE; /* We can ask for more than there is */ req->data_version = dvnode->status.data_version; /* May change */ iov_iter_mapping(&req->def_iter, READ, dvnode->vfs_inode.i_mapping, 0, i_size); @@ -322,7 +332,7 @@ static struct afs_read *afs_read_dir(struct afs_vnode *dvnode, struct key *key) * been at work and pin all the pages. If there are any gaps, we will * need to reread the entire directory contents. */ - i = req->nr_pages; + i = req->cache.nr_pages; while (i < nr_pages) { struct page *pages[8], *page; @@ -351,10 +361,10 @@ static struct afs_read *afs_read_dir(struct afs_vnode *dvnode, struct key *key) set_page_private(page, 1); SetPagePrivate(page); unlock_page(page); - req->nr_pages++; + req->cache.nr_pages++; i++; } else { - req->nr_pages += n; + req->cache.nr_pages += n; i += n; } } @@ -379,9 +389,9 @@ static struct afs_read *afs_read_dir(struct afs_vnode *dvnode, struct key *key) if (ret < 0) goto error_unlock; - task_io_account_read(PAGE_SIZE * req->nr_pages); + task_io_account_read(PAGE_SIZE * req->cache.nr_pages); - if (req->len < req->file_size) { + if (req->cache.len < req->file_size) { /* The content has grown, so we need to expand the * buffer. */ diff --git a/fs/afs/file.c b/fs/afs/file.c index 4a429b3a5f2f..8baafe655433 100644 --- a/fs/afs/file.c +++ b/fs/afs/file.c @@ -199,12 +199,13 @@ int afs_release(struct inode *inode, struct file *file) /* * Handle completion of a read operation. */ -static void afs_file_read_done(struct afs_read *req) +static void afs_file_read_done(struct fscache_io_request *fsreq) { + struct afs_read *req = container_of(fsreq, struct afs_read, cache); struct afs_vnode *vnode = req->vnode; struct page *page; - pgoff_t index = req->pos >> PAGE_SHIFT; - pgoff_t last = index + req->nr_pages - 1; + pgoff_t index = req->cache.pos >> PAGE_SHIFT; + pgoff_t last = index + req->cache.nr_pages - 1; XA_STATE(xas, &vnode->vfs_inode.i_mapping->i_pages, index); @@ -213,7 +214,7 @@ static void afs_file_read_done(struct afs_read *req) _debug("afterclear %zx %zx %llx/%llx", req->iter->iov_offset, iov_iter_count(req->iter), - req->actual_len, req->len); + req->actual_len, req->cache.len); iov_iter_zero(iov_iter_count(req->iter), req->iter); } @@ -224,7 +225,7 @@ static void afs_file_read_done(struct afs_read *req) } rcu_read_unlock(); - task_io_account_read(req->len); + task_io_account_read(req->cache.len); req->cleanup = NULL; } @@ -234,20 +235,21 @@ static void afs_file_read_done(struct afs_read *req) static void afs_file_read_cleanup(struct afs_read *req) { struct page *page; - pgoff_t index = req->pos >> PAGE_SHIFT; - pgoff_t last = index + req->nr_pages - 1; + pgoff_t index = req->cache.pos >> PAGE_SHIFT; + pgoff_t last = index + req->cache.nr_pages - 1; if (req->iter) { XA_STATE(xas, &req->iter->mapping->i_pages, index); - _enter("%lu,%u,%zu", index, req->nr_pages, iov_iter_count(req->iter)); + _enter("%lu,%u,%zu", + index, req->cache.nr_pages, iov_iter_count(req->iter)); rcu_read_lock(); xas_for_each(&xas, page, last) { BUG_ON(xa_is_value(page)); BUG_ON(PageCompound(page)); - page_endio(page, false, req->error); + page_endio(page, false, req->cache.error); put_page(page); } rcu_read_unlock(); @@ -279,7 +281,7 @@ static void afs_fetch_data_success(struct afs_operation *op) static void afs_fetch_data_put(struct afs_operation *op) { - op->fetch.req->error = op->error; + op->fetch.req->cache.error = op->error; afs_put_read(op->fetch.req); } @@ -341,15 +343,15 @@ static int afs_page_filler(struct key *key, struct page *page) refcount_set(&req->usage, 1); req->vnode = vnode; req->key = key_get(key); - req->pos = (loff_t)page->index << PAGE_SHIFT; - req->len = PAGE_SIZE; - req->nr_pages = 1; - req->done = afs_file_read_done; + req->cache.nr_pages = 1; + req->cache.pos = (loff_t)page->index << PAGE_SHIFT; + req->cache.len = PAGE_SIZE; + req->cache.io_done = afs_file_read_done; req->cleanup = afs_file_read_cleanup; get_page(page); iov_iter_mapping(&req->def_iter, READ, page->mapping, - req->pos, req->len); + req->cache.pos, req->cache.len); req->iter = &req->def_iter; ret = afs_fetch_data(vnode, req); @@ -448,10 +450,10 @@ static int afs_readpages_one(struct file *file, struct address_space *mapping, refcount_set(&req->usage, 1); req->vnode = vnode; req->key = key_get(afs_file_key(file)); - req->done = afs_file_read_done; req->cleanup = afs_file_read_cleanup; - req->pos = first->index; - req->pos <<= PAGE_SHIFT; + req->cache.io_done = afs_file_read_done; + req->cache.pos = first->index; + req->cache.pos <<= PAGE_SHIFT; /* Add pages to the LRU until it fails. We keep the pages ref'd and * locked until the read is complete. @@ -471,17 +473,17 @@ static int afs_readpages_one(struct file *file, struct address_space *mapping, break; } - req->nr_pages++; - } while (req->nr_pages < n); + req->cache.nr_pages++; + } while (req->cache.nr_pages < n); - if (req->nr_pages == 0) { + if (req->cache.nr_pages == 0) { afs_put_read(req); return 0; } - req->len = req->nr_pages * PAGE_SIZE; + req->cache.len = req->cache.nr_pages * PAGE_SIZE; iov_iter_mapping(&req->def_iter, READ, file->f_mapping, - req->pos, req->len); + req->cache.pos, req->cache.len); req->iter = &req->def_iter; ret = afs_fetch_data(vnode, req); diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c index c0c91079e76b..d6a8066e666d 100644 --- a/fs/afs/fsclient.c +++ b/fs/afs/fsclient.c @@ -339,7 +339,7 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call) call->unmarshall++; call->iter = req->iter; - call->iov_len = min(req->actual_len, req->len); + call->iov_len = min(req->actual_len, req->cache.len); /* Fall through */ /* extract the returned data */ @@ -352,17 +352,17 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call) return ret; call->iter = &call->def_iter; - if (req->actual_len <= req->len) + if (req->actual_len <= req->cache.len) goto no_more_data; /* Discard any excess data the server gave us */ - afs_extract_discard(call, req->actual_len - req->len); + afs_extract_discard(call, req->actual_len - req->cache.len); call->unmarshall = 3; /* Fall through */ case 3: _debug("extract discard %zu/%llu", - iov_iter_count(call->iter), req->actual_len - req->len); + iov_iter_count(call->iter), req->actual_len - req->cache.len); ret = afs_extract_data(call, true); if (ret < 0) @@ -393,8 +393,8 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call) break; } - if (req->done) - req->done(req); + if (req->cache.io_done) + req->cache.io_done(&req->cache); _leave(" = 0 [done]"); return 0; @@ -439,10 +439,10 @@ static void afs_fs_fetch_data64(struct afs_operation *op) bp[1] = htonl(vp->fid.vid); bp[2] = htonl(vp->fid.vnode); bp[3] = htonl(vp->fid.unique); - bp[4] = htonl(upper_32_bits(req->pos)); - bp[5] = htonl(lower_32_bits(req->pos)); + bp[4] = htonl(upper_32_bits(req->cache.pos)); + bp[5] = htonl(lower_32_bits(req->cache.pos)); bp[6] = 0; - bp[7] = htonl(lower_32_bits(req->len)); + bp[7] = htonl(lower_32_bits(req->cache.len)); trace_afs_make_fs_call(call, &vp->fid); afs_make_op_call(op, call, GFP_NOFS); @@ -458,9 +458,9 @@ void afs_fs_fetch_data(struct afs_operation *op) struct afs_read *req = op->fetch.req; __be32 *bp; - if (upper_32_bits(req->pos) || - upper_32_bits(req->len) || - upper_32_bits(req->pos + req->len)) + if (upper_32_bits(req->cache.pos) || + upper_32_bits(req->cache.len) || + upper_32_bits(req->cache.pos + req->cache.len)) return afs_fs_fetch_data64(op); _enter(""); @@ -477,8 +477,8 @@ void afs_fs_fetch_data(struct afs_operation *op) bp[1] = htonl(vp->fid.vid); bp[2] = htonl(vp->fid.vnode); bp[3] = htonl(vp->fid.unique); - bp[4] = htonl(lower_32_bits(req->pos)); - bp[5] = htonl(lower_32_bits(req->len)); + bp[4] = htonl(lower_32_bits(req->cache.pos)); + bp[5] = htonl(lower_32_bits(req->cache.len)); trace_afs_make_fs_call(call, &vp->fid); afs_make_op_call(op, call, GFP_NOFS); diff --git a/fs/afs/internal.h b/fs/afs/internal.h index 3d0aa1e46539..d55ea1904a27 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -201,8 +201,9 @@ static inline struct key *afs_file_key(struct file *file) * Record of an outstanding read operation on a vnode. */ struct afs_read { - loff_t pos; /* Where to start reading */ - loff_t len; /* How much we're asking for */ + struct fscache_io_request cache; + struct iov_iter def_iter; /* Default iterator */ + struct iov_iter *iter; /* Iterator to use */ loff_t actual_len; /* How much we're actually getting */ loff_t file_size; /* File size returned by server */ struct key *key; /* The key to use to reissue the read */ @@ -210,12 +211,7 @@ struct afs_read { afs_dataversion_t data_version; /* Version number returned by server */ refcount_t usage; unsigned int call_debug_id; - unsigned int nr_pages; - int error; - void (*done)(struct afs_read *); - void (*cleanup)(struct afs_read *); - struct iov_iter *iter; /* Iterator representing the buffer */ - struct iov_iter def_iter; /* Default iterator */ + void (*cleanup)(struct afs_read *req); }; /* diff --git a/fs/afs/write.c b/fs/afs/write.c index 37c968b9c89b..d9de0dc877ca 100644 --- a/fs/afs/write.c +++ b/fs/afs/write.c @@ -25,8 +25,10 @@ int afs_set_page_dirty(struct page *page) /* * Handle completion of a read operation to fill a page. */ -static void afs_fill_hole(struct afs_read *req) +static void afs_fill_hole(struct fscache_io_request *fsreq) { + struct afs_read *req = container_of(fsreq, struct afs_read, cache); + if (iov_iter_count(req->iter) > 0) /* The read was short - clear the excess buffer. */ iov_iter_zero(iov_iter_count(req->iter), req->iter); @@ -60,13 +62,13 @@ static int afs_fill_page(struct file *file, return -ENOMEM; refcount_set(&req->usage, 1); - req->vnode = vnode; - req->done = afs_fill_hole; - req->key = afs_file_key(file); - req->pos = pos; - req->len = len; - req->nr_pages = 1; - req->iter = &req->def_iter; + req->vnode = vnode; + req->key = afs_file_key(file); + req->cache.io_done = afs_fill_hole; + req->cache.pos = pos; + req->cache.len = len; + req->cache.nr_pages = 1; + req->iter = &req->def_iter; iov_iter_mapping(&req->def_iter, READ, vnode->vfs_inode.i_mapping, pos, len); diff --git a/fs/afs/yfsclient.c b/fs/afs/yfsclient.c index ac3541773e7c..30621f4fffc0 100644 --- a/fs/afs/yfsclient.c +++ b/fs/afs/yfsclient.c @@ -392,7 +392,7 @@ static int yfs_deliver_fs_fetch_data64(struct afs_call *call) call->unmarshall++; call->iter = req->iter; - call->iov_len = min(req->actual_len, req->len); + call->iov_len = min(req->actual_len, req->cache.len); /* Fall through */ /* extract the returned data */ @@ -405,17 +405,17 @@ static int yfs_deliver_fs_fetch_data64(struct afs_call *call) return ret; call->iter = &call->def_iter; - if (req->actual_len <= req->len) + if (req->actual_len <= req->cache.len) goto no_more_data; /* Discard any excess data the server gave us */ - afs_extract_discard(call, req->actual_len - req->len); + afs_extract_discard(call, req->actual_len - req->cache.len); call->unmarshall = 3; /* Fall through */ case 3: _debug("extract discard %zu/%llu", - iov_iter_count(call->iter), req->actual_len - req->len); + iov_iter_count(call->iter), req->actual_len - req->cache.len); ret = afs_extract_data(call, true); if (ret < 0) @@ -450,8 +450,8 @@ static int yfs_deliver_fs_fetch_data64(struct afs_call *call) break; } - if (req->done) - req->done(req); + if (req->cache.io_done) + req->cache.io_done(&req->cache); _leave(" = 0 [done]"); return 0; @@ -479,7 +479,7 @@ void yfs_fs_fetch_data(struct afs_operation *op) _enter(",%x,{%llx:%llu},%llx,%llx", key_serial(op->key), vp->fid.vid, vp->fid.vnode, - req->pos, req->len); + req->cache.pos, req->cache.len); call = afs_alloc_flat_call(op->net, &yfs_RXYFSFetchData64, sizeof(__be32) * 2 + @@ -498,8 +498,8 @@ void yfs_fs_fetch_data(struct afs_operation *op) bp = xdr_encode_u32(bp, YFSFETCHDATA64); bp = xdr_encode_u32(bp, 0); /* RPC flags */ bp = xdr_encode_YFSFid(bp, &vp->fid); - bp = xdr_encode_u64(bp, req->pos); - bp = xdr_encode_u64(bp, req->len); + bp = xdr_encode_u64(bp, req->cache.pos); + bp = xdr_encode_u64(bp, req->cache.len); yfs_check_req(call, bp); trace_afs_make_fs_call(call, &vp->fid); From patchwork Mon Jul 13 16:38:32 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Howells X-Patchwork-Id: 11660673 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 309C413B4 for ; Mon, 13 Jul 2020 16:38:47 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 186B22067D for ; Mon, 13 Jul 2020 16:38:47 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="Z5Maz9ED" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730290AbgGMQip (ORCPT ); Mon, 13 Jul 2020 12:38:45 -0400 Received: from us-smtp-1.mimecast.com ([205.139.110.61]:43130 "EHLO us-smtp-delivery-1.mimecast.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1730591AbgGMQio (ORCPT ); Mon, 13 Jul 2020 12:38:44 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1594658322; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=sL3hQiLEAPYlRGXT83j6gzNW7fCSVrdyHgkgU/ju4ks=; b=Z5Maz9ED4bYMu/Rqo49vxAqA943i5AtbJZg7qYSOoeZuCE8mPwNEqQNtZRpncXkHlZ969t 1WAa2U9t1Hga/137jZmQovBb3bmsLt8fYj1pNd9yIRx5t5eeOjo3YGqueY+5VoI7cJX2g2 K8KUuHP0omyETbESmUI6I0/+OwPRzHs= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-166--kgTRIfMOL-pA7rXZyEOTQ-1; Mon, 13 Jul 2020 12:38:40 -0400 X-MC-Unique: -kgTRIfMOL-pA7rXZyEOTQ-1 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id EDB6380183C; Mon, 13 Jul 2020 16:38:38 +0000 (UTC) Received: from warthog.procyon.org.uk (ovpn-112-113.rdu2.redhat.com [10.10.112.113]) by smtp.corp.redhat.com (Postfix) with ESMTP id B0D5110013C0; Mon, 13 Jul 2020 16:38:33 +0000 (UTC) Organization: Red Hat UK Ltd. Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SI4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 3798903 Subject: [PATCH 08/13] afs: Note the amount transferred in fetch-data delivery From: David Howells To: Trond Myklebust , Anna Schumaker , Steve French , Alexander Viro , Matthew Wilcox Cc: Jeff Layton , Dave Wysochanski , dhowells@redhat.com, linux-cachefs@redhat.com, linux-afs@lists.infradead.org, linux-nfs@vger.kernel.org, linux-cifs@vger.kernel.org, ceph-devel@vger.kernel.org, v9fs-developer@lists.sourceforge.net, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Date: Mon, 13 Jul 2020 17:38:32 +0100 Message-ID: <159465831290.1377938.10075677476527399814.stgit@warthog.procyon.org.uk> In-Reply-To: <159465821598.1377938.2046362270225008168.stgit@warthog.procyon.org.uk> References: <159465821598.1377938.2046362270225008168.stgit@warthog.procyon.org.uk> User-Agent: StGit/0.22 MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.22 Sender: linux-nfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org Note the amount of data transferred in the fscache request op structure in the delivery/decode routines for the various FetchData operations. Also, we need to exclude the excess from this value and then we need to use this in directory read rather than actual_len. Signed-off-by: David Howells --- fs/afs/dir.c | 9 ++++----- fs/afs/fsclient.c | 5 +++++ fs/afs/yfsclient.c | 5 +++++ 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/fs/afs/dir.c b/fs/afs/dir.c index 9d47df15c790..03ef09330d10 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c @@ -209,9 +209,8 @@ static void afs_dir_dump(struct afs_vnode *dvnode, struct afs_read *req) pr_warn("DIR %llx:%llx f=%llx l=%llx al=%llx\n", dvnode->fid.vid, dvnode->fid.vnode, req->file_size, req->cache.len, req->actual_len); - pr_warn("DIR %llx %x %zx %zx\n", - req->cache.pos, req->cache.nr_pages, - req->iter->iov_offset, iov_iter_count(req->iter)); + pr_warn("DIR %llx %x %llx\n", + req->cache.pos, req->cache.nr_pages, req->cache.transferred); xas_for_each(&xas, page, last) { if (xas_retry(&xas, page)) @@ -321,7 +320,7 @@ static struct afs_read *afs_read_dir(struct afs_vnode *dvnode, struct key *key) nr_pages = (i_size + PAGE_SIZE - 1) / PAGE_SIZE; - req->actual_len = i_size; /* May change */ + req->cache.transferred = i_size; /* May change */ req->cache.len = nr_pages * PAGE_SIZE; /* We can ask for more than there is */ req->data_version = dvnode->status.data_version; /* May change */ iov_iter_mapping(&req->def_iter, READ, dvnode->vfs_inode.i_mapping, @@ -546,7 +545,7 @@ static int afs_dir_iterate(struct inode *dir, struct dir_context *ctx, /* walk through the blocks in sequence */ ret = 0; - while (ctx->pos < req->actual_len) { + while (ctx->pos < req->cache.transferred) { blkoff = ctx->pos & ~(sizeof(union afs_xdr_dir_block) - 1); /* Fetch the appropriate page from the directory and re-add it diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c index d6a8066e666d..e729a19f28c5 100644 --- a/fs/afs/fsclient.c +++ b/fs/afs/fsclient.c @@ -393,6 +393,11 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call) break; } + /* Pass the call's ref on the read request descriptor to the completion + * handler. + */ + req->cache.transferred = min(req->actual_len, req->cache.len); + set_bit(FSCACHE_IO_DATA_FROM_SERVER, &req->cache.flags); if (req->cache.io_done) req->cache.io_done(&req->cache); diff --git a/fs/afs/yfsclient.c b/fs/afs/yfsclient.c index 30621f4fffc0..4ead0c1f9014 100644 --- a/fs/afs/yfsclient.c +++ b/fs/afs/yfsclient.c @@ -450,6 +450,11 @@ static int yfs_deliver_fs_fetch_data64(struct afs_call *call) break; } + /* Pass the call's ref on the read request descriptor to the completion + * handler. + */ + req->cache.transferred = min(req->actual_len, req->cache.len); + set_bit(FSCACHE_IO_DATA_FROM_SERVER, &req->cache.flags); if (req->cache.io_done) req->cache.io_done(&req->cache); From patchwork Mon Jul 13 16:38:44 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Howells X-Patchwork-Id: 11660685 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id EBE246C1 for ; Mon, 13 Jul 2020 16:38:57 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id D4122206F5 for ; Mon, 13 Jul 2020 16:38:57 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="i2egx+rJ" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730496AbgGMQiz (ORCPT ); Mon, 13 Jul 2020 12:38:55 -0400 Received: from us-smtp-1.mimecast.com ([205.139.110.61]:38027 "EHLO us-smtp-delivery-1.mimecast.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1730119AbgGMQiy (ORCPT ); Mon, 13 Jul 2020 12:38:54 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1594658333; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=hBqsUy2masEpa+uY5TjuNpXWjnW0S3sDVF3PP2vI20s=; b=i2egx+rJwczMwQ2+YAxEZjpntPrvYj1vrK09xvsIUmlo0ImxbPAHUIXCN6l/jnTkJ9axfE yz2q87Y4spSknS7zzs8jSNXIPo9H1wTBmOuJ0r1luj2u/ADq+gddrS27Vsmyb9SBSafS48 1zqfXMJUN3te/2P3gc79+omdbivjCvY= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-260-K7doxlJWMZ237TzMS3ZXzA-1; Mon, 13 Jul 2020 12:38:51 -0400 X-MC-Unique: K7doxlJWMZ237TzMS3ZXzA-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 1E7B71080; Mon, 13 Jul 2020 16:38:50 +0000 (UTC) Received: from warthog.procyon.org.uk (ovpn-112-113.rdu2.redhat.com [10.10.112.113]) by smtp.corp.redhat.com (Postfix) with ESMTP id E089D6FDD1; Mon, 13 Jul 2020 16:38:44 +0000 (UTC) Organization: Red Hat UK Ltd. Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SI4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 3798903 Subject: [PATCH 09/13] afs: Wait on PG_fscache before modifying/releasing a page From: David Howells To: Trond Myklebust , Anna Schumaker , Steve French , Alexander Viro , Matthew Wilcox Cc: Jeff Layton , Dave Wysochanski , dhowells@redhat.com, linux-cachefs@redhat.com, linux-afs@lists.infradead.org, linux-nfs@vger.kernel.org, linux-cifs@vger.kernel.org, ceph-devel@vger.kernel.org, v9fs-developer@lists.sourceforge.net, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Date: Mon, 13 Jul 2020 17:38:44 +0100 Message-ID: <159465832417.1377938.3571599385208729791.stgit@warthog.procyon.org.uk> In-Reply-To: <159465821598.1377938.2046362270225008168.stgit@warthog.procyon.org.uk> References: <159465821598.1377938.2046362270225008168.stgit@warthog.procyon.org.uk> User-Agent: StGit/0.22 MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 Sender: linux-nfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org PG_fscache is going to be used to indicate that a page is being written to the cache, and that the page should not be modified or released until it's finished. Make afs_invalidatepage() and afs_releasepage() wait for it. Signed-off-by: David Howells --- fs/afs/file.c | 7 +++++++ fs/afs/write.c | 9 +++++++++ 2 files changed, 16 insertions(+) diff --git a/fs/afs/file.c b/fs/afs/file.c index 8baafe655433..2f9a7369b77b 100644 --- a/fs/afs/file.c +++ b/fs/afs/file.c @@ -580,6 +580,13 @@ static int afs_releasepage(struct page *page, gfp_t gfp_flags) /* deny if page is being written to the cache and the caller hasn't * elected to wait */ +#ifdef CONFIG_AFS_FSCACHE + if (PageFsCache(page)) { + if (!(gfp_flags & __GFP_DIRECT_RECLAIM) || !(gfp_flags & __GFP_FS)) + return false; + } +#endif + if (PagePrivate(page)) { priv = page_private(page); trace_afs_page_dirty(vnode, tracepoint_string("rel"), diff --git a/fs/afs/write.c b/fs/afs/write.c index d9de0dc877ca..73e2f4c93512 100644 --- a/fs/afs/write.c +++ b/fs/afs/write.c @@ -125,6 +125,10 @@ int afs_write_begin(struct file *file, struct address_space *mapping, SetPageUptodate(page); } +#ifdef CONFIG_AFS_FSCACHE + wait_on_page_fscache(page); +#endif + /* page won't leak in error case: it eventually gets cleaned off LRU */ *pagep = page; @@ -849,6 +853,11 @@ vm_fault_t afs_page_mkwrite(struct vm_fault *vmf) /* Wait for the page to be written to the cache before we allow it to * be modified. We then assume the entire page will need writing back. */ +#ifdef CONFIG_AFS_FSCACHE + if (PageFsCache(vmf->page) && + wait_on_page_bit_killable(vmf->page, PG_fscache) < 0) + return VM_FAULT_RETRY; +#endif if (PageWriteback(vmf->page) && wait_on_page_bit_killable(vmf->page, PG_writeback) < 0) From patchwork Mon Jul 13 16:38:55 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Howells X-Patchwork-Id: 11660691 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id B27B013B4 for ; Mon, 13 Jul 2020 16:39:16 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 8C85D20773 for ; Mon, 13 Jul 2020 16:39:16 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="cTgyWnXP" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730098AbgGMQjO (ORCPT ); Mon, 13 Jul 2020 12:39:14 -0400 Received: from us-smtp-delivery-1.mimecast.com ([205.139.110.120]:34707 "EHLO us-smtp-1.mimecast.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1730633AbgGMQjM (ORCPT ); Mon, 13 Jul 2020 12:39:12 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1594658349; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=KKadESJQ09lMc3nk+ibKGUSX3dfDS51s+7mWdjFN8QU=; b=cTgyWnXPU+8KfHczTa0EYIrucrQCqr7RKD+Z81uxM2gg8ouX6xo2+eP8PlcpwzLFpa/nG7 ZP7BlNuHMzBG66B47anWaMapLZM1bBTktTIlUYJiPdhpqBL38ZEa/FQtGn23pAxHZK1rcs zSU2/VLNBSMkEZhsPsAhFqc9ObBXuac= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-318-F_Xx8fLIOfuaVJ70wM9uoQ-1; Mon, 13 Jul 2020 12:39:04 -0400 X-MC-Unique: F_Xx8fLIOfuaVJ70wM9uoQ-1 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 2AFA38018A1; Mon, 13 Jul 2020 16:39:02 +0000 (UTC) Received: from warthog.procyon.org.uk (ovpn-112-113.rdu2.redhat.com [10.10.112.113]) by smtp.corp.redhat.com (Postfix) with ESMTP id 286ED1010404; Mon, 13 Jul 2020 16:38:56 +0000 (UTC) Organization: Red Hat UK Ltd. Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SI4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 3798903 Subject: [PATCH 10/13] afs: Use new fscache I/O API From: David Howells To: Trond Myklebust , Anna Schumaker , Steve French , Alexander Viro , Matthew Wilcox Cc: Jeff Layton , Dave Wysochanski , dhowells@redhat.com, linux-cachefs@redhat.com, linux-afs@lists.infradead.org, linux-nfs@vger.kernel.org, linux-cifs@vger.kernel.org, ceph-devel@vger.kernel.org, v9fs-developer@lists.sourceforge.net, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Date: Mon, 13 Jul 2020 17:38:55 +0100 Message-ID: <159465833532.1377938.17200329236364493561.stgit@warthog.procyon.org.uk> In-Reply-To: <159465821598.1377938.2046362270225008168.stgit@warthog.procyon.org.uk> References: <159465821598.1377938.2046362270225008168.stgit@warthog.procyon.org.uk> User-Agent: StGit/0.22 MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.22 Sender: linux-nfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org Make AFS use the new fscache I/O API to read and write from the cache. afs_readpage() now calls fscache_read_helper() once to try and create a block around the page to be read. afs_readpages() now calls fscache_read_helper() multiple times until its list is exhausted or an error occurs. afs_prefetch_for_write() is provided to be called from afs_write_begin() to load the data that will be overwritten by the write into the cache, extending the read as necessary. This guarantees that the page it returns will be up to date, rendering it unnecessary for afs_write_end() to fill in the gaps. Signed-off-by: David Howells --- fs/afs/Kconfig | 1 fs/afs/dir.c | 1 fs/afs/file.c | 368 +++++++++++++++++++++++++---------------------------- fs/afs/internal.h | 9 + fs/afs/write.c | 105 +-------------- 5 files changed, 192 insertions(+), 292 deletions(-) diff --git a/fs/afs/Kconfig b/fs/afs/Kconfig index 1ad211d72b3b..4cbf93a55bf9 100644 --- a/fs/afs/Kconfig +++ b/fs/afs/Kconfig @@ -4,6 +4,7 @@ config AFS_FS depends on INET select AF_RXRPC select DNS_RESOLVER + select FSCACHE_SUPPORT help If you say Y here, you will get an experimental Andrew File System driver. It currently only supports unsecured read-only AFS access. diff --git a/fs/afs/dir.c b/fs/afs/dir.c index 03ef09330d10..eb51c92ec807 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c @@ -303,6 +303,7 @@ static struct afs_read *afs_read_dir(struct afs_vnode *dvnode, struct key *key) req->vnode = dvnode; req->cleanup = afs_dir_read_cleanup; req->cache.io_done = afs_dir_read_done; + fscache_init_io_request(&req->cache, NULL, NULL); expand: i_size = i_size_read(&dvnode->vfs_inode); diff --git a/fs/afs/file.c b/fs/afs/file.c index 2f9a7369b77b..5aa7b89e7359 100644 --- a/fs/afs/file.c +++ b/fs/afs/file.c @@ -196,76 +196,80 @@ int afs_release(struct inode *inode, struct file *file) return ret; } -/* - * Handle completion of a read operation. - */ -static void afs_file_read_done(struct fscache_io_request *fsreq) -{ - struct afs_read *req = container_of(fsreq, struct afs_read, cache); - struct afs_vnode *vnode = req->vnode; - struct page *page; - pgoff_t index = req->cache.pos >> PAGE_SHIFT; - pgoff_t last = index + req->cache.nr_pages - 1; - - XA_STATE(xas, &vnode->vfs_inode.i_mapping->i_pages, index); - - if (iov_iter_count(req->iter) > 0) { - /* The read was short - clear the excess buffer. */ - _debug("afterclear %zx %zx %llx/%llx", - req->iter->iov_offset, - iov_iter_count(req->iter), - req->actual_len, req->cache.len); - iov_iter_zero(iov_iter_count(req->iter), req->iter); - } - - rcu_read_lock(); - xas_for_each(&xas, page, last) { - page_endio(page, false, 0); - put_page(page); - } - rcu_read_unlock(); - - task_io_account_read(req->cache.len); - req->cleanup = NULL; -} - /* * Dispose of our locks and refs on the pages if the read failed. */ static void afs_file_read_cleanup(struct afs_read *req) { + struct afs_vnode *vnode = req->vnode; struct page *page; pgoff_t index = req->cache.pos >> PAGE_SHIFT; pgoff_t last = index + req->cache.nr_pages - 1; - if (req->iter) { - XA_STATE(xas, &req->iter->mapping->i_pages, index); + _enter("%lx,%x,%llx", index, req->cache.nr_pages, req->cache.len); - _enter("%lu,%u,%zu", - index, req->cache.nr_pages, iov_iter_count(req->iter)); + if (req->cache.nr_pages > 0) { + XA_STATE(xas, &vnode->vfs_inode.i_mapping->i_pages, index); rcu_read_lock(); xas_for_each(&xas, page, last) { BUG_ON(xa_is_value(page)); BUG_ON(PageCompound(page)); - page_endio(page, false, req->cache.error); + if (req->cache.error) + page_endio(page, false, req->cache.error); + else + unlock_page(page); put_page(page); } rcu_read_unlock(); } } +/* + * Allocate a new read record. + */ +struct afs_read *afs_alloc_read(gfp_t gfp) +{ + static atomic_t debug_ids; + struct afs_read *req; + + req = kzalloc(sizeof(struct afs_read), gfp); + if (req) { + refcount_set(&req->usage, 1); + req->debug_id = atomic_inc_return(&debug_ids); + } + + return req; +} + +/* + * + */ +static void __afs_put_read(struct work_struct *work) +{ + struct afs_read *req = container_of(work, struct afs_read, cache.work); + + if (req->cleanup) + req->cleanup(req); + fscache_free_io_request(&req->cache); + key_put(req->key); + kfree(req); +} + /* * Dispose of a ref to a read record. */ void afs_put_read(struct afs_read *req) { if (refcount_dec_and_test(&req->usage)) { - if (req->cleanup) - req->cleanup(req); - key_put(req->key); - kfree(req); + _debug("dead %u", req->debug_id); + if (in_softirq()) { + INIT_WORK(&req->cache.work, __afs_put_read); + queue_work(afs_wq, &req->cache.work); + } else { + __afs_put_read(&req->cache.work); + } } } @@ -318,189 +322,89 @@ int afs_fetch_data(struct afs_vnode *vnode, struct afs_read *req) return afs_do_sync_operation(op); } -/* - * read page from file, directory or symlink, given a key to use - */ -static int afs_page_filler(struct key *key, struct page *page) +void afs_req_issue_op(struct fscache_io_request *fsreq) { - struct inode *inode = page->mapping->host; - struct afs_vnode *vnode = AFS_FS_I(inode); - struct afs_read *req; + struct afs_read *req = container_of(fsreq, struct afs_read, cache); int ret; - _enter("{%x},{%lu},{%lu}", key_serial(key), inode->i_ino, page->index); - - BUG_ON(!PageLocked(page)); - - ret = -ESTALE; - if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) - goto error; - - req = kzalloc(sizeof(struct afs_read), GFP_KERNEL); - if (!req) - goto enomem; - - refcount_set(&req->usage, 1); - req->vnode = vnode; - req->key = key_get(key); - req->cache.nr_pages = 1; - req->cache.pos = (loff_t)page->index << PAGE_SHIFT; - req->cache.len = PAGE_SIZE; - req->cache.io_done = afs_file_read_done; - req->cleanup = afs_file_read_cleanup; - - get_page(page); - iov_iter_mapping(&req->def_iter, READ, page->mapping, + iov_iter_mapping(&req->def_iter, READ, req->cache.mapping, req->cache.pos, req->cache.len); req->iter = &req->def_iter; - ret = afs_fetch_data(vnode, req); + ret = afs_fetch_data(req->vnode, req); if (ret < 0) - goto fetch_error; + req->cache.error = ret; +} - afs_put_read(req); - _leave(" = 0"); - return 0; +void afs_req_done(struct fscache_io_request *fsreq) +{ + struct afs_read *req = container_of(fsreq, struct afs_read, cache); -fetch_error: - switch (ret) { - case -EINTR: - case -ENOMEM: - case -ERESTARTSYS: - case -EAGAIN: - afs_put_read(req); - goto error; - case -ENOENT: - _debug("got NOENT from server - marking file deleted and stale"); - set_bit(AFS_VNODE_DELETED, &vnode->flags); - ret = -ESTALE; - /* Fall through */ - default: - page_endio(page, false, ret); - afs_put_read(req); - _leave(" = %d", ret); - return ret; - } + req->cleanup = NULL; +} -enomem: - ret = -ENOMEM; -error: - unlock_page(page); - _leave(" = %d", ret); - return ret; +void afs_req_get(struct fscache_io_request *fsreq) +{ + struct afs_read *req = container_of(fsreq, struct afs_read, cache); + + afs_get_read(req); +} + +void afs_req_put(struct fscache_io_request *fsreq) +{ + struct afs_read *req = container_of(fsreq, struct afs_read, cache); + + afs_put_read(req); } +const struct fscache_io_request_ops afs_req_ops = { + .issue_op = afs_req_issue_op, + .done = afs_req_done, + .get = afs_req_get, + .put = afs_req_put, +}; + /* * read page from file, directory or symlink, given a file to nominate the key * to be used */ static int afs_readpage(struct file *file, struct page *page) { + struct afs_vnode *vnode = AFS_FS_I(page->mapping->host); + struct afs_read *req; struct key *key; - int ret; + int ret = -ENOMEM; + + _enter(",%lx", page->index); if (file) { - key = afs_file_key(file); + key = key_get(afs_file_key(file)); ASSERT(key != NULL); - ret = afs_page_filler(key, page); } else { - struct inode *inode = page->mapping->host; - key = afs_request_key(AFS_FS_S(inode->i_sb)->cell); + key = afs_request_key(vnode->volume->cell); if (IS_ERR(key)) { ret = PTR_ERR(key); - } else { - ret = afs_page_filler(key, page); - key_put(key); + goto out; } } - return ret; -} - -/* - * Read a contiguous set of pages. - */ -static int afs_readpages_one(struct file *file, struct address_space *mapping, - struct list_head *pages) -{ - struct afs_vnode *vnode = AFS_FS_I(mapping->host); - struct afs_read *req; - struct list_head *p; - struct page *first, *page; - pgoff_t index; - int ret, n; - - /* Count the number of contiguous pages at the front of the list. Note - * that the list goes prev-wards rather than next-wards. - */ - first = lru_to_page(pages); - index = first->index + 1; - n = 1; - for (p = first->lru.prev; p != pages; p = p->prev) { - page = list_entry(p, struct page, lru); - if (page->index != index) - break; - index++; - n++; - } - req = kzalloc(sizeof(struct afs_read), GFP_NOFS); + req = afs_alloc_read(GFP_NOFS); if (!req) - return -ENOMEM; + goto out_key; - refcount_set(&req->usage, 1); + fscache_init_io_request(&req->cache, afs_vnode_cache(vnode), &afs_req_ops); req->vnode = vnode; - req->key = key_get(afs_file_key(file)); + req->key = key; req->cleanup = afs_file_read_cleanup; - req->cache.io_done = afs_file_read_done; - req->cache.pos = first->index; - req->cache.pos <<= PAGE_SHIFT; - - /* Add pages to the LRU until it fails. We keep the pages ref'd and - * locked until the read is complete. - * - * Note that it's possible for the file size to change whilst we're - * doing this, but we rely on the server returning less than we asked - * for if the file shrank. We also rely on this to deal with a partial - * page at the end of the file. - */ - do { - page = lru_to_page(pages); - list_del(&page->lru); - index = page->index; - if (add_to_page_cache_lru(page, mapping, index, - readahead_gfp_mask(mapping))) { - put_page(page); - break; - } - - req->cache.nr_pages++; - } while (req->cache.nr_pages < n); - - if (req->cache.nr_pages == 0) { - afs_put_read(req); - return 0; - } - - req->cache.len = req->cache.nr_pages * PAGE_SIZE; - iov_iter_mapping(&req->def_iter, READ, file->f_mapping, - req->cache.pos, req->cache.len); - req->iter = &req->def_iter; - - ret = afs_fetch_data(vnode, req); - if (ret < 0) - goto error; + req->cache.mapping = page->mapping; + ret = fscache_read_helper_locked_page(&req->cache, page, ULONG_MAX); afs_put_read(req); - return 0; - -error: - if (ret == -ENOENT) { - _debug("got NOENT from server - marking file deleted and stale"); - set_bit(AFS_VNODE_DELETED, &vnode->flags); - ret = -ESTALE; - } + return ret; - afs_put_read(req); +out_key: + key_put(key); +out: return ret; } @@ -510,14 +414,11 @@ static int afs_readpages_one(struct file *file, struct address_space *mapping, static int afs_readpages(struct file *file, struct address_space *mapping, struct list_head *pages, unsigned nr_pages) { - struct key *key = afs_file_key(file); struct afs_vnode *vnode; + struct afs_read *req; int ret = 0; - _enter("{%d},{%lu},,%d", - key_serial(key), mapping->host->i_ino, nr_pages); - - ASSERT(key != NULL); + _enter(",{%lu},,%x", mapping->host->i_ino, nr_pages); vnode = AFS_FS_I(mapping->host); if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) { @@ -525,9 +426,21 @@ static int afs_readpages(struct file *file, struct address_space *mapping, return -ESTALE; } - /* attempt to read as many of the pages as possible */ while (!list_empty(pages)) { - ret = afs_readpages_one(file, mapping, pages); + req = afs_alloc_read(GFP_NOFS); + if (!req) + return -ENOMEM; + + fscache_init_io_request(&req->cache, afs_vnode_cache(vnode), + &afs_req_ops); + req->vnode = AFS_FS_I(mapping->host); + req->key = key_get(afs_file_key(file)); + req->cleanup = afs_file_read_cleanup; + req->cache.mapping = mapping; + + ret = fscache_read_helper_page_list(&req->cache, pages, + ULONG_MAX); + afs_put_read(req); if (ret < 0) break; } @@ -536,6 +449,67 @@ static int afs_readpages(struct file *file, struct address_space *mapping, return ret; } +/* + * Prefetch data into the cache prior to writing, returning the requested page + * to the caller, with the lock held, upon completion of the write. + */ +struct page *afs_prefetch_for_write(struct file *file, + struct address_space *mapping, + pgoff_t index, + unsigned int aop_flags) +{ + struct afs_vnode *vnode = AFS_FS_I(mapping->host); + struct afs_read *req; + struct page *page; + int ret = 0; + + _enter("{%lu},%lx", mapping->host->i_ino, index); + + if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) { + _leave(" = -ESTALE"); + return ERR_PTR(-ESTALE); + } + + page = pagecache_get_page(mapping, index, FGP_WRITE, 0); + if (page) { + if (PageUptodate(page)) { + lock_page(page); + if (PageUptodate(page)) + goto have_page; + unlock_page(page); + } + } + + req = afs_alloc_read(GFP_NOFS); + if (!req) + return ERR_PTR(-ENOMEM); + + fscache_init_io_request(&req->cache, afs_vnode_cache(vnode), &afs_req_ops); + req->vnode = AFS_FS_I(mapping->host); + req->key = key_get(afs_file_key(file)); + req->cleanup = afs_file_read_cleanup; + req->cache.mapping = mapping; + + ret = fscache_read_helper_for_write(&req->cache, &page, index, + ULONG_MAX, aop_flags); + if (ret == 0) + /* Synchronicity required */ + ret = wait_on_bit(&req->cache.flags, FSCACHE_IO_READ_IN_PROGRESS, + TASK_KILLABLE); + + afs_put_read(req); + + if (ret < 0) { + if (page) + put_page(page); + return ERR_PTR(ret); + } + +have_page: + wait_for_stable_page(page); + return page; +} + /* * invalidate part or all of a page * - release a page and clean up its private data if offset is 0 (indicating diff --git a/fs/afs/internal.h b/fs/afs/internal.h index d55ea1904a27..8c9abfa33a91 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -210,6 +210,7 @@ struct afs_read { struct afs_vnode *vnode; /* The file being read into. */ afs_dataversion_t data_version; /* Version number returned by server */ refcount_t usage; + unsigned int debug_id; unsigned int call_debug_id; void (*cleanup)(struct afs_read *req); }; @@ -961,6 +962,7 @@ extern void afs_dynroot_depopulate(struct super_block *); /* * file.c */ +extern const struct fscache_io_request_ops afs_req_ops; extern const struct address_space_operations afs_fs_aops; extern const struct inode_operations afs_file_inode_operations; extern const struct file_operations afs_file_operations; @@ -970,7 +972,14 @@ extern void afs_put_wb_key(struct afs_wb_key *); extern int afs_open(struct inode *, struct file *); extern int afs_release(struct inode *, struct file *); extern int afs_fetch_data(struct afs_vnode *, struct afs_read *); +extern struct afs_read *afs_alloc_read(gfp_t); extern void afs_put_read(struct afs_read *); +extern void afs_req_issue_op(struct fscache_io_request *); +extern void afs_req_done(struct fscache_io_request *); +extern void afs_req_get(struct fscache_io_request *); +extern void afs_req_put(struct fscache_io_request *); +extern struct page *afs_prefetch_for_write(struct file *, struct address_space *, + pgoff_t, unsigned int); static inline struct afs_read *afs_get_read(struct afs_read *req) { diff --git a/fs/afs/write.c b/fs/afs/write.c index 73e2f4c93512..cb27027c06bb 100644 --- a/fs/afs/write.c +++ b/fs/afs/write.c @@ -22,71 +22,6 @@ int afs_set_page_dirty(struct page *page) return __set_page_dirty_nobuffers(page); } -/* - * Handle completion of a read operation to fill a page. - */ -static void afs_fill_hole(struct fscache_io_request *fsreq) -{ - struct afs_read *req = container_of(fsreq, struct afs_read, cache); - - if (iov_iter_count(req->iter) > 0) - /* The read was short - clear the excess buffer. */ - iov_iter_zero(iov_iter_count(req->iter), req->iter); -} - -/* - * partly or wholly fill a page that's under preparation for writing - */ -static int afs_fill_page(struct file *file, - loff_t pos, unsigned int len, struct page *page) -{ - struct afs_vnode *vnode = AFS_FS_I(file_inode(file)); - struct afs_read *req; - size_t p; - void *data; - int ret; - - _enter(",,%llu", (unsigned long long)pos); - - if (pos >= vnode->vfs_inode.i_size) { - p = pos & ~PAGE_MASK; - ASSERTCMP(p + len, <=, PAGE_SIZE); - data = kmap(page); - memset(data + p, 0, len); - kunmap(page); - return 0; - } - - req = kzalloc(sizeof(struct afs_read), GFP_KERNEL); - if (!req) - return -ENOMEM; - - refcount_set(&req->usage, 1); - req->vnode = vnode; - req->key = afs_file_key(file); - req->cache.io_done = afs_fill_hole; - req->cache.pos = pos; - req->cache.len = len; - req->cache.nr_pages = 1; - req->iter = &req->def_iter; - iov_iter_mapping(&req->def_iter, READ, vnode->vfs_inode.i_mapping, - pos, len); - - ret = afs_fetch_data(vnode, req); - afs_put_read(req); - if (ret < 0) { - if (ret == -ENOENT) { - _debug("got NOENT from server" - " - marking file deleted and stale"); - set_bit(AFS_VNODE_DELETED, &vnode->flags); - ret = -ESTALE; - } - } - - _leave(" = %d", ret); - return ret; -} - /* * prepare to perform part of a write to a page */ @@ -110,20 +45,15 @@ int afs_write_begin(struct file *file, struct address_space *mapping, */ BUILD_BUG_ON(PAGE_SIZE > 32768 && sizeof(page->private) < 8); - page = grab_cache_page_write_begin(mapping, index, flags); - if (!page) - return -ENOMEM; + /* Prefetch area to be written into the cache if we're caching this + * file. We need to do this before we get a lock on the page in case + * there's more than one writer competing for the same cache block. + */ + page = afs_prefetch_for_write(file, mapping, index, flags); + if (IS_ERR(page)) + return PTR_ERR(page); - if (!PageUptodate(page) && len != PAGE_SIZE) { - ret = afs_fill_page(file, pos & PAGE_MASK, PAGE_SIZE, page); - if (ret < 0) { - unlock_page(page); - put_page(page); - _leave(" = %d [prep]", ret); - return ret; - } - SetPageUptodate(page); - } + ASSERT(PageUptodate(page)); #ifdef CONFIG_AFS_FSCACHE wait_on_page_fscache(page); @@ -203,7 +133,6 @@ int afs_write_end(struct file *file, struct address_space *mapping, { struct afs_vnode *vnode = AFS_FS_I(file_inode(file)); loff_t i_size, maybe_i_size; - int ret; _enter("{%llx:%llu},{%lx}", vnode->fid.vid, vnode->fid.vnode, page->index); @@ -219,29 +148,15 @@ int afs_write_end(struct file *file, struct address_space *mapping, write_sequnlock(&vnode->cb_lock); } - if (!PageUptodate(page)) { - if (copied < len) { - /* Try and load any missing data from the server. The - * unmarshalling routine will take care of clearing any - * bits that are beyond the EOF. - */ - ret = afs_fill_page(file, pos + copied, - len - copied, page); - if (ret < 0) - goto out; - } - SetPageUptodate(page); - } + ASSERT(PageUptodate(page)); set_page_dirty(page); if (PageDirty(page)) _debug("dirtied"); - ret = copied; -out: unlock_page(page); put_page(page); - return ret; + return copied; } /* From patchwork Mon Jul 13 16:39:07 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Howells X-Patchwork-Id: 11660701 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 833F014DD for ; Mon, 13 Jul 2020 16:39:22 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 6BC90206F5 for ; Mon, 13 Jul 2020 16:39:22 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="goHkOIOY" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730754AbgGMQjU (ORCPT ); Mon, 13 Jul 2020 12:39:20 -0400 Received: from us-smtp-2.mimecast.com ([205.139.110.61]:24087 "EHLO us-smtp-delivery-1.mimecast.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1730547AbgGMQjU (ORCPT ); Mon, 13 Jul 2020 12:39:20 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1594658358; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=q/UEZJh6DxJYQ3NJ0rsCIBC20umyEHBIxGnpwbS930w=; b=goHkOIOYNCmpPhcqMekVBwZ8yrEMevIHEPHt2q0nJ5MgRLfki8Y5DX1xN2c6HwidFJimEF GlH7Y3avnNxOh/+bhDVHDegkPemrPBfruaaFkFNtzT1osGvk/7nmnsgV0SlEhdZ+qV/Y7v N94rLMGIUI5R9S2x+0ydD867XyVuFI8= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-294-_j0I8sfdN9yYFVLd3GQOIQ-1; Mon, 13 Jul 2020 12:39:15 -0400 X-MC-Unique: _j0I8sfdN9yYFVLd3GQOIQ-1 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id B9C5980040A; Mon, 13 Jul 2020 16:39:13 +0000 (UTC) Received: from warthog.procyon.org.uk (ovpn-112-113.rdu2.redhat.com [10.10.112.113]) by smtp.corp.redhat.com (Postfix) with ESMTP id 2FD1B5D9CC; Mon, 13 Jul 2020 16:39:08 +0000 (UTC) Organization: Red Hat UK Ltd. Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SI4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 3798903 Subject: [PATCH 11/13] afs: Copy local writes to the cache when writing to the server From: David Howells To: Trond Myklebust , Anna Schumaker , Steve French , Alexander Viro , Matthew Wilcox Cc: Jeff Layton , Dave Wysochanski , dhowells@redhat.com, linux-cachefs@redhat.com, linux-afs@lists.infradead.org, linux-nfs@vger.kernel.org, linux-cifs@vger.kernel.org, ceph-devel@vger.kernel.org, v9fs-developer@lists.sourceforge.net, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Date: Mon, 13 Jul 2020 17:39:07 +0100 Message-ID: <159465834740.1377938.16996503111636748338.stgit@warthog.procyon.org.uk> In-Reply-To: <159465821598.1377938.2046362270225008168.stgit@warthog.procyon.org.uk> References: <159465821598.1377938.2046362270225008168.stgit@warthog.procyon.org.uk> User-Agent: StGit/0.22 MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 Sender: linux-nfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org When writing to the server from afs_writepage() or afs_writepages(), copy the data to the cache object too. Signed-off-by: David Howells --- fs/afs/write.c | 132 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 128 insertions(+), 4 deletions(-) diff --git a/fs/afs/write.c b/fs/afs/write.c index cb27027c06bb..10c60837775e 100644 --- a/fs/afs/write.c +++ b/fs/afs/write.c @@ -13,6 +13,9 @@ #include #include "internal.h" +static void afs_write_to_cache(struct afs_vnode *vnode, + pgoff_t start, pgoff_t end, loff_t a, loff_t b); + /* * mark a page as having been made dirty and thus needing writeback */ @@ -427,6 +430,8 @@ static int afs_write_back_from_locked_page(struct address_space *mapping, count = 1; if (test_set_page_writeback(primary_page)) BUG(); + if (TestSetPageFsCache(primary_page)) + BUG(); /* Find all consecutive lockable dirty pages that have contiguous * written regions, stopping when we find a page that is not @@ -475,7 +480,8 @@ static int afs_write_back_from_locked_page(struct address_space *mapping, break; if (!trylock_page(page)) break; - if (!PageDirty(page) || PageWriteback(page)) { + if (!PageDirty(page) || PageWriteback(page) || + PageFsCache(page)) { unlock_page(page); break; } @@ -497,6 +503,8 @@ static int afs_write_back_from_locked_page(struct address_space *mapping, BUG(); if (test_set_page_writeback(page)) BUG(); + if (TestSetPageFsCache(page)) + BUG(); unlock_page(page); put_page(page); } @@ -534,6 +542,11 @@ static int afs_write_back_from_locked_page(struct address_space *mapping, end = i_size; if (pos < i_size) { + /* Speculatively write to the cache. We have to fix this up + * later if the store fails. + */ + afs_write_to_cache(vnode, first, last, pos, end); + iov_iter_mapping(&iter, WRITE, mapping, pos, end - pos); ret = afs_store_data(vnode, &iter, pos, first, last); } else { @@ -592,6 +605,10 @@ int afs_writepage(struct page *page, struct writeback_control *wbc) _enter("{%lx},", page->index); +#ifdef CONFIG_AFS_FSCACHE + wait_on_page_fscache(page); +#endif + ret = afs_write_back_from_locked_page(page->mapping, wbc, page, wbc->range_end >> PAGE_SHIFT); if (ret < 0) { @@ -619,7 +636,7 @@ static int afs_writepages_region(struct address_space *mapping, do { n = find_get_pages_range_tag(mapping, &index, end, - PAGECACHE_TAG_DIRTY, 1, &page); + PAGECACHE_TAG_DIRTY, 1, &page); if (!n) break; @@ -644,10 +661,14 @@ static int afs_writepages_region(struct address_space *mapping, continue; } - if (PageWriteback(page)) { + if (PageWriteback(page) || PageFsCache(page)) { unlock_page(page); - if (wbc->sync_mode != WB_SYNC_NONE) + if (wbc->sync_mode != WB_SYNC_NONE) { wait_on_page_writeback(page); +#ifdef CONFIG_AFS_FSCACHE + wait_on_page_fscache(page); +#endif + } put_page(page); continue; } @@ -868,3 +889,106 @@ int afs_launder_page(struct page *page) ClearPagePrivate(page); return ret; } + +/* + * Clear the PG_fscache flag from a sequence of pages and wake up anyone who's + * waiting. The last page is included in the sequence. + */ +static void afs_clear_fscache_bits(struct address_space *mapping, + pgoff_t start, pgoff_t last) +{ + struct page *page; + + XA_STATE(xas, &mapping->i_pages, start); + + rcu_read_lock(); + xas_for_each(&xas, page, last) { + unlock_page_fscache(page); + } + rcu_read_unlock(); +} + +/* + * Deal with the completion of writing the data to the cache. + */ +static void afs_write_to_cache_done(struct fscache_io_request *_req) +{ + struct afs_read *req = container_of(_req, struct afs_read, cache); + pgoff_t index = req->cache.pos >> PAGE_SHIFT; + pgoff_t last = index + req->cache.nr_pages - 1; + + _enter("%lx,%x,%llx", index, req->cache.nr_pages, req->cache.transferred); + + afs_clear_fscache_bits(req->cache.mapping, index, last); + + if (req->cache.error && req->cache.error != -ENOBUFS) { + struct afs_vnode *vnode = req->vnode; + struct afs_vnode_cache_aux aux = { + .data_version = vnode->status.data_version, + }; + _debug("inval wr %d", req->cache.error); + fscache_invalidate(req->cache.cookie, &aux, + i_size_read(&vnode->vfs_inode), 0); + } +} + +static const struct fscache_io_request_ops afs_write_req_ops = { + .get = afs_req_get, + .put = afs_req_put, +}; + +/* + * Save the write to the cache also. + */ +static void afs_write_to_cache(struct afs_vnode *vnode, + pgoff_t start, pgoff_t last, loff_t a, loff_t b) +{ + struct afs_read *req; + struct iov_iter iter; + + struct fscache_request_shape shape = { + .proposed_start = start, + .proposed_nr_pages = last - start + 1, + .max_io_pages = UINT_MAX, + .i_size = i_size_read(&vnode->vfs_inode), + .for_write = true, + }; + + _enter("%lx,%lx,%llx,%llx", start, last, a, b); + + fscache_shape_request(afs_vnode_cache(vnode), &shape); + if (!(shape.to_be_done & FSCACHE_WRITE_TO_CACHE) || + shape.actual_nr_pages == 0 || + shape.actual_start != start) + goto abandon; + + if (shape.actual_nr_pages < shape.proposed_nr_pages) { + afs_clear_fscache_bits(vnode->vfs_inode.i_mapping, + start + shape.actual_nr_pages, + start + shape.proposed_nr_pages - 1); + last = start + shape.actual_nr_pages - 1; + b = (loff_t)(last + 1) << PAGE_SHIFT; + } + + req = afs_alloc_read(GFP_NOFS); + if (!req) + goto abandon; + + fscache_init_io_request(&req->cache, afs_vnode_cache(vnode), + &afs_write_req_ops); + req->vnode = vnode; + req->cache.pos = round_down(a, shape.dio_block_size); + req->cache.len = round_up(b, shape.dio_block_size) - req->cache.pos; + req->cache.nr_pages = shape.actual_nr_pages; + req->cache.mapping = vnode->vfs_inode.i_mapping; + req->cache.io_done = &afs_write_to_cache_done; + + iov_iter_mapping(&iter, WRITE, req->cache.mapping, + req->cache.pos, req->cache.len); + fscache_write(&req->cache, &iter); + afs_put_read(req); + return; + +abandon: + afs_clear_fscache_bits(vnode->vfs_inode.i_mapping, start, last); +} From patchwork Mon Jul 13 16:39:18 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Howells X-Patchwork-Id: 11660713 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id ECAC913B4 for ; Mon, 13 Jul 2020 16:39:36 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id D4D1F206F5 for ; Mon, 13 Jul 2020 16:39:36 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="DsW52XOz" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730633AbgGMQje (ORCPT ); Mon, 13 Jul 2020 12:39:34 -0400 Received: from us-smtp-2.mimecast.com ([205.139.110.61]:57382 "EHLO us-smtp-delivery-1.mimecast.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1730815AbgGMQjc (ORCPT ); Mon, 13 Jul 2020 12:39:32 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1594658371; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=oaCTdM19WMNtk5n7WfsDY0jjk79XuarMYPGTkLXDeKs=; b=DsW52XOz5XFGVwY8ILOVu9we4YIZWYWzor2VYKscKUYrofq/jQGRhicjDO1igwhhv+74uq +FoPrwizS8VdfZssdyGVSa4ngqjUdDCAhJKVg35HNSCmozPtLV/mXI833AciWWjV8jjJwx MqNCKFHXaN6/28hAAw+Jk+GrRC6MYe0= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-380-A6iXCXkrPfe5d0m4hJIjuQ-1; Mon, 13 Jul 2020 12:39:27 -0400 X-MC-Unique: A6iXCXkrPfe5d0m4hJIjuQ-1 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 6DE988015CB; Mon, 13 Jul 2020 16:39:25 +0000 (UTC) Received: from warthog.procyon.org.uk (ovpn-112-113.rdu2.redhat.com [10.10.112.113]) by smtp.corp.redhat.com (Postfix) with ESMTP id C831660BF3; Mon, 13 Jul 2020 16:39:19 +0000 (UTC) Organization: Red Hat UK Ltd. Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SI4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 3798903 Subject: [PATCH 12/13] afs: Invoke fscache_resize_cookie() when handling ATTR_SIZE for setattr From: David Howells To: Trond Myklebust , Anna Schumaker , Steve French , Alexander Viro , Matthew Wilcox Cc: Jeff Layton , Dave Wysochanski , dhowells@redhat.com, linux-cachefs@redhat.com, linux-afs@lists.infradead.org, linux-nfs@vger.kernel.org, linux-cifs@vger.kernel.org, ceph-devel@vger.kernel.org, v9fs-developer@lists.sourceforge.net, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Date: Mon, 13 Jul 2020 17:39:18 +0100 Message-ID: <159465835897.1377938.1598226019201611820.stgit@warthog.procyon.org.uk> In-Reply-To: <159465821598.1377938.2046362270225008168.stgit@warthog.procyon.org.uk> References: <159465821598.1377938.2046362270225008168.stgit@warthog.procyon.org.uk> User-Agent: StGit/0.22 MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 Sender: linux-nfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org Invoke fscache_resize_cookie() to adjust the size of the backing cache object when setattr is called with ATTR_SIZE. This discards any data that then lies beyond the revised EOF and frees up space. Signed-off-by: David Howells --- fs/afs/inode.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/fs/afs/inode.c b/fs/afs/inode.c index eab191b9c01d..baaaa5e55f95 100644 --- a/fs/afs/inode.c +++ b/fs/afs/inode.c @@ -815,14 +815,19 @@ void afs_evict_inode(struct inode *inode) static void afs_setattr_success(struct afs_operation *op) { - struct inode *inode = &op->file[0].vnode->vfs_inode; + struct afs_vnode_param *vp = &op->file[0]; + struct inode *inode = &vp->vnode->vfs_inode; - afs_vnode_commit_status(op, &op->file[0]); + afs_vnode_commit_status(op, vp); if (op->setattr.attr->ia_valid & ATTR_SIZE) { loff_t i_size = inode->i_size, size = op->setattr.attr->ia_size; + if (size > i_size) pagecache_isize_extended(inode, i_size, size); truncate_pagecache(inode, size); + + fscache_resize_cookie(afs_vnode_cache(vp->vnode), + vp->scb.status.size); } } @@ -864,6 +869,8 @@ int afs_setattr(struct dentry *dentry, struct iattr *attr) attr->ia_valid &= ~ATTR_SIZE; } + fscache_use_cookie(afs_vnode_cache(vnode), true); + /* flush any dirty data outstanding on a regular file */ if (S_ISREG(vnode->vfs_inode.i_mode)) filemap_write_and_wait(vnode->vfs_inode.i_mapping); @@ -871,8 +878,10 @@ int afs_setattr(struct dentry *dentry, struct iattr *attr) op = afs_alloc_operation(((attr->ia_valid & ATTR_FILE) ? afs_file_key(attr->ia_file) : NULL), vnode->volume); - if (IS_ERR(op)) - return PTR_ERR(op); + if (IS_ERR(op)) { + ret = PTR_ERR(op); + goto error_unuse; + } afs_op_set_vnode(op, 0, vnode); op->setattr.attr = attr; @@ -885,5 +894,10 @@ int afs_setattr(struct dentry *dentry, struct iattr *attr) op->file[0].update_ctime = 1; op->ops = &afs_setattr_operation; - return afs_do_sync_operation(op); + ret = afs_do_sync_operation(op); + +error_unuse: + fscache_unuse_cookie(afs_vnode_cache(vnode), NULL, NULL); + _leave(" = %d", ret); + return ret; } From patchwork Mon Jul 13 16:39:30 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Howells X-Patchwork-Id: 11660719 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 6F5986C1 for ; Mon, 13 Jul 2020 16:39:50 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 401262067D for ; Mon, 13 Jul 2020 16:39:50 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="LdVtWo+R" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729990AbgGMQjt (ORCPT ); Mon, 13 Jul 2020 12:39:49 -0400 Received: from us-smtp-2.mimecast.com ([205.139.110.61]:52895 "EHLO us-smtp-delivery-1.mimecast.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1730386AbgGMQjn (ORCPT ); Mon, 13 Jul 2020 12:39:43 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1594658380; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ZltF3kTtRDCqeiMAKnWdkROIh1F0y4ZuBnVQ0RqDrdI=; b=LdVtWo+RCJIB9mO1BUDEkea7cw2nwLNbT4D/S/tYQPRQZFrH9VBbqVpf7p4uuucVoT5Kpo TWuTaI/jDbU1Rs5dQp4Co+H7BfFFsownOa9k8aIQYt/705gxE+0dzMd9TWtSB4JdkvWoPi aqEqgE0XLzLj7F18PEpGvV1l8VukTco= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-426-HML89eGQOUm5MGBgYTDxLA-1; Mon, 13 Jul 2020 12:39:39 -0400 X-MC-Unique: HML89eGQOUm5MGBgYTDxLA-1 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 46AE7800400; Mon, 13 Jul 2020 16:39:37 +0000 (UTC) Received: from warthog.procyon.org.uk (ovpn-112-113.rdu2.redhat.com [10.10.112.113]) by smtp.corp.redhat.com (Postfix) with ESMTP id 7FF2072E41; Mon, 13 Jul 2020 16:39:31 +0000 (UTC) Organization: Red Hat UK Ltd. Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SI4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 3798903 Subject: [PATCH 13/13] afs: Add O_DIRECT read support From: David Howells To: Trond Myklebust , Anna Schumaker , Steve French , Alexander Viro , Matthew Wilcox Cc: Jeff Layton , Dave Wysochanski , dhowells@redhat.com, linux-cachefs@redhat.com, linux-afs@lists.infradead.org, linux-nfs@vger.kernel.org, linux-cifs@vger.kernel.org, ceph-devel@vger.kernel.org, v9fs-developer@lists.sourceforge.net, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Date: Mon, 13 Jul 2020 17:39:30 +0100 Message-ID: <159465837067.1377938.13569650454944979305.stgit@warthog.procyon.org.uk> In-Reply-To: <159465821598.1377938.2046362270225008168.stgit@warthog.procyon.org.uk> References: <159465821598.1377938.2046362270225008168.stgit@warthog.procyon.org.uk> User-Agent: StGit/0.22 MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 Sender: linux-nfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org Add synchronous O_DIRECT read support to AFS (no AIO yet). It can theoretically handle reads up to the maximum size describable by loff_t - and given an iterator with sufficiently capacity to handle that and given support on the server. Signed-off-by: David Howells --- fs/afs/file.c | 59 +++++++++++++++++++++++++++++++++++++++ fs/afs/fsclient.c | 18 +++++++++--- fs/afs/internal.h | 2 + fs/afs/write.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++------ fs/afs/yfsclient.c | 12 +++++--- mm/filemap.c | 9 +++++- 6 files changed, 159 insertions(+), 19 deletions(-) diff --git a/fs/afs/file.c b/fs/afs/file.c index 5aa7b89e7359..0ee0e94ba042 100644 --- a/fs/afs/file.c +++ b/fs/afs/file.c @@ -24,6 +24,7 @@ static int afs_releasepage(struct page *page, gfp_t gfp_flags); static int afs_readpages(struct file *filp, struct address_space *mapping, struct list_head *pages, unsigned nr_pages); +static ssize_t afs_direct_IO(struct kiocb *iocb, struct iov_iter *iter); const struct file_operations afs_file_operations = { .open = afs_open, @@ -52,6 +53,7 @@ const struct address_space_operations afs_fs_aops = { .launder_page = afs_launder_page, .releasepage = afs_releasepage, .invalidatepage = afs_invalidatepage, + .direct_IO = afs_direct_IO, .write_begin = afs_write_begin, .write_end = afs_write_end, .writepage = afs_writepage, @@ -586,3 +588,60 @@ static int afs_file_mmap(struct file *file, struct vm_area_struct *vma) vma->vm_ops = &afs_vm_ops; return ret; } + +/* + * Direct file read operation for an AFS file. + * + * TODO: To support AIO, the pages in the iterator have to be copied and + * refs taken on them. Then -EIOCBQUEUED needs to be returned. + * iocb->ki_complete must then be called upon completion of the operation. + */ +static ssize_t afs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter) +{ + struct file *file = iocb->ki_filp; + struct afs_vnode *vnode = AFS_FS_I(file_inode(file)); + struct afs_read *req; + ssize_t ret, transferred; + + _enter("%llx,%zx", iocb->ki_pos, iov_iter_count(iter)); + + req = afs_alloc_read(GFP_KERNEL); + if (!req) + return -ENOMEM; + + req->vnode = vnode; + req->key = key_get(afs_file_key(file)); + req->cache.pos = iocb->ki_pos; + req->cache.len = iov_iter_count(iter); + req->iter = iter; + + task_io_account_read(req->cache.len); + + // TODO nfs_start_io_direct(inode); + ret = afs_fetch_data(vnode, req); + if (ret == 0) + transferred = req->cache.transferred; + afs_put_read(req); + + // TODO nfs_end_io_direct(inode); + + if (ret == 0) + ret = transferred; + + BUG_ON(ret == -EIOCBQUEUED); // TODO + //if (iocb->ki_complete) + // iocb->ki_complete(iocb, ret, 0); // only if ret == -EIOCBQUEUED + + _leave(" = %zu", ret); + return ret; +} + +/* + * Do direct I/O. + */ +static ssize_t afs_direct_IO(struct kiocb *iocb, struct iov_iter *iter) +{ + if (iov_iter_rw(iter) == READ) + return afs_file_direct_read(iocb, iter); + return afs_file_direct_write(iocb, iter); +} diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c index e729a19f28c5..1d0465654256 100644 --- a/fs/afs/fsclient.c +++ b/fs/afs/fsclient.c @@ -446,7 +446,7 @@ static void afs_fs_fetch_data64(struct afs_operation *op) bp[3] = htonl(vp->fid.unique); bp[4] = htonl(upper_32_bits(req->cache.pos)); bp[5] = htonl(lower_32_bits(req->cache.pos)); - bp[6] = 0; + bp[6] = htonl(upper_32_bits(req->cache.len)); bp[7] = htonl(lower_32_bits(req->cache.len)); trace_afs_make_fs_call(call, &vp->fid); @@ -1066,6 +1066,7 @@ static void afs_fs_store_data64(struct afs_operation *op) struct afs_vnode_param *vp = &op->file[0]; struct afs_call *call; __be32 *bp; + u32 mask = 0; _enter(",%x,{%llx:%llu},,", key_serial(op->key), vp->fid.vid, vp->fid.vnode); @@ -1078,6 +1079,9 @@ static void afs_fs_store_data64(struct afs_operation *op) call->write_iter = op->store.write_iter; + if (op->flags & AFS_OPERATION_SET_MTIME) + mask |= AFS_SET_MTIME; + /* marshall the parameters */ bp = call->request; *bp++ = htonl(FSSTOREDATA64); @@ -1085,8 +1089,8 @@ static void afs_fs_store_data64(struct afs_operation *op) *bp++ = htonl(vp->fid.vnode); *bp++ = htonl(vp->fid.unique); - *bp++ = htonl(AFS_SET_MTIME); /* mask */ - *bp++ = htonl(op->mtime.tv_sec); /* mtime */ + *bp++ = htonl(mask); + *bp++ = htonl(op->mtime.tv_sec); *bp++ = 0; /* owner */ *bp++ = 0; /* group */ *bp++ = 0; /* unix mode */ @@ -1111,6 +1115,7 @@ void afs_fs_store_data(struct afs_operation *op) struct afs_vnode_param *vp = &op->file[0]; struct afs_call *call; __be32 *bp; + u32 mask = 0; _enter(",%x,{%llx:%llu},,", key_serial(op->key), vp->fid.vid, vp->fid.vnode); @@ -1133,6 +1138,9 @@ void afs_fs_store_data(struct afs_operation *op) call->write_iter = op->store.write_iter; + if (op->flags & AFS_OPERATION_SET_MTIME) + mask |= AFS_SET_MTIME; + /* marshall the parameters */ bp = call->request; *bp++ = htonl(FSSTOREDATA); @@ -1140,8 +1148,8 @@ void afs_fs_store_data(struct afs_operation *op) *bp++ = htonl(vp->fid.vnode); *bp++ = htonl(vp->fid.unique); - *bp++ = htonl(AFS_SET_MTIME); /* mask */ - *bp++ = htonl(op->mtime.tv_sec); /* mtime */ + *bp++ = htonl(mask); + *bp++ = htonl(op->mtime.tv_sec); *bp++ = 0; /* owner */ *bp++ = 0; /* group */ *bp++ = 0; /* unix mode */ diff --git a/fs/afs/internal.h b/fs/afs/internal.h index 8c9abfa33a91..7bb26975080f 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -843,6 +843,7 @@ struct afs_operation { #define AFS_OPERATION_TRIED_ALL 0x0400 /* Set if we've tried all the fileservers */ #define AFS_OPERATION_RETRY_SERVER 0x0800 /* Set if we should retry the current server */ #define AFS_OPERATION_DIR_CONFLICT 0x1000 /* Set if we detected a 3rd-party dir change */ +#define AFS_OPERATION_SET_MTIME 0x2000 /* Set if we should try to store the mtime */ }; /* @@ -1440,6 +1441,7 @@ extern int afs_fsync(struct file *, loff_t, loff_t, int); extern vm_fault_t afs_page_mkwrite(struct vm_fault *vmf); extern void afs_prune_wb_keys(struct afs_vnode *); extern int afs_launder_page(struct page *); +extern ssize_t afs_file_direct_write(struct kiocb *, struct iov_iter *); /* * xattr.c diff --git a/fs/afs/write.c b/fs/afs/write.c index 10c60837775e..14d31adf4825 100644 --- a/fs/afs/write.c +++ b/fs/afs/write.c @@ -377,7 +377,7 @@ static int afs_store_data(struct afs_vnode *vnode, struct iov_iter *iter, op->store.size = size; op->store.i_size = max(pos + size, i_size); op->mtime = vnode->vfs_inode.i_mtime; - op->flags |= AFS_OPERATION_UNINTR; + op->flags |= AFS_OPERATION_SET_MTIME | AFS_OPERATION_UNINTR; op->ops = &afs_store_data_operation; try_next_key: @@ -732,7 +732,6 @@ int afs_writepages(struct address_space *mapping, ssize_t afs_file_write(struct kiocb *iocb, struct iov_iter *from) { struct afs_vnode *vnode = AFS_FS_I(file_inode(iocb->ki_filp)); - ssize_t result; size_t count = iov_iter_count(from); _enter("{%llx:%llu},{%zu},", @@ -744,13 +743,7 @@ ssize_t afs_file_write(struct kiocb *iocb, struct iov_iter *from) return -EBUSY; } - if (!count) - return 0; - - result = generic_file_write_iter(iocb, from); - - _leave(" = %zd", result); - return result; + return generic_file_write_iter(iocb, from); } /* @@ -992,3 +985,70 @@ static void afs_write_to_cache(struct afs_vnode *vnode, abandon: afs_clear_fscache_bits(vnode->vfs_inode.i_mapping, start, last); } + +static void afs_dio_store_data_success(struct afs_operation *op) +{ + struct afs_vnode *vnode = op->file[0].vnode; + + op->ctime = op->file[0].scb.status.mtime_client; + afs_vnode_commit_status(op, &op->file[0]); + if (op->error == 0) { + afs_stat_v(vnode, n_stores); + atomic_long_add(op->store.size, &afs_v2net(vnode)->n_store_bytes); + } +} + +static const struct afs_operation_ops afs_dio_store_data_operation = { + .issue_afs_rpc = afs_fs_store_data, + .issue_yfs_rpc = yfs_fs_store_data, + .success = afs_dio_store_data_success, +}; + +/* + * Direct file write operation for an AFS file. + * + * TODO: To support AIO, the pages in the iterator have to be copied and + * refs taken on them. Then -EIOCBQUEUED needs to be returned. + * iocb->ki_complete must then be called upon completion of the operation. + */ +ssize_t afs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter) +{ + struct file *file = iocb->ki_filp; + struct afs_vnode *vnode = AFS_FS_I(file_inode(file)); + struct afs_operation *op; + loff_t size = iov_iter_count(iter), i_size; + ssize_t ret; + + _enter("%s{%llx:%llu.%u},%llx,%llx", + vnode->volume->name, + vnode->fid.vid, + vnode->fid.vnode, + vnode->fid.unique, + size, iocb->ki_pos); + + op = afs_alloc_operation(afs_file_key(file), vnode->volume); + if (IS_ERR(op)) + return -ENOMEM; + + i_size = i_size_read(&vnode->vfs_inode); + + afs_op_set_vnode(op, 0, vnode); + op->file[0].dv_delta = 1; + op->store.write_iter = iter; + op->store.pos = iocb->ki_pos; + op->store.size = size; + op->store.i_size = max(iocb->ki_pos + size, i_size); + op->ops = &afs_dio_store_data_operation; + + //if (!is_sync_kiocb(iocb)) { + + ret = afs_do_sync_operation(op); + if (ret == 0) + ret = size; + + //if (iocb->ki_complete) + // iocb->ki_complete(iocb, ret, 0); // only if ret == -EIOCBQUEUED + + _leave(" = %zd", ret); + return ret; +} diff --git a/fs/afs/yfsclient.c b/fs/afs/yfsclient.c index 4ead0c1f9014..04c285e6b4ed 100644 --- a/fs/afs/yfsclient.c +++ b/fs/afs/yfsclient.c @@ -95,12 +95,16 @@ static __be32 *xdr_encode_YFSStoreStatus_mode(__be32 *bp, mode_t mode) return bp + xdr_size(x); } -static __be32 *xdr_encode_YFSStoreStatus_mtime(__be32 *bp, const struct timespec64 *t) +static __be32 *xdr_encode_YFSStoreStatus_mtime(__be32 *bp, struct afs_operation *op) { struct yfs_xdr_YFSStoreStatus *x = (void *)bp; - s64 mtime = linux_to_yfs_time(t); + s64 mtime = linux_to_yfs_time(&op->mtime); + u32 mask = 0; - x->mask = htonl(AFS_SET_MTIME); + if (op->flags & AFS_OPERATION_SET_MTIME) + mask |= AFS_SET_MTIME; + + x->mask = htonl(mask); x->mode = htonl(0); x->mtime_client = u64_to_xdr(mtime); x->owner = u64_to_xdr(0); @@ -1112,7 +1116,7 @@ void yfs_fs_store_data(struct afs_operation *op) bp = xdr_encode_u32(bp, YFSSTOREDATA64); bp = xdr_encode_u32(bp, 0); /* RPC flags */ bp = xdr_encode_YFSFid(bp, &vp->fid); - bp = xdr_encode_YFSStoreStatus_mtime(bp, &op->mtime); + bp = xdr_encode_YFSStoreStatus_mtime(bp, op); bp = xdr_encode_u64(bp, op->store.pos); bp = xdr_encode_u64(bp, op->store.size); bp = xdr_encode_u64(bp, op->store.i_size); diff --git a/mm/filemap.c b/mm/filemap.c index 4894e9705d34..6c52de0674eb 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -3245,7 +3245,14 @@ generic_file_direct_write(struct kiocb *iocb, struct iov_iter *from) } iocb->ki_pos = pos; } - iov_iter_revert(from, write_len - iov_iter_count(from)); + { + size_t unroll = write_len - iov_iter_count(from); + if (unroll > MAX_RW_COUNT) + pr_warn("XXX unroll %zd [%zd - %zd]", + unroll, write_len, iov_iter_count(from)); + else + iov_iter_revert(from, unroll); + } out: return written; }