Skip to content

Commit

Permalink
Merge tag 'ovl-fixes-4.18' of git://git.kernel.org/pub/scm/linux/kern…
Browse files Browse the repository at this point in the history
…el/git/mszeredi/vfs

Pull overlayfs fixes from Miklos Szeredi:
 "This contains a fix for the vfs_mkdir() issue discovered by Al, as
  well as other fixes and cleanups"

* tag 'ovl-fixes-4.18' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs:
  ovl: use inode_insert5() to hash a newly created inode
  ovl: Pass argument to ovl_get_inode() in a structure
  vfs: factor out inode_insert5()
  ovl: clean up copy-up error paths
  ovl: return EIO on internal error
  ovl: make ovl_create_real() cope with vfs_mkdir() safely
  ovl: create helper ovl_create_temp()
  ovl: return dentry from ovl_create_real()
  ovl: struct cattr cleanups
  ovl: strip debug argument from ovl_do_ helpers
  ovl: remove WARN_ON() real inode attributes mismatch
  ovl: Kconfig documentation fixes
  ovl: update documentation for unionmount-testsuite
  • Loading branch information
Linus Torvalds committed Jun 7, 2018
2 parents da315f6 + 01b39dc commit 70f2ae1
Show file tree
Hide file tree
Showing 11 changed files with 319 additions and 273 deletions.
7 changes: 4 additions & 3 deletions Documentation/filesystems/overlayfs.txt
Original file line number Diff line number Diff line change
Expand Up @@ -429,11 +429,12 @@ This verification may cause significant overhead in some cases.
Testsuite
---------

There's testsuite developed by David Howells at:
There's a testsuite originally developed by David Howells and currently
maintained by Amir Goldstein at:

git://git.infradead.org/users/dhowells/unionmount-testsuite.git
https://github.com/amir73il/unionmount-testsuite.git

Run as root:

# cd unionmount-testsuite
# ./run --ov
# ./run --ov --verify
164 changes: 75 additions & 89 deletions fs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1003,6 +1003,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
Expand All @@ -1027,66 +1091,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);

Expand Down Expand Up @@ -1427,43 +1443,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);

Expand Down
6 changes: 3 additions & 3 deletions fs/overlayfs/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ config OVERLAY_FS
For more information see Documentation/filesystems/overlayfs.txt

config OVERLAY_FS_REDIRECT_DIR
bool "Overlayfs: turn on redirect dir feature by default"
bool "Overlayfs: turn on redirect directory feature by default"
depends on OVERLAY_FS
help
If this config option is enabled then overlay filesystems will use
Expand Down Expand Up @@ -46,7 +46,7 @@ config OVERLAY_FS_INDEX
depends on OVERLAY_FS
help
If this config option is enabled then overlay filesystems will use
the inodes index dir to map lower inodes to upper inodes by default.
the index directory to map lower inodes to upper inodes by default.
In this case it is still possible to turn off index globally with the
"index=off" module option or on a filesystem instance basis with the
"index=off" mount option.
Expand All @@ -66,7 +66,7 @@ config OVERLAY_FS_NFS_EXPORT
depends on OVERLAY_FS_INDEX
help
If this config option is enabled then overlay filesystems will use
the inodes index dir to decode overlay NFS file handles by default.
the index directory to decode overlay NFS file handles by default.
In this case, it is still possible to turn off NFS export support
globally with the "nfs_export=off" module option or on a filesystem
instance basis with the "nfs_export=off" mount option.
Expand Down
Loading

0 comments on commit 70f2ae1

Please sign in to comment.