|
@@ -189,14 +189,30 @@ static int autofs4_getpath(struct autofs_sb_info *sbi,
|
|
|
return len;
|
|
|
}
|
|
|
|
|
|
+static struct autofs_wait_queue *
|
|
|
+autofs4_find_wait(struct autofs_sb_info *sbi,
|
|
|
+ char *name, unsigned int hash, unsigned int len)
|
|
|
+{
|
|
|
+ struct autofs_wait_queue *wq;
|
|
|
+
|
|
|
+ for (wq = sbi->queues; wq; wq = wq->next) {
|
|
|
+ if (wq->hash == hash &&
|
|
|
+ wq->len == len &&
|
|
|
+ wq->name && !memcmp(wq->name, name, len))
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ return wq;
|
|
|
+}
|
|
|
+
|
|
|
int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry,
|
|
|
enum autofs_notify notify)
|
|
|
{
|
|
|
+ struct autofs_info *ino;
|
|
|
struct autofs_wait_queue *wq;
|
|
|
char *name;
|
|
|
unsigned int len = 0;
|
|
|
unsigned int hash = 0;
|
|
|
- int status;
|
|
|
+ int status, type;
|
|
|
|
|
|
/* In catatonic mode, we don't wait for nobody */
|
|
|
if (sbi->catatonic)
|
|
@@ -223,21 +239,41 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry,
|
|
|
return -EINTR;
|
|
|
}
|
|
|
|
|
|
- for (wq = sbi->queues ; wq ; wq = wq->next) {
|
|
|
- if (wq->hash == dentry->d_name.hash &&
|
|
|
- wq->len == len &&
|
|
|
- wq->name && !memcmp(wq->name, name, len))
|
|
|
- break;
|
|
|
- }
|
|
|
+ wq = autofs4_find_wait(sbi, name, hash, len);
|
|
|
+ ino = autofs4_dentry_ino(dentry);
|
|
|
+ if (!wq && ino && notify == NFY_NONE) {
|
|
|
+ /*
|
|
|
+ * Either we've betean the pending expire to post it's
|
|
|
+ * wait or it finished while we waited on the mutex.
|
|
|
+ * So we need to wait till either, the wait appears
|
|
|
+ * or the expire finishes.
|
|
|
+ */
|
|
|
+
|
|
|
+ while (ino->flags & AUTOFS_INF_EXPIRING) {
|
|
|
+ mutex_unlock(&sbi->wq_mutex);
|
|
|
+ schedule_timeout_interruptible(HZ/10);
|
|
|
+ if (mutex_lock_interruptible(&sbi->wq_mutex)) {
|
|
|
+ kfree(name);
|
|
|
+ return -EINTR;
|
|
|
+ }
|
|
|
+ wq = autofs4_find_wait(sbi, name, hash, len);
|
|
|
+ if (wq)
|
|
|
+ break;
|
|
|
+ }
|
|
|
|
|
|
- if (!wq) {
|
|
|
- /* Can't wait for an expire if there's no mount */
|
|
|
- if (notify == NFY_NONE && !d_mountpoint(dentry)) {
|
|
|
+ /*
|
|
|
+ * Not ideal but the status has already gone. Of the two
|
|
|
+ * cases where we wait on NFY_NONE neither depend on the
|
|
|
+ * return status of the wait.
|
|
|
+ */
|
|
|
+ if (!wq) {
|
|
|
kfree(name);
|
|
|
mutex_unlock(&sbi->wq_mutex);
|
|
|
- return -ENOENT;
|
|
|
+ return 0;
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
+ if (!wq) {
|
|
|
/* Create a new wait queue */
|
|
|
wq = kmalloc(sizeof(struct autofs_wait_queue),GFP_KERNEL);
|
|
|
if (!wq) {
|
|
@@ -263,20 +299,7 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry,
|
|
|
wq->tgid = current->tgid;
|
|
|
wq->status = -EINTR; /* Status return if interrupted */
|
|
|
atomic_set(&wq->wait_ctr, 2);
|
|
|
- atomic_set(&wq->notify, 1);
|
|
|
- mutex_unlock(&sbi->wq_mutex);
|
|
|
- } else {
|
|
|
- atomic_inc(&wq->wait_ctr);
|
|
|
mutex_unlock(&sbi->wq_mutex);
|
|
|
- kfree(name);
|
|
|
- DPRINTK("existing wait id = 0x%08lx, name = %.*s, nfy=%d",
|
|
|
- (unsigned long) wq->wait_queue_token, wq->len, wq->name, notify);
|
|
|
- }
|
|
|
-
|
|
|
- if (notify != NFY_NONE && atomic_read(&wq->notify)) {
|
|
|
- int type;
|
|
|
-
|
|
|
- atomic_dec(&wq->notify);
|
|
|
|
|
|
if (sbi->version < 5) {
|
|
|
if (notify == NFY_MOUNT)
|
|
@@ -299,6 +322,12 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry,
|
|
|
|
|
|
/* autofs4_notify_daemon() may block */
|
|
|
autofs4_notify_daemon(sbi, wq, type);
|
|
|
+ } else {
|
|
|
+ atomic_inc(&wq->wait_ctr);
|
|
|
+ mutex_unlock(&sbi->wq_mutex);
|
|
|
+ kfree(name);
|
|
|
+ DPRINTK("existing wait id = 0x%08lx, name = %.*s, nfy=%d",
|
|
|
+ (unsigned long) wq->wait_queue_token, wq->len, wq->name, notify);
|
|
|
}
|
|
|
|
|
|
/* wq->name is NULL if and only if the lock is already released */
|