]> git.ipfire.org Git - thirdparty/kernel/stable.git/blobdiff - fs/overlayfs/inode.c
Merge tag 'spdx-5.2-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh...
[thirdparty/kernel/stable.git] / fs / overlayfs / inode.c
index b48273e846adc524eeaa50bde608a93b8bdeb102..7663aeb85fa3f4a44d2474f0009de3c74c61246c 100644 (file)
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  *
  * Copyright (C) 2011 Novell Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
  */
 
 #include <linux/fs.h>
@@ -553,15 +550,15 @@ static void ovl_fill_inode(struct inode *inode, umode_t mode, dev_t rdev,
        int xinobits = ovl_xino_bits(inode->i_sb);
 
        /*
-        * When NFS export is enabled and d_ino is consistent with st_ino
-        * (samefs or i_ino has enough bits to encode layer), set the same
-        * value used for d_ino to i_ino, because nfsd readdirplus compares
-        * d_ino values to i_ino values of child entries. When called from
+        * When d_ino is consistent with st_ino (samefs or i_ino has enough
+        * bits to encode layer), set the same value used for st_ino to i_ino,
+        * so inode number exposed via /proc/locks and a like will be
+        * consistent with d_ino and st_ino values. An i_ino value inconsistent
+        * with d_ino also causes nfsd readdirplus to fail.  When called from
         * ovl_new_inode(), ino arg is 0, so i_ino will be updated to real
         * upper inode i_ino on ovl_inode_init() or ovl_inode_update().
         */
-       if (inode->i_sb->s_export_op &&
-           (ovl_same_sb(inode->i_sb) || xinobits)) {
+       if (ovl_same_sb(inode->i_sb) || xinobits) {
                inode->i_ino = ino;
                if (xinobits && fsid && !(ino >> (64 - xinobits)))
                        inode->i_ino |= (unsigned long)fsid << (64 - xinobits);
@@ -777,6 +774,54 @@ struct inode *ovl_lookup_inode(struct super_block *sb, struct dentry *real,
        return inode;
 }
 
+bool ovl_lookup_trap_inode(struct super_block *sb, struct dentry *dir)
+{
+       struct inode *key = d_inode(dir);
+       struct inode *trap;
+       bool res;
+
+       trap = ilookup5(sb, (unsigned long) key, ovl_inode_test, key);
+       if (!trap)
+               return false;
+
+       res = IS_DEADDIR(trap) && !ovl_inode_upper(trap) &&
+                                 !ovl_inode_lower(trap);
+
+       iput(trap);
+       return res;
+}
+
+/*
+ * Create an inode cache entry for layer root dir, that will intentionally
+ * fail ovl_verify_inode(), so any lookup that will find some layer root
+ * will fail.
+ */
+struct inode *ovl_get_trap_inode(struct super_block *sb, struct dentry *dir)
+{
+       struct inode *key = d_inode(dir);
+       struct inode *trap;
+
+       if (!d_is_dir(dir))
+               return ERR_PTR(-ENOTDIR);
+
+       trap = iget5_locked(sb, (unsigned long) key, ovl_inode_test,
+                           ovl_inode_set, key);
+       if (!trap)
+               return ERR_PTR(-ENOMEM);
+
+       if (!(trap->i_state & I_NEW)) {
+               /* Conflicting layer roots? */
+               iput(trap);
+               return ERR_PTR(-ELOOP);
+       }
+
+       trap->i_mode = S_IFDIR;
+       trap->i_flags = S_DEAD;
+       unlock_new_inode(trap);
+
+       return trap;
+}
+
 /*
  * Does overlay inode need to be hashed by lower inode?
  */