+ autofs4-nfy_none-wait-race-fix.patch added to -mm tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The patch titled

     autofs4: NFY_NONE wait race fix

has been added to the -mm tree.  Its filename is

     autofs4-nfy_none-wait-race-fix.patch

See http://www.zip.com.au/~akpm/linux/patches/stuff/added-to-mm.txt to find
out what to do about this


From: Ian Kent <raven@xxxxxxxxxx>

This patch fixes two problems.

First, the comparison of entries in the waitq.c was incorrect.

Second, the NFY_NONE check was incorrect. The test of whether the dentry
is mounted if ineffective, for example, if an expire fails then we could
wait forever on a non existant expire. The bug was identified by Jeff
Moyer.

The patch changes autofs4 to wait on expires only as this is all that's
needed.  If there is no existing wait when autofs4_wait is call with a type
of NFY_NONE it delays until either a wait appears or the the expire flag is
cleared.

Signed-off-by: Ian Kent <raven@xxxxxxxxxx>
Signed-off-by: Andrew Morton <akpm@xxxxxxxx>
---

 fs/autofs4/autofs_i.h |    5 +-
 fs/autofs4/root.c     |   10 +----
 fs/autofs4/waitq.c    |   78 +++++++++++++++++++++++++++-------------
 3 files changed, 59 insertions(+), 34 deletions(-)

diff -puN fs/autofs4/autofs_i.h~autofs4-nfy_none-wait-race-fix fs/autofs4/autofs_i.h
--- 25/fs/autofs4/autofs_i.h~autofs4-nfy_none-wait-race-fix	Mon May  8 12:07:23 2006
+++ 25-akpm/fs/autofs4/autofs_i.h	Mon May  8 12:07:23 2006
@@ -74,8 +74,8 @@ struct autofs_wait_queue {
 	struct autofs_wait_queue *next;
 	autofs_wqt_t wait_queue_token;
 	/* We use the following to see what we are waiting for */
-	int hash;
-	int len;
+	unsigned int hash;
+	unsigned int len;
 	char *name;
 	u32 dev;
 	u64 ino;
@@ -85,7 +85,6 @@ struct autofs_wait_queue {
 	pid_t tgid;
 	/* This is for status reporting upon return */
 	int status;
-	atomic_t notify;
 	atomic_t wait_ctr;
 };
 
diff -puN fs/autofs4/root.c~autofs4-nfy_none-wait-race-fix fs/autofs4/root.c
--- 25/fs/autofs4/root.c~autofs4-nfy_none-wait-race-fix	Mon May  8 12:07:23 2006
+++ 25-akpm/fs/autofs4/root.c	Mon May  8 12:07:23 2006
@@ -327,6 +327,7 @@ static int try_to_fill_dentry(struct den
 static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
 	struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
+	struct autofs_info *ino = autofs4_dentry_ino(dentry);
 	int oz_mode = autofs4_oz_mode(sbi);
 	unsigned int lookup_type;
 	int status;
@@ -340,13 +341,8 @@ static void *autofs4_follow_link(struct 
 	if (oz_mode || !lookup_type)
 		goto done;
 
-	/*
-	 * If a request is pending wait for it.
-	 * If it's a mount then it won't be expired till at least
-	 * a liitle later and if it's an expire then we might need
-	 * to mount it again.
-	 */
-	if (autofs4_ispending(dentry)) {
+	/* If an expire request is pending wait for it. */
+	if (ino && (ino->flags & AUTOFS_INF_EXPIRING)) {
 		DPRINTK("waiting for active request %p name=%.*s",
 			dentry, dentry->d_name.len, dentry->d_name.name);
 
diff -puN fs/autofs4/waitq.c~autofs4-nfy_none-wait-race-fix fs/autofs4/waitq.c
--- 25/fs/autofs4/waitq.c~autofs4-nfy_none-wait-race-fix	Mon May  8 12:07:23 2006
+++ 25-akpm/fs/autofs4/waitq.c	Mon May  8 12:12:14 2006
@@ -189,14 +189,30 @@ static int autofs4_getpath(struct autofs
 	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 = NULL;
+
+	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,42 @@ int autofs4_wait(struct autofs_sb_info *
 		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.
+		 */
 
-	if (!wq) {
-		/* Can't wait for an expire if there's no mount */
-		if (notify == NFY_NONE && !d_mountpoint(dentry)) {
+		while (ino->flags & AUTOFS_INF_EXPIRING) {
+			mutex_unlock(&sbi->wq_mutex);
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(HZ/10);
+			if (mutex_lock_interruptible(&sbi->wq_mutex)) {
+				kfree(name);
+				return -EINTR;
+			}
+			wq = autofs4_find_wait(sbi, name, hash, len);
+			if (wq)
+				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) {
 			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 +300,7 @@ int autofs4_wait(struct autofs_sb_info *
 		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 +323,12 @@ int autofs4_wait(struct autofs_sb_info *
 
 		/* 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 */
_

Patches currently in -mm which might be from raven@xxxxxxxxxx are

autofs4-nfy_none-wait-race-fix.patch
autofs4-nfy_none-wait-race-fix-tidy.patch
fs-use-list_move.patch

-
To unsubscribe from this list: send the line "unsubscribe mm-commits" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Kernel Newbies FAQ]     [Kernel Archive]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [Bugtraq]     [Photo]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]

  Powered by Linux