X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;ds=sidebyside;f=fs%2Fautofs4%2Fwaitq.c;h=394ff36ef8f19ec84a4f26a0c1a96e2badb7cb84;hb=987b0145d94eecf292d8b301228356f44611ab7c;hp=ce103e7b0bc360f684a2556c55ea9ed8be0e38f2;hpb=e6a27dba1cf83d871b2dfcd64f04f12a67e3f4d5;p=linux-2.6.git diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c index ce103e7b0..394ff36ef 100644 --- a/fs/autofs4/waitq.c +++ b/fs/autofs4/waitq.c @@ -3,7 +3,7 @@ * linux/fs/autofs/waitq.c * * Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved - * Copyright 2001-2006 Ian Kent + * Copyright 2001-2003 Ian Kent * * This file is part of the Linux kernel and is made available under * the terms of the GNU General Public License, version 2, or at your @@ -33,7 +33,7 @@ void autofs4_catatonic_mode(struct autofs_sb_info *sbi) sbi->catatonic = 1; wq = sbi->queues; sbi->queues = NULL; /* Erase all wait queues */ - while (wq) { + while ( wq ) { nwq = wq->next; wq->status = -ENOENT; /* Magic is gone - report failure */ kfree(wq->name); @@ -45,6 +45,7 @@ void autofs4_catatonic_mode(struct autofs_sb_info *sbi) fput(sbi->pipe); /* Close the pipe */ sbi->pipe = NULL; } + shrink_dcache_sb(sbi->sb); } @@ -97,10 +98,7 @@ static void autofs4_notify_daemon(struct autofs_sb_info *sbi, pkt.hdr.proto_version = sbi->version; pkt.hdr.type = type; - switch (type) { - /* Kernel protocol v4 missing and expire packets */ - case autofs_ptype_missing: - { + if (type == autofs_ptype_missing) { struct autofs_packet_missing *mp = &pkt.missing; pktsz = sizeof(*mp); @@ -109,10 +107,7 @@ static void autofs4_notify_daemon(struct autofs_sb_info *sbi, mp->len = wq->len; memcpy(mp->name, wq->name, wq->len); mp->name[wq->len] = '\0'; - break; - } - case autofs_ptype_expire_multi: - { + } else if (type == autofs_ptype_expire_multi) { struct autofs_packet_expire_multi *ep = &pkt.expire_multi; pktsz = sizeof(*ep); @@ -121,34 +116,7 @@ static void autofs4_notify_daemon(struct autofs_sb_info *sbi, ep->len = wq->len; memcpy(ep->name, wq->name, wq->len); ep->name[wq->len] = '\0'; - break; - } - /* - * Kernel protocol v5 packet for handling indirect and direct - * mount missing and expire requests - */ - case autofs_ptype_missing_indirect: - case autofs_ptype_expire_indirect: - case autofs_ptype_missing_direct: - case autofs_ptype_expire_direct: - { - struct autofs_v5_packet *packet = &pkt.v5_packet; - - pktsz = sizeof(*packet); - - packet->wait_queue_token = wq->wait_queue_token; - packet->len = wq->len; - memcpy(packet->name, wq->name, wq->len); - packet->name[wq->len] = '\0'; - packet->dev = wq->dev; - packet->ino = wq->ino; - packet->uid = wq->uid; - packet->gid = wq->gid; - packet->pid = wq->pid; - packet->tgid = wq->tgid; - break; - } - default: + } else { printk("autofs4_notify_daemon: bad type %d!\n", type); return; } @@ -189,96 +157,52 @@ 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, type; + int len, status; /* In catatonic mode, we don't wait for nobody */ - if (sbi->catatonic) + if ( sbi->catatonic ) return -ENOENT; name = kmalloc(NAME_MAX + 1, GFP_KERNEL); if (!name) return -ENOMEM; - /* If this is a direct mount request create a dummy name */ - if (IS_ROOT(dentry) && (sbi->type & AUTOFS_TYPE_DIRECT)) - len = sprintf(name, "%p", dentry); - else { - len = autofs4_getpath(sbi, dentry, &name); - if (!len) { - kfree(name); - return -ENOENT; - } + len = autofs4_getpath(sbi, dentry, &name); + if (!len) { + kfree(name); + return -ENOENT; } - hash = full_name_hash(name, len); - if (mutex_lock_interruptible(&sbi->wq_mutex)) { + if (down_interruptible(&sbi->wq_sem)) { kfree(name); return -EINTR; } - 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; - } + 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; + } - /* - * 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) { + if ( !wq ) { + /* Can't wait for an expire if there's no mount */ + if (notify == NFY_NONE && !d_mountpoint(dentry)) { kfree(name); - mutex_unlock(&sbi->wq_mutex); - return 0; + up(&sbi->wq_sem); + return -ENOENT; } - } - if (!wq) { /* Create a new wait queue */ wq = kmalloc(sizeof(struct autofs_wait_queue),GFP_KERNEL); - if (!wq) { + if ( !wq ) { kfree(name); - mutex_unlock(&sbi->wq_mutex); + up(&sbi->wq_sem); return -ENOMEM; } @@ -288,58 +212,42 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry, wq->next = sbi->queues; sbi->queues = wq; init_waitqueue_head(&wq->queue); - wq->hash = hash; + wq->hash = dentry->d_name.hash; wq->name = name; wq->len = len; - wq->dev = autofs4_get_dev(sbi); - wq->ino = autofs4_get_ino(sbi); - wq->uid = current->uid; - wq->gid = current->gid; - wq->pid = current->pid; - wq->tgid = current->tgid; wq->status = -EINTR; /* Status return if interrupted */ atomic_set(&wq->wait_ctr, 2); - mutex_unlock(&sbi->wq_mutex); - - if (sbi->version < 5) { - if (notify == NFY_MOUNT) - type = autofs_ptype_missing; - else - type = autofs_ptype_expire_multi; - } else { - if (notify == NFY_MOUNT) - type = (sbi->type & AUTOFS_TYPE_DIRECT) ? - autofs_ptype_missing_direct : - autofs_ptype_missing_indirect; - else - type = (sbi->type & AUTOFS_TYPE_DIRECT) ? - autofs_ptype_expire_direct : - autofs_ptype_expire_indirect; - } + atomic_set(&wq->notified, 1); + up(&sbi->wq_sem); + } else { + atomic_inc(&wq->wait_ctr); + up(&sbi->wq_sem); + 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_dec_and_test(&wq->notified)) { + int type = (notify == NFY_MOUNT ? + autofs_ptype_missing : autofs_ptype_expire_multi); DPRINTK("new wait id = 0x%08lx, name = %.*s, nfy=%d\n", (unsigned long) wq->wait_queue_token, wq->len, wq->name, notify); /* 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 */ - if (sbi->catatonic) { + if ( sbi->catatonic ) { /* We might have slept, so check again for catatonic mode */ wq->status = -ENOENT; kfree(wq->name); wq->name = NULL; } - if (wq->name) { + if ( wq->name ) { /* Block all but "shutdown" signals while waiting */ sigset_t oldset; unsigned long irqflags; @@ -374,19 +282,19 @@ int autofs4_wait_release(struct autofs_sb_info *sbi, autofs_wqt_t wait_queue_tok { struct autofs_wait_queue *wq, **wql; - mutex_lock(&sbi->wq_mutex); - for (wql = &sbi->queues ; (wq = *wql) != 0 ; wql = &wq->next) { - if (wq->wait_queue_token == wait_queue_token) + down(&sbi->wq_sem); + for ( wql = &sbi->queues ; (wq = *wql) != 0 ; wql = &wq->next ) { + if ( wq->wait_queue_token == wait_queue_token ) break; } - if (!wq) { - mutex_unlock(&sbi->wq_mutex); + if ( !wq ) { + up(&sbi->wq_sem); return -EINVAL; } *wql = wq->next; /* Unlink from chain */ - mutex_unlock(&sbi->wq_mutex); + up(&sbi->wq_sem); kfree(wq->name); wq->name = NULL; /* Do not wait on this queue */