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

Re: shutdown umount hangs



Utz Lehmann wrote:

>
> xfs_unmountfs_writesb pre  strat flags 0xa08017e  pb_iodonesema cnt(0,0)sl
> xfs_unmountfs_writesb prot strat flags 0xa08017e  pb_iodonesema cnt(0,0)sl

   yup the flags are wrong... ok I have another patch for you to try.
I think this will fix the problem.
I haven't tested it yet but you can give it a try if you want.


>
>
> (hangs)
>
> utz

--
Russell Cattelan
--
Digital Elves inc. -- Currently on loan to SGI
Linux XFS core developer.



===========================================================================
linux/fs/pagebuf/page_buf.c
===========================================================================

--- /usr/tmp/TmpDir.17129-0/linux/fs/pagebuf/page_buf.c_1.72	Fri Apr  6 11:51:48 2001
+++ linux/fs/pagebuf/page_buf.c	Fri Apr  6 11:25:53 2001
@@ -2136,6 +2136,7 @@
 	struct list_head *head, *curr;
 	unsigned long save;
 	pagebuf_marker_t *pb_marker_ptr;
+	int lr=1; 
 
 
 	pb_marker_ptr = kmalloc(sizeof(pagebuf_marker_t), GFP_KERNEL);
@@ -2152,73 +2153,58 @@
 	while (curr != head) {
 		pb = list_entry(curr, page_buf_t, pb_list);
 
-		/*
-		 * Skip other markers.
-		 */
-		if (pb->pb_flags == 0 ) { 
-			curr = curr->next;
-			continue;
-		}
 
 		PB_TRACE(pb, PB_TRACE_REC(walkq2), pagebuf_ispin(pb));
 
-		if (pb->pb_target == target) {
-			if (pb->pb_flags & PBF_DELWRI) {
+			  
+		if ((pb->pb_flags == 0) || (pb->pb_target != target) ||
+			!(pb->pb_flags & PBF_DELWRI)) {
+		  curr = curr->next;
+		  continue;
+		}
 
-			  if ((flags & PBDF_PINCOUNT) && pagebuf_ispin(pb)){
-				/* just want a count of the number of pinned buffer */
-				(*pincount)++;
-				curr = curr->next;
-				continue;
-			  }
-
-				pb->pb_flags &= ~PBF_DELWRI;
-				pb->pb_flags |= PBF_WRITE;
-				if (flags & PBDF_WAIT)
-					pb->pb_flags &= ~PBF_ASYNC;
-
-			  	/* insert a place holder */
-				list_add(&pb_marker_ptr->pb_list, curr);
-
-				spin_unlock_irqrestore(
-						&pb_daemon->pb_delwrite_lock,
-						save);
-
-				if (pb->pb_flags & _PBF_LOCKABLE){
-				  if (flags & PBDF_PINCOUNT){
-					/* if we are doing this pin count thing and we can't get the lock just skip it for now */
-					}if (!pagebuf_cond_lock(pb)){
-					  __pagebuf_iorequest(pb);
-					} else {
-					  (*pincount)++;
-					  /* make it async again... don't want to wait on in below */
-					  pb->pb_flags |= PBF_ASYNC;
-					}
-				  }else {
-					pagebuf_lock(pb);
-					__pagebuf_iorequest(pb);
-				  }
-
-				spin_lock_irqsave(
-						&pb_daemon->pb_delwrite_lock,
-						save);
-				/*
-				 * ok got the lock back; pick up the place
-				 * holder and continue on
-				 */
-				curr = pb_marker_ptr->pb_list.next;
-				list_del(&pb_marker_ptr->pb_list);
-			} else {
-				/* not doing anything with current...
-				 * move on to the next one */
-				curr = curr->next;
+		if (!pagebuf_ispin(pb)){
+		  /* insert a place holder */
+		  list_add(&pb_marker_ptr->pb_list, curr);
+		  
+		  spin_unlock_irqrestore(&pb_daemon->pb_delwrite_lock, save);
+		  
+		  /* meta data pagebufs better be lockable pagebuf's */
+		  assert(pb->pb_flags & _PBF_LOCKABLE); 
+		  
+		  if ((flags & (PBDF_WAIT | PBDF_PINCOUNT)) == PBDF_WAIT)
+			lr = pagebuf_lock(pb);
+		  else if (flags &  PBDF_PINCOUNT)
+			lr = pagebuf_cond_lock(pb);
+		  
+		  if (lr == 0){ /* got the lock */
+			/* check the pin count one more time just make sure */
+			if (pagebuf_ispin(pb)){
+			  /* opps somebody bumped the pin count since the last time we checked it */
+			  pagebuf_unlock(pb);
+			  (*pincount)++;
+			  goto out;
 			}
-		} else {
-			/* not doing anything with current...
-			 * move on to the next one */
-			curr = curr->next;
+			  pb->pb_flags &= ~PBF_DELWRI;
+			  pb->pb_flags |= PBF_WRITE;
+			  if (flags & PBDF_WAIT)
+				pb->pb_flags &= ~PBF_ASYNC;
+			  __pagebuf_iorequest(pb);
+			} else  /* didn't get the lock just bump pin count return val*/
+			  (*pincount)++;
+	out:
+		  spin_lock_irqsave(&pb_daemon->pb_delwrite_lock, save);
+		  /*
+		   * ok got the list lock back; pick up the place
+		   * holder and continue on
+		   */
+		  curr = pb_marker_ptr->pb_list.next;
+		  list_del(&pb_marker_ptr->pb_list);
+		} else { /* still pinned */
+		  (*pincount)++;
+		  curr = curr->next;
 		}
-	}
+	} /* while */
 
 	spin_unlock_irqrestore(&pb_daemon->pb_delwrite_lock, save);
 
@@ -2238,63 +2224,45 @@
 	 * order to synchronize with it.
 	 */
 
-
 	/* Now do that again, just waiting for the lock */
 	spin_lock_irqsave(&pb_daemon->pb_delwrite_lock, flags);
 
 	head = curr = &pb_daemon->pb_delwrite_l;
 	curr = curr->next;
 
-
 	while (curr != head) {
 
 		pb = list_entry(curr, page_buf_t, pb_list);
 
 		/*
 		 * Skip other markers.
-		 */
-		if (pb->pb_flags == 0 ) { 
-			curr = curr->next;
-			continue;
-		}
-
-		/*
 		 * Skip pagebuf's that may have been added
 		 * after the previous loop initiated I/O.
 		 */
-		if (pb->pb_flags & PBF_DELWRI) {
+		if ((pb->pb_flags == 0) ||(pb->pb_flags & PBF_DELWRI)
+			|| !(pb->pb_flags & PBF_ASYNC)
+			|| !(pb->pb_target == target)) { 
 			curr = curr->next;
 			continue;
 		}
 
 		PB_TRACE(pb, PB_TRACE_REC(walkq3), pagebuf_ispin(pb));
 
-		if (pb->pb_target == target) {
-			int	sync = (pb->pb_flags & PBF_ASYNC) == 0;
-			list_add(&pb_marker_ptr->pb_list, curr);
-
-			spin_unlock_irqrestore(
-					&pb_daemon->pb_delwrite_lock,
-					flags);
-
-			if (sync) {
-				pagebuf_iowait(pb);
-				pb->pb_flags |= PBF_ASYNC;
-				pagebuf_delwri_dequeue(pb);
-				if (!pb->pb_relse)
-					pagebuf_unlock(pb);
-				pagebuf_rele(pb);
-			}
+		list_add(&pb_marker_ptr->pb_list, curr);
+		
+		spin_unlock_irqrestore(&pb_daemon->pb_delwrite_lock, flags);
+
+		pagebuf_iowait(pb);
+		pb->pb_flags |= PBF_ASYNC;
+		pagebuf_delwri_dequeue(pb);
+		if (!pb->pb_relse)
+		  pagebuf_unlock(pb);
+		pagebuf_rele(pb);
+		
+		spin_lock_irqsave( &pb_daemon->pb_delwrite_lock, flags);
 
-			spin_lock_irqsave(
-					&pb_daemon->pb_delwrite_lock,
-					flags);
-
-			curr = pb_marker_ptr->pb_list.next;
-			list_del(&pb_marker_ptr->pb_list);
-		} else {
-			curr = curr->next;
-		}
+		curr = pb_marker_ptr->pb_list.next;
+		list_del(&pb_marker_ptr->pb_list);
 	}
 
 	spin_unlock_irqrestore(&pb_daemon->pb_delwrite_lock, flags);

===========================================================================
linux/fs/xfs/xfs_buf.h
===========================================================================

--- /usr/tmp/TmpDir.17129-0/linux/fs/xfs/xfs_buf.h_1.70	Fri Apr  6 11:51:48 2001
+++ linux/fs/xfs/xfs_buf.h	Fri Apr  6 11:15:28 2001
@@ -317,7 +317,7 @@
 #define xfs_iowait(pb)              \
 	    pagebuf_iowait(pb)
 
-#define xfs_binval(buftarg) /* NOT used with pagebufs... do nothing */
+#define xfs_binval(buftarg) XFS_bflush(buftarg)
 
 extern void XFS_bflush(buftarg_t);
 

===========================================================================
linux/fs/xfs/xfs_mount.c
===========================================================================

--- /usr/tmp/TmpDir.17129-0/linux/fs/xfs/xfs_mount.c_1.249	Fri Apr  6 11:51:48 2001
+++ linux/fs/xfs/xfs_mount.c	Fri Apr  6 11:20:20 2001
@@ -29,7 +29,7 @@
  * 
  * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
  */
-
+#define _PAGE_BUF_INTERNAL_
 #include <xfs.h>
 
 
@@ -1075,12 +1075,13 @@
 	xfs_buf_t	*sbp;
 	xfs_sb_t	*sb;
 	int		error = 0;
-
+	page_buf_private_t *pb;
 	/*
 	 * skip superblock write if fs is read-only, or
 	 * if we are doing a forced umount.
 	 */
 	sbp = xfs_getsb(mp, 0);
+	pb = (page_buf_private_t *)sbp;
 	if (!(XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY ||
 		XFS_FORCED_SHUTDOWN(mp))) {
 		/*
@@ -1099,8 +1100,19 @@
 		XFS_BUF_UNREAD(sbp);
 		XFS_BUF_WRITE(sbp);
 		xfs_bwait_unpin(sbp);
+		/* the next two lines added for linux port 
+		 * make sure the superblock buffer won't simply
+		 * get requeued. If delwri or async is set iowait will never see
+		 * the iodone up(pb_iodonesema)
+		 */
+		XFS_BUF_UNDELAYWRITE(sbp);
+		XFS_BUF_UNASYNC(sbp);
 		ASSERT(XFS_BUF_TARGET(sbp) == mp->m_dev);
+		printk ("xfs_unmountfs_writesb pre  strat flags 0x%x  pb_iodonesema cnt(%d,%d)sl\n",
+				sbp->pb_flags,pb->pb_iodonesema.count.counter, pb->pb_iodonesema.sleepers);
 		xfsbdstrat(mp, sbp);
+		printk ("xfs_unmountfs_writesb prot strat flags 0x%x  pb_iodonesema cnt(%d,%d)sl\n",
+				sbp->pb_flags,pb->pb_iodonesema.count.counter, pb->pb_iodonesema.sleepers);
 		/* Nevermind errors we might get here. */
 		error = xfs_iowait(sbp);
 		if (error && mp->m_mk_sharedro)