Received: by 2002:ac0:a5b6:0:0:0:0:0 with SMTP id m51-v6csp3502468imm; Tue, 29 May 2018 08:18:22 -0700 (PDT) X-Google-Smtp-Source: ADUXVKJzJSE1d2PtCcZegSBkPpJy2xk+ai2kT6rJ1KkA7/fbLARwfB0Lc2rEfywuchMYsgyow/3X X-Received: by 2002:a62:9652:: with SMTP id c79-v6mr5829229pfe.114.1527607102637; Tue, 29 May 2018 08:18:22 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1527607102; cv=none; d=google.com; s=arc-20160816; b=nl+eQs19ad5W6BtxTDji0/T9X5bHRhyNH6n8gNCK/5WUEh06lIQ1cOvM+dVPJVpRb2 OaT3rw8mjKMf1JLJ9CxzCYhdSjWZilcbNdgpI9NMH4l9fbXl15LMoDvzbm2M8k92EJw+ 7nG+ffiAS2adPEfLYrBg2Le0LGcRFcx4Fn7P+SsIjT6mw3bwO0/4haCuC15lAH8K36gi LxhEANoK4t1tefm+XLJfS+27QszwYYcbTTRYbTumWDN5NXn4zo0xAFEDD6Jt9dtPDyK3 Hp5hIyofWKd8CsGhq8liipVM815mf35YH1p8LbZYD3x4TDwHZ5TwmcVDzucwizazhYTI +RNA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:arc-authentication-results; bh=9XEyOYwD6AINU8nJ4Gqb0FvjfhwyWT8eLqF5WegfqPU=; b=rkHSidy4d8Q2DZ+psmYxHMRc/HjsmsnVR2Etil568uF3Zd1VLFKcVvSL6w4r3svTdq QrKIJOqYX7vlWKsMpU2/DiZS6xA0aPefS8/jXNHpIoQPB1lRPQy1IP5SL06ypAhMgReC WkTJ2o7xU9dTFENQjC/pDRjmCW9INPSXnmjYQHK9mRfhW5iv87oGmsecAIpS/FRExQ0w zKoio3f/OjS/U36+XDZUYIHSxKQ6GYZM6ll8cGTVR4/2ZUamM9KHOiqWimQBNEo1Evpg E+6ft8McilT+6p4iOkrtgQg7Z5ZMJWGC+lKTYWQAj8M9p8LSJQZaJ3pl10WW5HNUvU3y ZlpQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=redhat.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id 82-v6si8456648pgh.144.2018.05.29.08.18.08; Tue, 29 May 2018 08:18:22 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S935418AbeE2OnH (ORCPT + 99 others); Tue, 29 May 2018 10:43:07 -0400 Received: from mail-wr0-f194.google.com ([209.85.128.194]:44163 "EHLO mail-wr0-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S934933AbeE2Ol7 (ORCPT ); Tue, 29 May 2018 10:41:59 -0400 Received: by mail-wr0-f194.google.com with SMTP id y15-v6so25968107wrg.11 for ; Tue, 29 May 2018 07:41:59 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=9XEyOYwD6AINU8nJ4Gqb0FvjfhwyWT8eLqF5WegfqPU=; b=S0Bd7E8lDl8pCnwWHsHdY+MXYAN0FxGA+VXdPuB3C9S7A1YkS+S/fsH9K+ZHAayLrj MUX1JvtWi7090Ov4Ca9cl7uEfDOfICNJOKxCB9z+MFQPKjPUrGxJY8EAecjelZYpSmVp AtrBFWB+l8OIMeASKJnwZTBTo5NrLRReKflyVfZGiLkNwpvdv6LK3q7ThaXNYFf83o61 dbRusOaqoLWh2whOQaIpZKmFkLbafydOuAnYbFuNb9le5x/aWGR++g6ibkgUfhtQPuBj 9jdTbs+LDJ9hrr0Lh8hdHBNb6vFjIRiTqPsGWOIcYwrmroZSMn57U2yfec7Xw23KDTgU Z4tw== X-Gm-Message-State: ALKqPwdV06YZInEzqE3+ZxJYmUmG5P5ZpOkInk/PGlxMjysTVXQpC2NF 4dnbQEBvS9RjydGPH1EQhXPazw== X-Received: by 2002:adf:e9c3:: with SMTP id l3-v6mr15345843wrn.195.1527604918540; Tue, 29 May 2018 07:41:58 -0700 (PDT) Received: from veci.piliscsaba.redhat.com (catv-176-63-54-97.catv.broadband.hu. [176.63.54.97]) by smtp.gmail.com with ESMTPSA id q17-v6sm12572113wmf.3.2018.05.29.07.41.57 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Tue, 29 May 2018 07:41:57 -0700 (PDT) From: Miklos Szeredi To: linux-unionfs@vger.kernel.org Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 09/11] vfs: factor out inode_insert5() Date: Tue, 29 May 2018 16:41:41 +0200 Message-Id: <20180529144143.16378-10-mszeredi@redhat.com> X-Mailer: git-send-email 2.14.3 In-Reply-To: <20180529144143.16378-1-mszeredi@redhat.com> References: <20180529144143.16378-1-mszeredi@redhat.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Miklos Szeredi Split out common helper for race free insertion of an already allocated inode into the cache. Use this from iget5_locked() and insert_inode_locked4(). Make iget5_locked() use new_inode()/iput() instead of alloc_inode()/destroy_inode() directly. Also export to modules for use by filesystems which want to preallocate an inode before file/directory creation. Signed-off-by: Amir Goldstein Signed-off-by: Miklos Szeredi --- fs/inode.c | 164 ++++++++++++++++++++++++----------------------------- include/linux/fs.h | 4 ++ 2 files changed, 79 insertions(+), 89 deletions(-) diff --git a/fs/inode.c b/fs/inode.c index 13ceb98c3bd3..1bea65d37afe 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -1002,6 +1002,70 @@ void unlock_two_nondirectories(struct inode *inode1, struct inode *inode2) } EXPORT_SYMBOL(unlock_two_nondirectories); +/** + * inode_insert5 - obtain an inode from a mounted file system + * @inode: pre-allocated inode to use for insert to cache + * @hashval: hash value (usually inode number) to get + * @test: callback used for comparisons between inodes + * @set: callback used to initialize a new struct inode + * @data: opaque data pointer to pass to @test and @set + * + * Search for the inode specified by @hashval and @data in the inode cache, + * and if present it is return it with an increased reference count. This is + * a variant of iget5_locked() for callers that don't want to fail on memory + * allocation of inode. + * + * If the inode is not in cache, insert the pre-allocated inode to cache and + * return it locked, hashed, and with the I_NEW flag set. The file system gets + * to fill it in before unlocking it via unlock_new_inode(). + * + * Note both @test and @set are called with the inode_hash_lock held, so can't + * sleep. + */ +struct inode *inode_insert5(struct inode *inode, unsigned long hashval, + int (*test)(struct inode *, void *), + int (*set)(struct inode *, void *), void *data) +{ + struct hlist_head *head = inode_hashtable + hash(inode->i_sb, hashval); + struct inode *old; + +again: + spin_lock(&inode_hash_lock); + old = find_inode(inode->i_sb, head, test, data); + if (unlikely(old)) { + /* + * Uhhuh, somebody else created the same inode under us. + * Use the old inode instead of the preallocated one. + */ + spin_unlock(&inode_hash_lock); + wait_on_inode(old); + if (unlikely(inode_unhashed(old))) { + iput(old); + goto again; + } + return old; + } + + if (set && unlikely(set(inode, data))) { + inode = NULL; + goto unlock; + } + + /* + * Return the locked inode with I_NEW set, the + * caller is responsible for filling in the contents + */ + spin_lock(&inode->i_lock); + inode->i_state |= I_NEW; + hlist_add_head(&inode->i_hash, head); + spin_unlock(&inode->i_lock); +unlock: + spin_unlock(&inode_hash_lock); + + return inode; +} +EXPORT_SYMBOL(inode_insert5); + /** * iget5_locked - obtain an inode from a mounted file system * @sb: super block of file system @@ -1026,66 +1090,18 @@ struct inode *iget5_locked(struct super_block *sb, unsigned long hashval, int (*test)(struct inode *, void *), int (*set)(struct inode *, void *), void *data) { - struct hlist_head *head = inode_hashtable + hash(sb, hashval); - struct inode *inode; -again: - spin_lock(&inode_hash_lock); - inode = find_inode(sb, head, test, data); - spin_unlock(&inode_hash_lock); + struct inode *inode = ilookup5(sb, hashval, test, data); - if (inode) { - wait_on_inode(inode); - if (unlikely(inode_unhashed(inode))) { - iput(inode); - goto again; - } - return inode; - } + if (!inode) { + struct inode *new = new_inode(sb); - inode = alloc_inode(sb); - if (inode) { - struct inode *old; - - spin_lock(&inode_hash_lock); - /* We released the lock, so.. */ - old = find_inode(sb, head, test, data); - if (!old) { - if (set(inode, data)) - goto set_failed; - - spin_lock(&inode->i_lock); - inode->i_state = I_NEW; - hlist_add_head(&inode->i_hash, head); - spin_unlock(&inode->i_lock); - inode_sb_list_add(inode); - spin_unlock(&inode_hash_lock); - - /* Return the locked inode with I_NEW set, the - * caller is responsible for filling in the contents - */ - return inode; - } - - /* - * Uhhuh, somebody else created the same inode under - * us. Use the old inode instead of the one we just - * allocated. - */ - spin_unlock(&inode_hash_lock); - destroy_inode(inode); - inode = old; - wait_on_inode(inode); - if (unlikely(inode_unhashed(inode))) { - iput(inode); - goto again; + if (new) { + inode = inode_insert5(new, hashval, test, set, data); + if (unlikely(inode != new)) + iput(new); } } return inode; - -set_failed: - spin_unlock(&inode_hash_lock); - destroy_inode(inode); - return NULL; } EXPORT_SYMBOL(iget5_locked); @@ -1426,43 +1442,13 @@ EXPORT_SYMBOL(insert_inode_locked); int insert_inode_locked4(struct inode *inode, unsigned long hashval, int (*test)(struct inode *, void *), void *data) { - struct super_block *sb = inode->i_sb; - struct hlist_head *head = inode_hashtable + hash(sb, hashval); + struct inode *old = inode_insert5(inode, hashval, test, NULL, data); - while (1) { - struct inode *old = NULL; - - spin_lock(&inode_hash_lock); - hlist_for_each_entry(old, head, i_hash) { - if (old->i_sb != sb) - continue; - if (!test(old, data)) - continue; - spin_lock(&old->i_lock); - if (old->i_state & (I_FREEING|I_WILL_FREE)) { - spin_unlock(&old->i_lock); - continue; - } - break; - } - if (likely(!old)) { - spin_lock(&inode->i_lock); - inode->i_state |= I_NEW; - hlist_add_head(&inode->i_hash, head); - spin_unlock(&inode->i_lock); - spin_unlock(&inode_hash_lock); - return 0; - } - __iget(old); - spin_unlock(&old->i_lock); - spin_unlock(&inode_hash_lock); - wait_on_inode(old); - if (unlikely(!inode_unhashed(old))) { - iput(old); - return -EBUSY; - } + if (old != inode) { iput(old); + return -EBUSY; } + return 0; } EXPORT_SYMBOL(insert_inode_locked4); diff --git a/include/linux/fs.h b/include/linux/fs.h index 760d8da1b6c7..4f637a9b213d 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2879,6 +2879,10 @@ extern struct inode *ilookup5(struct super_block *sb, unsigned long hashval, int (*test)(struct inode *, void *), void *data); extern struct inode *ilookup(struct super_block *sb, unsigned long ino); +extern struct inode *inode_insert5(struct inode *inode, unsigned long hashval, + int (*test)(struct inode *, void *), + int (*set)(struct inode *, void *), + void *data); extern struct inode * iget5_locked(struct super_block *, unsigned long, int (*test)(struct inode *, void *), int (*set)(struct inode *, void *), void *); extern struct inode * iget_locked(struct super_block *, unsigned long); extern struct inode *find_inode_nowait(struct super_block *, -- 2.14.3