From patchwork Tue Nov 22 08:25:02 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Omar Sandoval X-Patchwork-Id: 9440605 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id E3D7860237 for ; Tue, 22 Nov 2016 08:25:27 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id DA3FB28480 for ; Tue, 22 Nov 2016 08:25:27 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id CE9A928482; Tue, 22 Nov 2016 08:25:27 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI,T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 5FE4528480 for ; Tue, 22 Nov 2016 08:25:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755448AbcKVIZZ (ORCPT ); Tue, 22 Nov 2016 03:25:25 -0500 Received: from mail-pg0-f41.google.com ([74.125.83.41]:34640 "EHLO mail-pg0-f41.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755544AbcKVIZX (ORCPT ); Tue, 22 Nov 2016 03:25:23 -0500 Received: by mail-pg0-f41.google.com with SMTP id x23so5374288pgx.1 for ; Tue, 22 Nov 2016 00:25:22 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=osandov-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :in-reply-to:references; bh=GHxA36iYCw06lyEgfpowjvThSwOtjoS9yMPK2XXYsYE=; b=WOkWGB0Wk3HrQnaHkZ0nOaUMFQ3xIVfI+m+gt+1n2ZmEnyECAVshUb/RcprtKfvdF7 vLdound5255xrI2RK5UDTCnXjoMldXUZTIibCPQ8yveQSwiNJ6mWLTGgxIAh/dR00k3S VVwTZZ74G6eB9Bf7PKzkXjfAJDXTkwpzhQT9MM2pviSpyajwVUBfQBuoJhNXrmfgR95W kzGlgEJBZPcSzkhBP1xW/4Sj7tdIqMmdhdnaeUQHkTeOJgetICSLMSLz8/SHiJk0zgNA 8ENGWrm7OuENsAVhR2WUB8yZnGaMLDD+GXq4L5kZOThoE7/JZo+d+4aolFFBr8oeZB3S 4jKQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:in-reply-to:references; bh=GHxA36iYCw06lyEgfpowjvThSwOtjoS9yMPK2XXYsYE=; b=LjFw1MyT9LF/Xf6oMTOPBl5rGh6OTuxeUmlAFrhsYWSIYiXQ/qKo72sxuj3B3x1+Pp pH9hudFg53am/Eh4QRAUq9zdmp13+DWXFmuK7wJXih5z/KJQ6S30eJ89PsEjRIJlH2W8 +1Ow9CMYzayp2KkwJ+TVEsII3LcFNvBh0WFw6ZgH1pqob82MZRLSsG5pgV4ccRt3ftD1 D9IMCm9IdbrZ55dOmz1feSAng5CPLp5VfgJayi1LrtXYsgi+T8JC2jIpKgDB7aN9cfV3 c7mp8kkdbExlisBUtsH5N8+/dl92GG+A+XSdDQJg6c17plHxfuJ2kSf6mKdHBbMld6ns w09g== X-Gm-Message-State: AKaTC02i/cOoULgP23YZtztwiYcYGErDbB6bYPelZX3xOkNjsczpuaW6ignlv5iQLCeo3NtI X-Received: by 10.99.163.1 with SMTP id s1mr41787133pge.120.1479803122427; Tue, 22 Nov 2016 00:25:22 -0800 (PST) Received: from localhost.localdomain ([2601:602:8801:8110:1a5e:fff:fea7:e0ef]) by smtp.gmail.com with ESMTPSA id y2sm42948466pff.82.2016.11.22.00.25.21 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 22 Nov 2016 00:25:21 -0800 (PST) From: Omar Sandoval To: linux-fsdevel@vger.kernel.org Cc: linux-api@vger.kernel.org, kernel-team@fb.com Subject: [RFC PATCH 2/3] vfs: add d_replace() Date: Tue, 22 Nov 2016 00:25:02 -0800 Message-Id: <527297d2dae27845b3b7ba8ad6e81ef477fddee2.1479802448.git.osandov@fb.com> X-Mailer: git-send-email 2.10.2 In-Reply-To: References: In-Reply-To: References: Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Omar Sandoval Changes the inode associated with a dentry. This'll be useful for implementations of linkat() AT_REPLACE. Signed-off-by: Omar Sandoval --- fs/dcache.c | 68 +++++++++++++++++++++++++++++++++++++++++++++----- include/linux/dcache.h | 1 + 2 files changed, 63 insertions(+), 6 deletions(-) diff --git a/fs/dcache.c b/fs/dcache.c index 5c7cc95..aaa2b16 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -316,6 +316,16 @@ static void dentry_free(struct dentry *dentry) call_rcu(&dentry->d_u.d_rcu, __d_free); } +static void dentry_iput(struct dentry *dentry, struct inode *inode) +{ + if (!inode->i_nlink) + fsnotify_inoderemove(inode); + if (dentry->d_op && dentry->d_op->d_iput) + dentry->d_op->d_iput(dentry, inode); + else + iput(inode); +} + /* * Release the dentry's inode, using the filesystem * d_iput() operation if defined. @@ -335,12 +345,7 @@ static void dentry_unlink_inode(struct dentry * dentry) raw_write_seqcount_end(&dentry->d_seq); spin_unlock(&dentry->d_lock); spin_unlock(&inode->i_lock); - if (!inode->i_nlink) - fsnotify_inoderemove(inode); - if (dentry->d_op && dentry->d_op->d_iput) - dentry->d_op->d_iput(dentry, inode); - else - iput(inode); + dentry_iput(dentry, inode); } /* @@ -1816,6 +1821,24 @@ void d_instantiate(struct dentry *entry, struct inode * inode) } EXPORT_SYMBOL(d_instantiate); +static void lock_two_inodes(struct inode *inode1, struct inode *inode2) +{ + if (inode1 > inode2) + swap(inode1, inode2); + if (inode1) + spin_lock(&inode1->i_lock); + if (inode2) + spin_lock(&inode2->i_lock); +} + +static void unlock_two_inodes(struct inode *inode1, struct inode *inode2) +{ + if (inode1) + spin_unlock(&inode1->i_lock); + if (inode2) + spin_unlock(&inode2->i_lock); +} + /** * d_instantiate_no_diralias - instantiate a non-aliased dentry * @entry: dentry to complete @@ -2339,6 +2362,39 @@ void d_delete(struct dentry * dentry) } EXPORT_SYMBOL(d_delete); +/** + * d_replace - change the inode a dentry is associated with + * @dentry: dentry to modify + * @inode: inode to attach to this dentry + * + * Fill in new inode information in a dentry that may have previously been + * instantiated. This handles both negative and positive dentries. + */ +void d_replace(struct dentry *dentry, struct inode *inode) +{ + struct inode *old_inode = dentry->d_inode; + unsigned int add_flags; + + lock_two_inodes(old_inode, inode); + spin_lock(&dentry->d_lock); + add_flags = d_flags_for_inode(inode); + + if (old_inode) + hlist_del(&dentry->d_u.d_alias); + hlist_add_head(&dentry->d_u.d_alias, &inode->i_dentry); + + raw_write_seqcount_begin(&dentry->d_seq); + __d_set_inode_and_type(dentry, inode, add_flags); + raw_write_seqcount_end(&dentry->d_seq); + fsnotify_update_flags(dentry); + + spin_unlock(&dentry->d_lock); + unlock_two_inodes(old_inode, inode); + if (old_inode) + dentry_iput(dentry, old_inode); +} +EXPORT_SYMBOL(d_replace); + static void __d_rehash(struct dentry *entry) { struct hlist_bl_head *b = d_hash(entry->d_name.hash); diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 5beed7b..0610bb0 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -224,6 +224,7 @@ extern int d_instantiate_no_diralias(struct dentry *, struct inode *); extern void __d_drop(struct dentry *dentry); extern void d_drop(struct dentry *dentry); extern void d_delete(struct dentry *); +extern void d_replace(struct dentry *, struct inode *); extern void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op); /* allocate/de-allocate */