From patchwork Tue Apr 24 06:19:42 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Omar Sandoval X-Patchwork-Id: 10358691 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 2E0816038F for ; Tue, 24 Apr 2018 06:20:01 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1E9CE28CF9 for ; Tue, 24 Apr 2018 06:20:01 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 136D628CFB; Tue, 24 Apr 2018 06:20:01 +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=-7.9 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI 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 94DD128CF9 for ; Tue, 24 Apr 2018 06:20:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756318AbeDXGT6 (ORCPT ); Tue, 24 Apr 2018 02:19:58 -0400 Received: from mail-io0-f195.google.com ([209.85.223.195]:46442 "EHLO mail-io0-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756311AbeDXGTz (ORCPT ); Tue, 24 Apr 2018 02:19:55 -0400 Received: by mail-io0-f195.google.com with SMTP id f3-v6so21326429iob.13 for ; Mon, 23 Apr 2018 23:19:54 -0700 (PDT) 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=ZjqFKR/cQ+RtGwe9rXM76N7TllC8ExvFHR1slTR8kzc=; b=Rtxcv+iM+tt+TigkJHksBkVmw5vG5m3YKjx2AjnMxTm69DpmsgKk3mKocyW9pVojy0 ZX+Elu+V09TAKDiOwNMqntcJ868k92LZ2ImKsHxLOIw2XBYA2Nfsh7rO9oFpvCLuYGcQ wzclHBOjFRhzGN9kYploPNqDIy8c8BwIrAoppqAQ1iSeklUZreKaQiaCuwpuxT49grDR M2UD1F9UHEOiBubuglp3nWwtwIibj6u8RcwayoEWfPAZPJHwxrLR3RzX53fPZ416BYNP OlnDoVq8pHNyz7OcPPgjUPp1wW1hiiEIQDyo6nUYPa0hNvswxGvX0D4bJZ7WpA6XwqoL /jow== 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:in-reply-to:references; bh=ZjqFKR/cQ+RtGwe9rXM76N7TllC8ExvFHR1slTR8kzc=; b=I2wACW0DG4BsB70POiL7S6YJTQGT/cRb0bpxYGpeTqomaku6YcrVqJmE83TFvbYnf7 9cszYDQ6waJKzod+r+UNK3yZEbBrEpyCmC9XOcaxf+EJ6Shv2YBANVvn3ii7pKkDSS/A xayWa4d6NwbQlL1T9rhAV5oZWedqZCeH8m0tT2MeVaefzEd2nnKIQ3Lhu2BjVdntzMC3 7brEvBOmU5U14YlmoxEW1gNco9XLRie1ipM6ewzKlkttCwMSH6MgrxWwaHA1CjcRQn1o n39cl6wHJfQNm8d9lQtJmeaRp2ERejS3BaHbBj+F+3vSVE5d4e0TCGDJls2X322j3GXY Y0gQ== X-Gm-Message-State: ALQs6tANKwskM+NMy5MnjV5ErW9HrGxkj3UEwfzSpvzMtL/obgkobiuc s2cNt7iIalQzQETPYUqrqHj35Q== X-Google-Smtp-Source: AB8JxZrZjirvXQfK2gR0Tkrr7shEUSu8iQhL4nnMwjkZjbvnVzJQuqYIq+37Se8hRtXa4yP9HmjNjQ== X-Received: by 2002:a6b:9b15:: with SMTP id d21-v6mr26047090ioe.243.1524550793999; Mon, 23 Apr 2018 23:19:53 -0700 (PDT) Received: from vader.Home (174-23-136-226.slkc.qwest.net. [174.23.136.226]) by smtp.gmail.com with ESMTPSA id n142-v6sm5057653itn.38.2018.04.23.23.19.52 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 23 Apr 2018 23:19:53 -0700 (PDT) From: Omar Sandoval To: Al Viro , linux-fsdevel@vger.kernel.org Cc: Linus Torvalds , linux-api@vger.kernel.org, kernel-team@fb.com, Xi Wang Subject: [RFC PATCH v3 2/2] Btrfs: add support for linkat() AT_REPLACE Date: Mon, 23 Apr 2018 23:19:42 -0700 Message-Id: <66bf922d58d708b5cbf85d6cea4e2b601d3ef8d9.1524549513.git.osandov@fb.com> X-Mailer: git-send-email 2.17.0 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 The implementation is fairly straightforward and looks a lot like btrfs_rename(). The only tricky bit is that instead of playing games with the dcache, we simply drop the dentry for it to be instantiated on the next lookup. This can be improved in the future. Signed-off-by: Omar Sandoval --- fs/btrfs/inode.c | 65 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 61 insertions(+), 4 deletions(-) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index d241285a0d2a..a061285bf3ab 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -6675,16 +6675,21 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry, } static int btrfs_link(struct dentry *old_dentry, struct inode *dir, - struct dentry *dentry) + struct dentry *dentry, unsigned int flags) { struct btrfs_trans_handle *trans = NULL; + unsigned int trans_num_items; struct btrfs_root *root = BTRFS_I(dir)->root; struct inode *inode = d_inode(old_dentry); + struct inode *new_inode = d_inode(dentry); struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); u64 index; int err; int drop_inode = 0; + if (flags & ~AT_REPLACE) + return -EINVAL; + /* do not allow sys_link's with other subvols of the same device */ if (root->objectid != BTRFS_I(inode)->root->objectid) return -EXDEV; @@ -6692,16 +6697,47 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, if (inode->i_nlink >= BTRFS_LINK_MAX) return -EMLINK; + /* check for collisions, even if the name isn't there */ + err = btrfs_check_dir_item_collision(root, dir->i_ino, + dentry->d_name.name, + dentry->d_name.len); + if (err) { + if (err == -EEXIST) { + if (WARN_ON(!new_inode)) + return err; + } else { + return err; + } + } + + /* + * we're using link to replace one file with another. Start IO on it now + * so we don't add too much work to the end of the transaction + */ + if (new_inode && S_ISREG(inode->i_mode) && new_inode->i_size) + filemap_flush(inode->i_mapping); + err = btrfs_set_inode_index(BTRFS_I(dir), &index); if (err) goto fail; /* + * For the source: * 2 items for inode and inode ref * 2 items for dir items * 1 item for parent inode + * + * For the target: + * 1 for the possible orphan item + * 1 for the dir item + * 1 for the dir index + * 1 for the inode ref + * 1 for the inode */ - trans = btrfs_start_transaction(root, 5); + trans_num_items = 5; + if (new_inode) + trans_num_items += 5; + trans = btrfs_start_transaction(root, trans_num_items); if (IS_ERR(trans)) { err = PTR_ERR(trans); trans = NULL; @@ -6713,6 +6749,22 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, inc_nlink(inode); inode_inc_iversion(inode); inode->i_ctime = current_time(inode); + + if (new_inode) { + inode_inc_iversion(new_inode); + new_inode->i_ctime = current_time(new_inode); + err = btrfs_unlink_inode(trans, root, BTRFS_I(dir), + BTRFS_I(new_inode), + dentry->d_name.name, + dentry->d_name.len); + if (!err && new_inode->i_nlink == 0) + err = btrfs_orphan_add(trans, BTRFS_I(new_inode)); + if (err) { + btrfs_abort_transaction(trans, err); + goto fail; + } + } + ihold(inode); set_bit(BTRFS_INODE_COPY_EVERYTHING, &BTRFS_I(inode)->runtime_flags); @@ -6735,7 +6787,12 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, if (err) goto fail; } - d_instantiate(dentry, inode); + if (new_inode) { + d_drop(dentry); + iput(inode); + } else { + d_instantiate(dentry, inode); + } btrfs_log_new_name(trans, BTRFS_I(inode), NULL, parent); } @@ -10555,7 +10612,7 @@ static const struct inode_operations btrfs_dir_inode_operations = { .lookup = btrfs_lookup, .create = btrfs_create, .unlink = btrfs_unlink, - .link = btrfs_link, + .link2 = btrfs_link, .mkdir = btrfs_mkdir, .rmdir = btrfs_rmdir, .rename = btrfs_rename2,