提交 4b1ae27a 编写于 作者: A Al Viro

Revert "autofs4: always use lookup for lookup"

This reverts commit 213614d5.

Alas, ->d_revalidate() can't rely on ->lookup() finishing what
it's started; if d_alloc() in do_lookup() fails, we are not going
to call ->lookup() at all.
Signed-off-by: NAl Viro <viro@zeniv.linux.org.uk>
上级 60b341b7
...@@ -60,11 +60,6 @@ do { \ ...@@ -60,11 +60,6 @@ do { \
current->pid, __func__, ##args); \ current->pid, __func__, ##args); \
} while (0) } while (0)
struct rehash_entry {
struct task_struct *task;
struct list_head list;
};
/* Unified info structure. This is pointed to by both the dentry and /* Unified info structure. This is pointed to by both the dentry and
inode structures. Each file in the filesystem has an instance of this inode structures. Each file in the filesystem has an instance of this
structure. It holds a reference to the dentry, so dentries are never structure. It holds a reference to the dentry, so dentries are never
...@@ -81,7 +76,6 @@ struct autofs_info { ...@@ -81,7 +76,6 @@ struct autofs_info {
struct list_head active; struct list_head active;
int active_count; int active_count;
struct list_head rehash_list;
struct list_head expiring; struct list_head expiring;
...@@ -104,7 +98,6 @@ struct autofs_info { ...@@ -104,7 +98,6 @@ struct autofs_info {
#define AUTOFS_INF_EXPIRING (1<<0) /* dentry is in the process of expiring */ #define AUTOFS_INF_EXPIRING (1<<0) /* dentry is in the process of expiring */
#define AUTOFS_INF_MOUNTPOINT (1<<1) /* mountpoint status for direct expire */ #define AUTOFS_INF_MOUNTPOINT (1<<1) /* mountpoint status for direct expire */
#define AUTOFS_INF_PENDING (1<<2) /* dentry pending mount */ #define AUTOFS_INF_PENDING (1<<2) /* dentry pending mount */
#define AUTOFS_INF_REHASH (1<<3) /* dentry in transit to ->lookup() */
struct autofs_wait_queue { struct autofs_wait_queue {
wait_queue_head_t queue; wait_queue_head_t queue;
......
...@@ -279,7 +279,6 @@ struct dentry *autofs4_expire_direct(struct super_block *sb, ...@@ -279,7 +279,6 @@ struct dentry *autofs4_expire_direct(struct super_block *sb,
root->d_mounted--; root->d_mounted--;
} }
ino->flags |= AUTOFS_INF_EXPIRING; ino->flags |= AUTOFS_INF_EXPIRING;
autofs4_add_expiring(root);
init_completion(&ino->expire_complete); init_completion(&ino->expire_complete);
spin_unlock(&sbi->fs_lock); spin_unlock(&sbi->fs_lock);
return root; return root;
...@@ -407,7 +406,6 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb, ...@@ -407,7 +406,6 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb,
expired, (int)expired->d_name.len, expired->d_name.name); expired, (int)expired->d_name.len, expired->d_name.name);
ino = autofs4_dentry_ino(expired); ino = autofs4_dentry_ino(expired);
ino->flags |= AUTOFS_INF_EXPIRING; ino->flags |= AUTOFS_INF_EXPIRING;
autofs4_add_expiring(expired);
init_completion(&ino->expire_complete); init_completion(&ino->expire_complete);
spin_unlock(&sbi->fs_lock); spin_unlock(&sbi->fs_lock);
spin_lock(&dcache_lock); spin_lock(&dcache_lock);
...@@ -435,7 +433,7 @@ int autofs4_expire_wait(struct dentry *dentry) ...@@ -435,7 +433,7 @@ int autofs4_expire_wait(struct dentry *dentry)
DPRINTK("expire done status=%d", status); DPRINTK("expire done status=%d", status);
if (d_unhashed(dentry) && IS_DEADDIR(dentry->d_inode)) if (d_unhashed(dentry))
return -EAGAIN; return -EAGAIN;
return status; return status;
...@@ -475,7 +473,6 @@ int autofs4_expire_run(struct super_block *sb, ...@@ -475,7 +473,6 @@ int autofs4_expire_run(struct super_block *sb,
spin_lock(&sbi->fs_lock); spin_lock(&sbi->fs_lock);
ino = autofs4_dentry_ino(dentry); ino = autofs4_dentry_ino(dentry);
ino->flags &= ~AUTOFS_INF_EXPIRING; ino->flags &= ~AUTOFS_INF_EXPIRING;
autofs4_del_expiring(dentry);
complete_all(&ino->expire_complete); complete_all(&ino->expire_complete);
spin_unlock(&sbi->fs_lock); spin_unlock(&sbi->fs_lock);
...@@ -506,7 +503,6 @@ int autofs4_do_expire_multi(struct super_block *sb, struct vfsmount *mnt, ...@@ -506,7 +503,6 @@ int autofs4_do_expire_multi(struct super_block *sb, struct vfsmount *mnt,
ino->flags &= ~AUTOFS_INF_MOUNTPOINT; ino->flags &= ~AUTOFS_INF_MOUNTPOINT;
} }
ino->flags &= ~AUTOFS_INF_EXPIRING; ino->flags &= ~AUTOFS_INF_EXPIRING;
autofs4_del_expiring(dentry);
complete_all(&ino->expire_complete); complete_all(&ino->expire_complete);
spin_unlock(&sbi->fs_lock); spin_unlock(&sbi->fs_lock);
dput(dentry); dput(dentry);
......
...@@ -49,7 +49,6 @@ struct autofs_info *autofs4_init_ino(struct autofs_info *ino, ...@@ -49,7 +49,6 @@ struct autofs_info *autofs4_init_ino(struct autofs_info *ino,
ino->dentry = NULL; ino->dentry = NULL;
ino->size = 0; ino->size = 0;
INIT_LIST_HEAD(&ino->active); INIT_LIST_HEAD(&ino->active);
INIT_LIST_HEAD(&ino->rehash_list);
ino->active_count = 0; ino->active_count = 0;
INIT_LIST_HEAD(&ino->expiring); INIT_LIST_HEAD(&ino->expiring);
atomic_set(&ino->count, 0); atomic_set(&ino->count, 0);
......
...@@ -104,99 +104,6 @@ static void autofs4_del_active(struct dentry *dentry) ...@@ -104,99 +104,6 @@ static void autofs4_del_active(struct dentry *dentry)
return; return;
} }
static void autofs4_add_rehash_entry(struct autofs_info *ino,
struct rehash_entry *entry)
{
entry->task = current;
INIT_LIST_HEAD(&entry->list);
list_add(&entry->list, &ino->rehash_list);
return;
}
static void autofs4_remove_rehash_entry(struct autofs_info *ino)
{
struct list_head *head = &ino->rehash_list;
struct rehash_entry *entry;
list_for_each_entry(entry, head, list) {
if (entry->task == current) {
list_del(&entry->list);
kfree(entry);
break;
}
}
return;
}
static void autofs4_remove_rehash_entrys(struct autofs_info *ino)
{
struct autofs_sb_info *sbi = ino->sbi;
struct rehash_entry *entry, *next;
struct list_head *head;
spin_lock(&sbi->fs_lock);
spin_lock(&sbi->lookup_lock);
if (!(ino->flags & AUTOFS_INF_REHASH)) {
spin_unlock(&sbi->lookup_lock);
spin_unlock(&sbi->fs_lock);
return;
}
ino->flags &= ~AUTOFS_INF_REHASH;
head = &ino->rehash_list;
list_for_each_entry_safe(entry, next, head, list) {
list_del(&entry->list);
kfree(entry);
}
spin_unlock(&sbi->lookup_lock);
spin_unlock(&sbi->fs_lock);
dput(ino->dentry);
return;
}
static void autofs4_revalidate_drop(struct dentry *dentry,
struct rehash_entry *entry)
{
struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
struct autofs_info *ino = autofs4_dentry_ino(dentry);
/*
* Add to the active list so we can pick this up in
* ->lookup(). Also add an entry to a rehash list so
* we know when there are no dentrys in flight so we
* know when we can rehash the dentry.
*/
spin_lock(&sbi->lookup_lock);
if (list_empty(&ino->active))
list_add(&ino->active, &sbi->active_list);
autofs4_add_rehash_entry(ino, entry);
spin_unlock(&sbi->lookup_lock);
if (!(ino->flags & AUTOFS_INF_REHASH)) {
ino->flags |= AUTOFS_INF_REHASH;
dget(dentry);
spin_lock(&dentry->d_lock);
__d_drop(dentry);
spin_unlock(&dentry->d_lock);
}
return;
}
static void autofs4_revalidate_rehash(struct dentry *dentry)
{
struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
struct autofs_info *ino = autofs4_dentry_ino(dentry);
if (ino->flags & AUTOFS_INF_REHASH) {
spin_lock(&sbi->lookup_lock);
autofs4_remove_rehash_entry(ino);
if (list_empty(&ino->rehash_list)) {
spin_unlock(&sbi->lookup_lock);
ino->flags &= ~AUTOFS_INF_REHASH;
d_rehash(dentry);
dput(ino->dentry);
} else
spin_unlock(&sbi->lookup_lock);
}
return;
}
static unsigned int autofs4_need_mount(unsigned int flags) static unsigned int autofs4_need_mount(unsigned int flags)
{ {
unsigned int res = 0; unsigned int res = 0;
...@@ -236,7 +143,7 @@ static int autofs4_dir_open(struct inode *inode, struct file *file) ...@@ -236,7 +143,7 @@ static int autofs4_dir_open(struct inode *inode, struct file *file)
return dcache_dir_open(inode, file); return dcache_dir_open(inode, file);
} }
static int try_to_fill_dentry(struct dentry *dentry) static int try_to_fill_dentry(struct dentry *dentry, int flags)
{ {
struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
struct autofs_info *ino = autofs4_dentry_ino(dentry); struct autofs_info *ino = autofs4_dentry_ino(dentry);
...@@ -249,17 +156,55 @@ static int try_to_fill_dentry(struct dentry *dentry) ...@@ -249,17 +156,55 @@ static int try_to_fill_dentry(struct dentry *dentry)
* Wait for a pending mount, triggering one if there * Wait for a pending mount, triggering one if there
* isn't one already * isn't one already
*/ */
DPRINTK("waiting for mount name=%.*s", if (dentry->d_inode == NULL) {
dentry->d_name.len, dentry->d_name.name); DPRINTK("waiting for mount name=%.*s",
dentry->d_name.len, dentry->d_name.name);
status = autofs4_wait(sbi, dentry, NFY_MOUNT); status = autofs4_wait(sbi, dentry, NFY_MOUNT);
DPRINTK("mount done status=%d", status); DPRINTK("mount done status=%d", status);
/* Update expiry counter */ /* Turn this into a real negative dentry? */
ino->last_used = jiffies; if (status == -ENOENT) {
spin_lock(&sbi->fs_lock);
ino->flags &= ~AUTOFS_INF_PENDING;
spin_unlock(&sbi->fs_lock);
return status;
} else if (status) {
/* Return a negative dentry, but leave it "pending" */
return status;
}
/* Trigger mount for path component or follow link */
} else if (ino->flags & AUTOFS_INF_PENDING ||
autofs4_need_mount(flags) ||
current->link_count) {
DPRINTK("waiting for mount name=%.*s",
dentry->d_name.len, dentry->d_name.name);
return status; spin_lock(&sbi->fs_lock);
ino->flags |= AUTOFS_INF_PENDING;
spin_unlock(&sbi->fs_lock);
status = autofs4_wait(sbi, dentry, NFY_MOUNT);
DPRINTK("mount done status=%d", status);
if (status) {
spin_lock(&sbi->fs_lock);
ino->flags &= ~AUTOFS_INF_PENDING;
spin_unlock(&sbi->fs_lock);
return status;
}
}
/* Initialize expiry counter after successful mount */
if (ino)
ino->last_used = jiffies;
spin_lock(&sbi->fs_lock);
ino->flags &= ~AUTOFS_INF_PENDING;
spin_unlock(&sbi->fs_lock);
return 0;
} }
/* For autofs direct mounts the follow link triggers the mount */ /* For autofs direct mounts the follow link triggers the mount */
...@@ -313,16 +258,10 @@ static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd) ...@@ -313,16 +258,10 @@ static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd)
*/ */
if (ino->flags & AUTOFS_INF_PENDING || if (ino->flags & AUTOFS_INF_PENDING ||
(!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs))) { (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs))) {
ino->flags |= AUTOFS_INF_PENDING;
spin_unlock(&dcache_lock); spin_unlock(&dcache_lock);
spin_unlock(&sbi->fs_lock); spin_unlock(&sbi->fs_lock);
status = try_to_fill_dentry(dentry); status = try_to_fill_dentry(dentry, 0);
spin_lock(&sbi->fs_lock);
ino->flags &= ~AUTOFS_INF_PENDING;
spin_unlock(&sbi->fs_lock);
if (status) if (status)
goto out_error; goto out_error;
...@@ -361,47 +300,18 @@ static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd) ...@@ -361,47 +300,18 @@ static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd)
{ {
struct inode *dir = dentry->d_parent->d_inode; struct inode *dir = dentry->d_parent->d_inode;
struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb); struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb);
struct autofs_info *ino = autofs4_dentry_ino(dentry); int oz_mode = autofs4_oz_mode(sbi);
struct rehash_entry *entry;
int flags = nd ? nd->flags : 0; int flags = nd ? nd->flags : 0;
unsigned int mutex_aquired; int status = 1;
DPRINTK("name = %.*s oz_mode = %d",
dentry->d_name.len, dentry->d_name.name, oz_mode);
/* Daemon never causes a mount to trigger */
if (autofs4_oz_mode(sbi))
return 1;
entry = kmalloc(sizeof(struct rehash_entry), GFP_KERNEL);
if (!entry)
return -ENOMEM;
mutex_aquired = mutex_trylock(&dir->i_mutex);
spin_lock(&sbi->fs_lock);
spin_lock(&dcache_lock);
/* Pending dentry */ /* Pending dentry */
spin_lock(&sbi->fs_lock);
if (autofs4_ispending(dentry)) { if (autofs4_ispending(dentry)) {
int status; /* The daemon never causes a mount to trigger */
/*
* We can only unhash and send this to ->lookup() if
* the directory mutex is held over d_revalidate() and
* ->lookup(). This prevents the VFS from incorrectly
* seeing the dentry as non-existent.
*/
ino->flags |= AUTOFS_INF_PENDING;
if (!mutex_aquired) {
autofs4_revalidate_drop(dentry, entry);
spin_unlock(&dcache_lock);
spin_unlock(&sbi->fs_lock);
return 0;
}
spin_unlock(&dcache_lock);
spin_unlock(&sbi->fs_lock); spin_unlock(&sbi->fs_lock);
mutex_unlock(&dir->i_mutex);
kfree(entry); if (oz_mode)
return 1;
/* /*
* If the directory has gone away due to an expire * If the directory has gone away due to an expire
...@@ -415,82 +325,45 @@ static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd) ...@@ -415,82 +325,45 @@ static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd)
* A zero status is success otherwise we have a * A zero status is success otherwise we have a
* negative error code. * negative error code.
*/ */
status = try_to_fill_dentry(dentry); status = try_to_fill_dentry(dentry, flags);
spin_lock(&sbi->fs_lock);
ino->flags &= ~AUTOFS_INF_PENDING;
spin_unlock(&sbi->fs_lock);
if (status == 0) if (status == 0)
return 1; return 1;
return status; return status;
} }
spin_unlock(&sbi->fs_lock);
/* Negative dentry.. invalidate if "old" */
if (dentry->d_inode == NULL)
return 0;
/* Check for a non-mountpoint directory with no contents */ /* Check for a non-mountpoint directory with no contents */
spin_lock(&dcache_lock);
if (S_ISDIR(dentry->d_inode->i_mode) && if (S_ISDIR(dentry->d_inode->i_mode) &&
!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) { !d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) {
DPRINTK("dentry=%p %.*s, emptydir", DPRINTK("dentry=%p %.*s, emptydir",
dentry, dentry->d_name.len, dentry->d_name.name); dentry, dentry->d_name.len, dentry->d_name.name);
spin_unlock(&dcache_lock);
if (autofs4_need_mount(flags) || current->link_count) { /* The daemon never causes a mount to trigger */
int status; if (oz_mode)
return 1;
/*
* We can only unhash and send this to ->lookup() if
* the directory mutex is held over d_revalidate() and
* ->lookup(). This prevents the VFS from incorrectly
* seeing the dentry as non-existent.
*/
ino->flags |= AUTOFS_INF_PENDING;
if (!mutex_aquired) {
autofs4_revalidate_drop(dentry, entry);
spin_unlock(&dcache_lock);
spin_unlock(&sbi->fs_lock);
return 0;
}
spin_unlock(&dcache_lock);
spin_unlock(&sbi->fs_lock);
mutex_unlock(&dir->i_mutex);
kfree(entry);
/*
* A zero status is success otherwise we have a
* negative error code.
*/
status = try_to_fill_dentry(dentry);
spin_lock(&sbi->fs_lock);
ino->flags &= ~AUTOFS_INF_PENDING;
spin_unlock(&sbi->fs_lock);
if (status == 0) /*
return 1; * A zero status is success otherwise we have a
* negative error code.
*/
status = try_to_fill_dentry(dentry, flags);
if (status == 0)
return 1;
return status; return status;
}
} }
spin_unlock(&dcache_lock); spin_unlock(&dcache_lock);
spin_unlock(&sbi->fs_lock);
if (mutex_aquired)
mutex_unlock(&dir->i_mutex);
kfree(entry);
return 1; return 1;
} }
static void autofs4_free_rehash_entrys(struct autofs_info *inf)
{
struct list_head *head = &inf->rehash_list;
struct rehash_entry *entry, *next;
list_for_each_entry_safe(entry, next, head, list) {
list_del(&entry->list);
kfree(entry);
}
}
void autofs4_dentry_release(struct dentry *de) void autofs4_dentry_release(struct dentry *de)
{ {
struct autofs_info *inf; struct autofs_info *inf;
...@@ -509,8 +382,6 @@ void autofs4_dentry_release(struct dentry *de) ...@@ -509,8 +382,6 @@ void autofs4_dentry_release(struct dentry *de)
list_del(&inf->active); list_del(&inf->active);
if (!list_empty(&inf->expiring)) if (!list_empty(&inf->expiring))
list_del(&inf->expiring); list_del(&inf->expiring);
if (!list_empty(&inf->rehash_list))
autofs4_free_rehash_entrys(inf);
spin_unlock(&sbi->lookup_lock); spin_unlock(&sbi->lookup_lock);
} }
...@@ -543,7 +414,6 @@ static struct dentry *autofs4_lookup_active(struct dentry *dentry) ...@@ -543,7 +414,6 @@ static struct dentry *autofs4_lookup_active(struct dentry *dentry)
const unsigned char *str = name->name; const unsigned char *str = name->name;
struct list_head *p, *head; struct list_head *p, *head;
restart:
spin_lock(&dcache_lock); spin_lock(&dcache_lock);
spin_lock(&sbi->lookup_lock); spin_lock(&sbi->lookup_lock);
head = &sbi->active_list; head = &sbi->active_list;
...@@ -561,19 +431,6 @@ static struct dentry *autofs4_lookup_active(struct dentry *dentry) ...@@ -561,19 +431,6 @@ static struct dentry *autofs4_lookup_active(struct dentry *dentry)
if (atomic_read(&active->d_count) == 0) if (atomic_read(&active->d_count) == 0)
goto next; goto next;
if (active->d_inode && IS_DEADDIR(active->d_inode)) {
if (!list_empty(&ino->rehash_list)) {
dget(active);
spin_unlock(&active->d_lock);
spin_unlock(&sbi->lookup_lock);
spin_unlock(&dcache_lock);
autofs4_remove_rehash_entrys(ino);
dput(active);
goto restart;
}
goto next;
}
qstr = &active->d_name; qstr = &active->d_name;
if (active->d_name.hash != hash) if (active->d_name.hash != hash)
...@@ -586,11 +443,13 @@ static struct dentry *autofs4_lookup_active(struct dentry *dentry) ...@@ -586,11 +443,13 @@ static struct dentry *autofs4_lookup_active(struct dentry *dentry)
if (memcmp(qstr->name, str, len)) if (memcmp(qstr->name, str, len))
goto next; goto next;
dget(active); if (d_unhashed(active)) {
spin_unlock(&active->d_lock); dget(active);
spin_unlock(&sbi->lookup_lock); spin_unlock(&active->d_lock);
spin_unlock(&dcache_lock); spin_unlock(&sbi->lookup_lock);
return active; spin_unlock(&dcache_lock);
return active;
}
next: next:
spin_unlock(&active->d_lock); spin_unlock(&active->d_lock);
} }
...@@ -639,11 +498,13 @@ static struct dentry *autofs4_lookup_expiring(struct dentry *dentry) ...@@ -639,11 +498,13 @@ static struct dentry *autofs4_lookup_expiring(struct dentry *dentry)
if (memcmp(qstr->name, str, len)) if (memcmp(qstr->name, str, len))
goto next; goto next;
dget(expiring); if (d_unhashed(expiring)) {
spin_unlock(&expiring->d_lock); dget(expiring);
spin_unlock(&sbi->lookup_lock); spin_unlock(&expiring->d_lock);
spin_unlock(&dcache_lock); spin_unlock(&sbi->lookup_lock);
return expiring; spin_unlock(&dcache_lock);
return expiring;
}
next: next:
spin_unlock(&expiring->d_lock); spin_unlock(&expiring->d_lock);
} }
...@@ -653,48 +514,6 @@ static struct dentry *autofs4_lookup_expiring(struct dentry *dentry) ...@@ -653,48 +514,6 @@ static struct dentry *autofs4_lookup_expiring(struct dentry *dentry)
return NULL; return NULL;
} }
static struct autofs_info *init_new_dentry(struct autofs_sb_info *sbi,
struct dentry *dentry, int oz_mode)
{
struct autofs_info *ino;
/*
* Mark the dentry incomplete but don't hash it. We do this
* to serialize our inode creation operations (symlink and
* mkdir) which prevents deadlock during the callback to
* the daemon. Subsequent user space lookups for the same
* dentry are placed on the wait queue while the daemon
* itself is allowed passage unresticted so the create
* operation itself can then hash the dentry. Finally,
* we check for the hashed dentry and return the newly
* hashed dentry.
*/
dentry->d_op = &autofs4_root_dentry_operations;
/*
* And we need to ensure that the same dentry is used for
* all following lookup calls until it is hashed so that
* the dentry flags are persistent throughout the request.
*/
ino = autofs4_init_ino(NULL, sbi, 0555);
if (!ino)
return ERR_PTR(-ENOMEM);
dentry->d_fsdata = ino;
ino->dentry = dentry;
/*
* Only set the mount pending flag for new dentrys not created
* by the daemon.
*/
if (!oz_mode)
ino->flags |= AUTOFS_INF_PENDING;
d_instantiate(dentry, NULL);
return ino;
}
/* Lookups in the root directory */ /* Lookups in the root directory */
static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
{ {
...@@ -702,7 +521,6 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s ...@@ -702,7 +521,6 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s
struct autofs_info *ino; struct autofs_info *ino;
struct dentry *expiring, *active; struct dentry *expiring, *active;
int oz_mode; int oz_mode;
int status = 0;
DPRINTK("name = %.*s", DPRINTK("name = %.*s",
dentry->d_name.len, dentry->d_name.name); dentry->d_name.len, dentry->d_name.name);
...@@ -717,26 +535,44 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s ...@@ -717,26 +535,44 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s
DPRINTK("pid = %u, pgrp = %u, catatonic = %d, oz_mode = %d", DPRINTK("pid = %u, pgrp = %u, catatonic = %d, oz_mode = %d",
current->pid, task_pgrp_nr(current), sbi->catatonic, oz_mode); current->pid, task_pgrp_nr(current), sbi->catatonic, oz_mode);
spin_lock(&sbi->fs_lock);
active = autofs4_lookup_active(dentry); active = autofs4_lookup_active(dentry);
if (active) { if (active) {
dentry = active; dentry = active;
ino = autofs4_dentry_ino(dentry); ino = autofs4_dentry_ino(dentry);
/* If this came from revalidate, rehash it */
autofs4_revalidate_rehash(dentry);
spin_unlock(&sbi->fs_lock);
} else { } else {
spin_unlock(&sbi->fs_lock); /*
ino = init_new_dentry(sbi, dentry, oz_mode); * Mark the dentry incomplete but don't hash it. We do this
if (IS_ERR(ino)) * to serialize our inode creation operations (symlink and
return (struct dentry *) ino; * mkdir) which prevents deadlock during the callback to
} * the daemon. Subsequent user space lookups for the same
* dentry are placed on the wait queue while the daemon
* itself is allowed passage unresticted so the create
* operation itself can then hash the dentry. Finally,
* we check for the hashed dentry and return the newly
* hashed dentry.
*/
dentry->d_op = &autofs4_root_dentry_operations;
/*
* And we need to ensure that the same dentry is used for
* all following lookup calls until it is hashed so that
* the dentry flags are persistent throughout the request.
*/
ino = autofs4_init_ino(NULL, sbi, 0555);
if (!ino)
return ERR_PTR(-ENOMEM);
autofs4_add_active(dentry); dentry->d_fsdata = ino;
ino->dentry = dentry;
autofs4_add_active(dentry);
d_instantiate(dentry, NULL);
}
if (!oz_mode) { if (!oz_mode) {
expiring = autofs4_lookup_expiring(dentry);
mutex_unlock(&dir->i_mutex); mutex_unlock(&dir->i_mutex);
expiring = autofs4_lookup_expiring(dentry);
if (expiring) { if (expiring) {
/* /*
* If we are racing with expire the request might not * If we are racing with expire the request might not
...@@ -744,22 +580,23 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s ...@@ -744,22 +580,23 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s
* so it must have been successful, so just wait for it. * so it must have been successful, so just wait for it.
*/ */
autofs4_expire_wait(expiring); autofs4_expire_wait(expiring);
autofs4_del_expiring(expiring);
dput(expiring); dput(expiring);
} }
status = try_to_fill_dentry(dentry);
mutex_lock(&dir->i_mutex);
spin_lock(&sbi->fs_lock); spin_lock(&sbi->fs_lock);
ino->flags &= ~AUTOFS_INF_PENDING; ino->flags |= AUTOFS_INF_PENDING;
spin_unlock(&sbi->fs_lock); spin_unlock(&sbi->fs_lock);
if (dentry->d_op && dentry->d_op->d_revalidate)
(dentry->d_op->d_revalidate)(dentry, nd);
mutex_lock(&dir->i_mutex);
} }
autofs4_del_active(dentry);
/* /*
* If we had a mount fail, check if we had to handle * If we are still pending, check if we had to handle
* a signal. If so we can force a restart.. * a signal. If so we can force a restart..
*/ */
if (status) { if (ino->flags & AUTOFS_INF_PENDING) {
/* See if we were interrupted */ /* See if we were interrupted */
if (signal_pending(current)) { if (signal_pending(current)) {
sigset_t *sigset = &current->pending.signal; sigset_t *sigset = &current->pending.signal;
...@@ -771,46 +608,43 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s ...@@ -771,46 +608,43 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s
return ERR_PTR(-ERESTARTNOINTR); return ERR_PTR(-ERESTARTNOINTR);
} }
} }
} if (!oz_mode) {
spin_lock(&sbi->fs_lock);
/* ino->flags &= ~AUTOFS_INF_PENDING;
* User space can (and has done in the past) remove and re-create spin_unlock(&sbi->fs_lock);
* this directory during the callback. This can leave us with an
* unhashed dentry, but a successful mount! So we need to
* perform another cached lookup in case the dentry now exists.
*/
if (!oz_mode && !have_submounts(dentry)) {
struct dentry *new;
new = d_lookup(dentry->d_parent, &dentry->d_name);
if (new) {
if (active)
dput(active);
return new;
} else {
if (!status)
status = -ENOENT;
} }
} }
/* /*
* If we had a mount failure, return status to user space. * If this dentry is unhashed, then we shouldn't honour this
* If the mount succeeded and we used a dentry from the active queue * lookup. Returning ENOENT here doesn't do the right thing
* return it. * for all system calls, but it should be OK for the operations
* we permit from an autofs.
*/ */
if (status) { if (!oz_mode && d_unhashed(dentry)) {
dentry = ERR_PTR(status);
if (active)
dput(active);
return dentry;
} else {
/* /*
* Valid successful mount, return active dentry or NULL * A user space application can (and has done in the past)
* for a new dentry. * remove and re-create this directory during the callback.
* This can leave us with an unhashed dentry, but a
* successful mount! So we need to perform another
* cached lookup in case the dentry now exists.
*/ */
struct dentry *parent = dentry->d_parent;
struct dentry *new = d_lookup(parent, &dentry->d_name);
if (new != NULL)
dentry = new;
else
dentry = ERR_PTR(-ENOENT);
if (active) if (active)
return active; dput(active);
return dentry;
} }
if (active)
return active;
return NULL; return NULL;
} }
...@@ -834,6 +668,8 @@ static int autofs4_dir_symlink(struct inode *dir, ...@@ -834,6 +668,8 @@ static int autofs4_dir_symlink(struct inode *dir,
if (!ino) if (!ino)
return -ENOMEM; return -ENOMEM;
autofs4_del_active(dentry);
ino->size = strlen(symname); ino->size = strlen(symname);
cp = kmalloc(ino->size + 1, GFP_KERNEL); cp = kmalloc(ino->size + 1, GFP_KERNEL);
if (!cp) { if (!cp) {
...@@ -910,6 +746,7 @@ static int autofs4_dir_unlink(struct inode *dir, struct dentry *dentry) ...@@ -910,6 +746,7 @@ static int autofs4_dir_unlink(struct inode *dir, struct dentry *dentry)
dir->i_mtime = CURRENT_TIME; dir->i_mtime = CURRENT_TIME;
spin_lock(&dcache_lock); spin_lock(&dcache_lock);
autofs4_add_expiring(dentry);
spin_lock(&dentry->d_lock); spin_lock(&dentry->d_lock);
__d_drop(dentry); __d_drop(dentry);
spin_unlock(&dentry->d_lock); spin_unlock(&dentry->d_lock);
...@@ -935,6 +772,7 @@ static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -935,6 +772,7 @@ static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry)
spin_unlock(&dcache_lock); spin_unlock(&dcache_lock);
return -ENOTEMPTY; return -ENOTEMPTY;
} }
autofs4_add_expiring(dentry);
spin_lock(&dentry->d_lock); spin_lock(&dentry->d_lock);
__d_drop(dentry); __d_drop(dentry);
spin_unlock(&dentry->d_lock); spin_unlock(&dentry->d_lock);
...@@ -972,6 +810,8 @@ static int autofs4_dir_mkdir(struct inode *dir, struct dentry *dentry, int mode) ...@@ -972,6 +810,8 @@ static int autofs4_dir_mkdir(struct inode *dir, struct dentry *dentry, int mode)
if (!ino) if (!ino)
return -ENOMEM; return -ENOMEM;
autofs4_del_active(dentry);
inode = autofs4_get_inode(dir->i_sb, ino); inode = autofs4_get_inode(dir->i_sb, ino);
if (!inode) { if (!inode) {
if (!dentry->d_fsdata) if (!dentry->d_fsdata)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册