Skip to content

Commit

Permalink
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/viro/vfs-2.6

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6:
  fs: simplify iget & friends
  fs: pull inode->i_lock up out of writeback_single_inode
  fs: rename inode_lock to inode_hash_lock
  fs: move i_wb_list out from under inode_lock
  fs: move i_sb_list out from under inode_lock
  fs: remove inode_lock from iput_final and prune_icache
  fs: Lock the inode LRU list separately
  fs: factor inode disposal
  fs: protect inode->i_state with inode->i_lock
  autofs4: Do not potentially dereference NULL pointer returned by fget() in autofs_dev_ioctl_setpipefd()
  autofs4 - remove autofs4_lock
  autofs4 - fix d_manage() return on rcu-walk
  autofs4 - fix autofs4_expire_indirect() traversal
  autofs4 - fix dentry leak in autofs4_expire_direct()
  autofs4 - reinstate last used update on access
  vfs - check non-mountpoint dentry might block in __follow_mount_rcu()
  • Loading branch information
torvalds committed Mar 25, 2011
2 parents 30f5b28 + 0b2d072 commit d39dd11
Show file tree
Hide file tree
Showing 27 changed files with 615 additions and 536 deletions.
2 changes: 1 addition & 1 deletion Documentation/filesystems/Locking
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ alloc_inode:
destroy_inode:
dirty_inode: (must not sleep)
write_inode:
drop_inode: !!!inode_lock!!!
drop_inode: !!!inode->i_lock!!!
evict_inode:
put_super: write
write_super: read
Expand Down
16 changes: 11 additions & 5 deletions Documentation/filesystems/porting
Original file line number Diff line number Diff line change
Expand Up @@ -298,11 +298,14 @@ be used instead. It gets called whenever the inode is evicted, whether it has
remaining links or not. Caller does *not* evict the pagecache or inode-associated
metadata buffers; getting rid of those is responsibility of method, as it had
been for ->delete_inode().
->drop_inode() returns int now; it's called on final iput() with inode_lock
held and it returns true if filesystems wants the inode to be dropped. As before,
generic_drop_inode() is still the default and it's been updated appropriately.
generic_delete_inode() is also alive and it consists simply of return 1. Note that
all actual eviction work is done by caller after ->drop_inode() returns.

->drop_inode() returns int now; it's called on final iput() with
inode->i_lock held and it returns true if filesystems wants the inode to be
dropped. As before, generic_drop_inode() is still the default and it's been
updated appropriately. generic_delete_inode() is also alive and it consists
simply of return 1. Note that all actual eviction work is done by caller after
->drop_inode() returns.

clear_inode() is gone; use end_writeback() instead. As before, it must
be called exactly once on each call of ->evict_inode() (as it used to be for
each call of ->delete_inode()). Unlike before, if you are using inode-associated
Expand Down Expand Up @@ -395,6 +398,9 @@ Currently you can only have FALLOC_FL_PUNCH_HOLE with FALLOC_FL_KEEP_SIZE set,
so the i_size should not change when hole punching, even when puching the end of
a file off.

--
[mandatory]

--
[mandatory]
->get_sb() is gone. Switch to use of ->mount(). Typically it's just
Expand Down
2 changes: 1 addition & 1 deletion Documentation/filesystems/vfs.txt
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ or bottom half).
should be synchronous or not, not all filesystems check this flag.

drop_inode: called when the last access to the inode is dropped,
with the inode_lock spinlock held.
with the inode->i_lock spinlock held.

This method should be either NULL (normal UNIX filesystem
semantics) or "generic_delete_inode" (for filesystems that do not
Expand Down
2 changes: 0 additions & 2 deletions fs/autofs4/autofs_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,6 @@ do { \
current->pid, __func__, ##args); \
} while (0)

extern spinlock_t autofs4_lock;

/* Unified info structure. This is pointed to by both the dentry and
inode structures. Each file in the filesystem has an instance of this
structure. It holds a reference to the dentry, so dentries are never
Expand Down
4 changes: 4 additions & 0 deletions fs/autofs4/dev-ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,10 @@ static int autofs_dev_ioctl_setpipefd(struct file *fp,
return -EBUSY;
} else {
struct file *pipe = fget(pipefd);
if (!pipe) {
err = -EBADF;
goto out;
}
if (!pipe->f_op || !pipe->f_op->write) {
err = -EPIPE;
fput(pipe);
Expand Down
84 changes: 63 additions & 21 deletions fs/autofs4/expire.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,19 +86,71 @@ static int autofs4_mount_busy(struct vfsmount *mnt, struct dentry *dentry)
return status;
}

/*
* Calculate and dget next entry in the subdirs list under root.
*/
static struct dentry *get_next_positive_subdir(struct dentry *prev,
struct dentry *root)
{
struct autofs_sb_info *sbi = autofs4_sbi(root->d_sb);
struct list_head *next;
struct dentry *p, *q;

spin_lock(&sbi->lookup_lock);

if (prev == NULL) {
spin_lock(&root->d_lock);
prev = dget_dlock(root);
next = prev->d_subdirs.next;
p = prev;
goto start;
}

p = prev;
spin_lock(&p->d_lock);
again:
next = p->d_u.d_child.next;
start:
if (next == &root->d_subdirs) {
spin_unlock(&p->d_lock);
spin_unlock(&sbi->lookup_lock);
dput(prev);
return NULL;
}

q = list_entry(next, struct dentry, d_u.d_child);

spin_lock_nested(&q->d_lock, DENTRY_D_LOCK_NESTED);
/* Negative dentry - try next */
if (!simple_positive(q)) {
spin_unlock(&p->d_lock);
p = q;
goto again;
}
dget_dlock(q);
spin_unlock(&q->d_lock);
spin_unlock(&p->d_lock);
spin_unlock(&sbi->lookup_lock);

dput(prev);

return q;
}

/*
* Calculate and dget next entry in top down tree traversal.
*/
static struct dentry *get_next_positive_dentry(struct dentry *prev,
struct dentry *root)
{
struct autofs_sb_info *sbi = autofs4_sbi(root->d_sb);
struct list_head *next;
struct dentry *p, *ret;

if (prev == NULL)
return dget(root);

spin_lock(&autofs4_lock);
spin_lock(&sbi->lookup_lock);
relock:
p = prev;
spin_lock(&p->d_lock);
Expand All @@ -110,7 +162,7 @@ static struct dentry *get_next_positive_dentry(struct dentry *prev,

if (p == root) {
spin_unlock(&p->d_lock);
spin_unlock(&autofs4_lock);
spin_unlock(&sbi->lookup_lock);
dput(prev);
return NULL;
}
Expand Down Expand Up @@ -140,7 +192,7 @@ static struct dentry *get_next_positive_dentry(struct dentry *prev,
dget_dlock(ret);
spin_unlock(&ret->d_lock);
spin_unlock(&p->d_lock);
spin_unlock(&autofs4_lock);
spin_unlock(&sbi->lookup_lock);

dput(prev);

Expand Down Expand Up @@ -290,19 +342,16 @@ struct dentry *autofs4_expire_direct(struct super_block *sb,
spin_lock(&sbi->fs_lock);
ino = autofs4_dentry_ino(root);
/* No point expiring a pending mount */
if (ino->flags & AUTOFS_INF_PENDING) {
spin_unlock(&sbi->fs_lock);
return NULL;
}
managed_dentry_set_transit(root);
if (ino->flags & AUTOFS_INF_PENDING)
goto out;
if (!autofs4_direct_busy(mnt, root, timeout, do_now)) {
struct autofs_info *ino = autofs4_dentry_ino(root);
ino->flags |= AUTOFS_INF_EXPIRING;
init_completion(&ino->expire_complete);
spin_unlock(&sbi->fs_lock);
return root;
}
managed_dentry_clear_transit(root);
out:
spin_unlock(&sbi->fs_lock);
dput(root);

Expand Down Expand Up @@ -336,13 +385,12 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb,
timeout = sbi->exp_timeout;

dentry = NULL;
while ((dentry = get_next_positive_dentry(dentry, root))) {
while ((dentry = get_next_positive_subdir(dentry, root))) {
spin_lock(&sbi->fs_lock);
ino = autofs4_dentry_ino(dentry);
/* No point expiring a pending mount */
if (ino->flags & AUTOFS_INF_PENDING)
goto cont;
managed_dentry_set_transit(dentry);
goto next;

/*
* Case 1: (i) indirect mount or top level pseudo direct mount
Expand Down Expand Up @@ -402,8 +450,6 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb,
}
}
next:
managed_dentry_clear_transit(dentry);
cont:
spin_unlock(&sbi->fs_lock);
}
return NULL;
Expand All @@ -415,13 +461,13 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb,
ino->flags |= AUTOFS_INF_EXPIRING;
init_completion(&ino->expire_complete);
spin_unlock(&sbi->fs_lock);
spin_lock(&autofs4_lock);
spin_lock(&sbi->lookup_lock);
spin_lock(&expired->d_parent->d_lock);
spin_lock_nested(&expired->d_lock, DENTRY_D_LOCK_NESTED);
list_move(&expired->d_parent->d_subdirs, &expired->d_u.d_child);
spin_unlock(&expired->d_lock);
spin_unlock(&expired->d_parent->d_lock);
spin_unlock(&autofs4_lock);
spin_unlock(&sbi->lookup_lock);
return expired;
}

Expand Down Expand Up @@ -484,8 +530,6 @@ int autofs4_expire_run(struct super_block *sb,
spin_lock(&sbi->fs_lock);
ino = autofs4_dentry_ino(dentry);
ino->flags &= ~AUTOFS_INF_EXPIRING;
if (!d_unhashed(dentry))
managed_dentry_clear_transit(dentry);
complete_all(&ino->expire_complete);
spin_unlock(&sbi->fs_lock);

Expand Down Expand Up @@ -513,9 +557,7 @@ int autofs4_do_expire_multi(struct super_block *sb, struct vfsmount *mnt,
spin_lock(&sbi->fs_lock);
ino->flags &= ~AUTOFS_INF_EXPIRING;
spin_lock(&dentry->d_lock);
if (ret)
__managed_dentry_clear_transit(dentry);
else {
if (!ret) {
if ((IS_ROOT(dentry) ||
(autofs_type_indirect(sbi->type) &&
IS_ROOT(dentry->d_parent))) &&
Expand Down
Loading

0 comments on commit d39dd11

Please sign in to comment.