From patchwork Tue May 23 09:50:32 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Amir Goldstein X-Patchwork-Id: 9742209 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 5B3E260380 for ; Tue, 23 May 2017 09:50:29 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4076C26212 for ; Tue, 23 May 2017 09:50:29 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 3407E287B6; Tue, 23 May 2017 09:50:29 +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.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FREEMAIL_FROM, 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 A216426212 for ; Tue, 23 May 2017 09:50:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S936834AbdEWJu0 (ORCPT ); Tue, 23 May 2017 05:50:26 -0400 Received: from mail-wr0-f195.google.com ([209.85.128.195]:33451 "EHLO mail-wr0-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S935917AbdEWJuY (ORCPT ); Tue, 23 May 2017 05:50:24 -0400 Received: by mail-wr0-f195.google.com with SMTP id w50so9519494wrc.0; Tue, 23 May 2017 02:50:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=t5J30SCAepLMBEZ5ywJZrLUd4fHBVRVnEILPH2vP6z8=; b=TGgHWqOyCJ0NjJchZh+psBGkElA+tKwOsxpLLJ6Vi0HlJT0KmmdSDLZDySzKuazl6w 6c6b/AFC0MLzGwPko3EVPvjb09BupEM947DW6qItoS5AcMVg+10FbxH8pytpPOEGe0C4 uIg28JXGsTQDNepmVoonGTLMpHzIN26kqgGkalR5BUYDiv/6bN3cjvaaGPWQpprDVNgD mtCoWA0EgfizPWrjDC/+yM6xW7Kw2T1NhkVD+A1rwQPgV3C3zaj3pt2Bb81PFNHaH0gc AaKvR+VzJ/9PqoWuH8Wzbrpo27UuMmauhMZjNpk27vYoZBBtx5Sh6+d9ArkOczcPbh6i L16Q== 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=t5J30SCAepLMBEZ5ywJZrLUd4fHBVRVnEILPH2vP6z8=; b=cK+4kT6cuAnutTOSTdR778gOEafrODoLkjBU+frMkVwunWoA4FEvI4XLw6DbDp55fI hYudEBdhhtmuSCwNNjPoiosIQxuwsFWVdjMxt1VA2zxUfgf76eBnrsgUMcfqnwCOyGY3 IjPtsqcW0UQie5aBVkpkD4U+B78afUoJ/dFEA9fUd4Cbw6dBTpZ1k40FH1iEa/EE/atx Pq77umWkI21UiebvkLoIsZMtmnhL8kEuytFUTXWgsEzPvZs7bWRbPa9ozoHiIHwMkhW4 YZ/tM6DPnTd90LEITFtOGTlcfyMdaY8Xyc7UKU1dFI0A4BwA2Qsgl/gLwRNDCAByMtt6 YzYQ== X-Gm-Message-State: AODbwcBBLnIxR9QkJlePRm98pWuZWNELcqoWam4YcmKacBuBzmd98TP0 7m6qWXWVeJQKKIRp X-Received: by 10.223.130.117 with SMTP id 108mr7117278wrb.70.1495533022442; Tue, 23 May 2017 02:50:22 -0700 (PDT) Received: from amir-VirtualBox.lan (bzq-79-179-137-123.red.bezeqint.net. [79.179.137.123]) by smtp.gmail.com with ESMTPSA id n99sm308844wrb.62.2017.05.23.02.50.20 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 23 May 2017 02:50:21 -0700 (PDT) From: Amir Goldstein To: Miklos Szeredi Cc: Al Viro , linux-unionfs@vger.kernel.org, linux-fsdevel@vger.kernel.org Subject: [PATCH 1/2] vfs: introduce inode 'inuse' lock Date: Tue, 23 May 2017 12:50:32 +0300 Message-Id: <1495533033-22367-2-git-send-email-amir73il@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1495533033-22367-1-git-send-email-amir73il@gmail.com> References: <1495533033-22367-1-git-send-email-amir73il@gmail.com> 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 Added an i_state flag I_INUSE and helpers to set/clear/test the bit. The 'inuse' lock is an 'advisory' inode lock, which also provides may_delete() protection, so can be used to extend exclusive create protection beyond parent->i_mutex lock among cooperating users. This is going to be used by overlayfs to get exclusive ownership on upper and work dirs among overlayfs mounts. Signed-off-by: Amir Goldstein --- fs/btrfs/ioctl.c | 3 +++ fs/inode.c | 40 ++++++++++++++++++++++++++++++++++++++++ fs/namei.c | 3 +++ include/linux/fs.h | 16 ++++++++++++++++ 4 files changed, 62 insertions(+) diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index e176375..17fa239 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -782,6 +782,7 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir, * 9. We can't remove a root or mountpoint. * 10. We don't allow removal of NFS sillyrenamed files; it's handled by * nfs_async_unlink(). + * 11. We don't allow removal of inodes marked 'inuse'. */ static int btrfs_may_delete(struct inode *dir, struct dentry *victim, int isdir) @@ -813,6 +814,8 @@ static int btrfs_may_delete(struct inode *dir, struct dentry *victim, int isdir) return -ENOENT; if (victim->d_flags & DCACHE_NFSFS_RENAMED) return -EBUSY; + if (inode_inuse(d_inode(victim))) + return -EBUSY; return 0; } diff --git a/fs/inode.c b/fs/inode.c index db59147..0552c8b 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -2120,3 +2120,43 @@ struct timespec current_time(struct inode *inode) return timespec_trunc(now, inode->i_sb->s_time_gran); } EXPORT_SYMBOL(current_time); + +/** + * inode_inuse_trylock - try to get an exclusive 'inuse' lock on inode + * @inode: inode being locked + * + * The 'inuse' lock is an 'advisory' inode lock, which also provides + * may_delete() protection, so can be used to extend exclusive create + * protection beyond parent->i_mutex lock among cooperating users. + * Used by overlayfs to get exclusive ownership on upper and work dirs + * among overlayfs mounts. + * + * Return true if I_INUSE flag was set by this call. + */ +bool inode_inuse_trylock(struct inode *inode) +{ + bool locked = false; + + spin_lock(&inode->i_lock); + if (!(inode->i_state & (I_FREEING|I_WILL_FREE|I_INUSE))) { + inode->i_state |= I_INUSE; + locked = true; + } + spin_unlock(&inode->i_lock); + return locked; +} +EXPORT_SYMBOL(inode_inuse_trylock); + +/* + * Non-cooperating users should not be calling this functions and cooperating + * users should call this function only if they have the exclusive 'inuse' lock. + */ +void inode_inuse_unlock(struct inode *inode) +{ + WARN_ON(!inode_inuse(inode)); + + spin_lock(&inode->i_lock); + inode->i_state &= ~I_INUSE; + spin_unlock(&inode->i_lock); +} +EXPORT_SYMBOL(inode_inuse_unlock); diff --git a/fs/namei.c b/fs/namei.c index 837da8b..c371b25 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -2790,6 +2790,7 @@ EXPORT_SYMBOL(__check_sticky); * 10. We can't remove a root or mountpoint. * 11. We don't allow removal of NFS sillyrenamed files; it's handled by * nfs_async_unlink(). + * 12. We don't allow removal of inodes marked 'inuse'. */ static int may_delete(struct inode *dir, struct dentry *victim, bool isdir) { @@ -2823,6 +2824,8 @@ static int may_delete(struct inode *dir, struct dentry *victim, bool isdir) return -ENOENT; if (victim->d_flags & DCACHE_NFSFS_RENAMED) return -EBUSY; + if (inode_inuse(d_inode(victim))) + return -EBUSY; return 0; } diff --git a/include/linux/fs.h b/include/linux/fs.h index aab10f9..1420e8b 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1864,6 +1864,7 @@ struct super_operations { #define IS_AUTOMOUNT(inode) ((inode)->i_flags & S_AUTOMOUNT) #define IS_NOSEC(inode) ((inode)->i_flags & S_NOSEC) #define IS_DAX(inode) ((inode)->i_flags & S_DAX) +#define IS_INUSE(inode) ((inode)->i_flags & S_INUSE) #define IS_WHITEOUT(inode) (S_ISCHR(inode->i_mode) && \ (inode)->i_rdev == WHITEOUT_DEV) @@ -1929,6 +1930,13 @@ static inline bool HAS_UNMAPPED_ID(struct inode *inode) * wb stat updates to grab mapping->tree_lock. See * inode_switch_wb_work_fn() for details. * + * I_INUSE An 'advisory' bit to get exclusive ownership on inode + * using inode_inuse_trylock(). Also provides may_delete() + * protection, so can be used to extend exclusive create + * protection beyond parent->i_mutex lock. + * Used by overlayfs to get exclusive ownership on upper + * and work dirs among overlayfs mounts. + * * Q: What is the difference between I_WILL_FREE and I_FREEING? */ #define I_DIRTY_SYNC (1 << 0) @@ -1949,6 +1957,7 @@ static inline bool HAS_UNMAPPED_ID(struct inode *inode) #define __I_DIRTY_TIME_EXPIRED 12 #define I_DIRTY_TIME_EXPIRED (1 << __I_DIRTY_TIME_EXPIRED) #define I_WB_SWITCH (1 << 13) +#define I_INUSE (1 << 14) #define I_DIRTY (I_DIRTY_SYNC | I_DIRTY_DATASYNC | I_DIRTY_PAGES) #define I_DIRTY_ALL (I_DIRTY | I_DIRTY_TIME) @@ -3258,5 +3267,12 @@ static inline bool dir_relax_shared(struct inode *inode) extern bool path_noexec(const struct path *path); extern void inode_nohighmem(struct inode *inode); +extern bool inode_inuse_trylock(struct inode *inode); +extern void inode_inuse_unlock(struct inode *inode); + +static inline bool inode_inuse(struct inode *inode) +{ + return inode->i_state & I_INUSE; +} #endif /* _LINUX_FS_H */