lkml.org 
[lkml]   [1998]   [Feb]   [21]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
SubjectRe: Hang in wait_on_inode with SMP 2.1.87
Carsten Gross wrote:

> Today, I started a 'df' and the 'df' hung. I used ps -afxl to have a look on
> the process state. And 'df' hung in "wait_on_inode" with status
> 'uninterruptible sleep'. The 'bdflush' process was in the same state, no
> write access to the disks were possible until reboot. (A sync hung too, also
> in "wait_on_inode")

> I cannot find a function actually removing the I_LOCK flag? Yes, sync_one
> does, but checks for I_LOCK presence before. I think 'get_new_inode' is only
> for new inodes? Would someone of the kernel experts have a look on this,
> please? Thanks a lot for your work.

Hi Carsten,

I looked over the inode code and it appears to me that a wakeup is done whenever
the I_LOCK flag is cleared. It might be possible for the inode i_state field to
get trashed somehow, so it would be very helpful if you could determine which
filesystem's inode is getting stuck. Did this problem just start recently?

I've attached a patch with some debugging code that may help track things down.
It enables a magic sysreq option to display a table of the inode state on
alt-sysrq-i, so if you could get your system to hang again and then dispay the
inode table, we may get some addditional clues.

Regards,
Bill--- linux-2.1.88/fs/inode.c.old Wed Feb 11 00:06:11 1998
+++ linux-2.1.88/fs/inode.c Sat Feb 21 10:14:02 1998
@@ -674,6 +710,11 @@
op->put_inode(inode);

spin_lock(&inode_lock);
+#ifdef INODE_PARANOIA
+if (!inode->i_count)
+printk("iput: device %s inode %ld already free\n",
+kdevname(inode->i_dev), inode->i_ino);
+#endif
if (!--inode->i_count) {
if (!inode->i_nlink) {
list_del(&inode->i_hash);
@@ -686,6 +727,14 @@
delete(inode);
spin_lock(&inode_lock);
}
+#ifdef INODE_PARANOIA
+if (!list_empty(&inode->i_hash))
+printk("iput: device %s inode %ld rehashed\n",
+kdevname(inode->i_dev), inode->i_ino);
+if (!list_empty(&inode->i_list))
+printk("iput: device %s inode %ld reinserted\n",
+kdevname(inode->i_dev), inode->i_ino);
+#endif
}
if (list_empty(&inode->i_hash)) {
list_del(&inode->i_list);
@@ -701,19 +750,22 @@
list_add(&inode->i_list, inode_in_use.prev);
}
#ifdef INODE_PARANOIA
+if (inode->i_flock)
+printk(KERN_ERR "iput: inode %s/%ld still has locks!\n",
+kdevname(inode->i_dev), inode->i_ino);
if (!list_empty(&inode->i_dentry))
-printk("iput: device %s inode %ld still has aliases!\n",
+printk(KERN_ERR "iput: device %s inode %ld still has aliases!\n",
kdevname(inode->i_dev), inode->i_ino);
if (inode->i_count)
-printk("iput: device %s inode %ld count changed, count=%d\n",
+printk(KERN_ERR "iput: device %s inode %ld count changed, count=%d\n",
kdevname(inode->i_dev), inode->i_ino, inode->i_count);
if (atomic_read(&inode->i_sem.count) != 1)
-printk("iput: Aieee, semaphore in use device %s, count=%d\n",
+printk(KERN_ERR "iput: Aieee, semaphore in use device %s, count=%d\n",
kdevname(inode->i_dev), atomic_read(&inode->i_sem.count));
#endif
}
- if (inode->i_count > (1<<15)) {
- printk("iput: device %s inode %ld count wrapped\n",
+ if (inode->i_count > (1<<31)) {
+ printk(KERN_ERR "iput: inode %s/%ld count wrapped\n",
kdevname(inode->i_dev), inode->i_ino);
}
spin_unlock(&inode_lock);
@@ -770,3 +822,84 @@
inode->i_atime = CURRENT_TIME;
mark_inode_dirty (inode);
} /* End Function update_atime */
+
+extern void show_inodes(void);
+/*
+ * Displays the attributes for the inodes in the specified list.
+ */
+static int show_inode_list(struct list_head *head, char *label, int *tot_pages)
+{
+ extern struct inode_operations pipe_inode_operations;
+ struct list_head *tmp;
+ struct inode *inode;
+ int found = 0, pages = 0;
+ int used, hashed, linked, locked, dirty, pipe, socket, bad;
+
+ used = hashed = linked = locked = dirty = pipe = socket = bad = 0;
+ for (tmp = head->next; tmp != head; tmp = tmp->next) {
+ found++;
+
+ inode = list_entry(tmp, struct inode, i_list);
+ if (inode->i_count > 0)
+ used++;
+ if (!list_empty(&inode->i_hash))
+ hashed++;
+ if (inode->i_nlink)
+ linked++;
+ if (inode->i_state & I_LOCK)
+ locked++;
+ if (inode->i_state & I_DIRTY)
+ dirty++;
+ if (inode->i_op == &pipe_inode_operations)
+ pipe++;
+ if (inode->i_sock)
+ socket++;
+ /*
+ * Count the number of cache pages.
+ */
+ pages += inode->i_nrpages;
+
+ /*
+ * Check for problems ... these shouldn't happen.
+ */
+ if (inode->i_count >= (1 << 31) ||
+ (inode->i_state & ~(I_LOCK | I_DIRTY)))
+ bad++;
+ }
+
+ printk("%6s %6d%6d%6d%6d%6d%6d%6d%6d%6d %6d\n",
+ label, found, used, hashed, linked, locked, dirty, pipe, socket,
+ bad, pages);
+ *tot_pages += pages;
+ return found;
+}
+
+/*
+ * Displays a table of attributes for the inodes in each list.
+ */
+void show_inodes(void)
+{
+ struct super_block * sb = &super_blocks[0];
+ int i, accounted = 0, tot_pages = 0;
+ static char *list_types[2] = {"UNUSED", "CLEAN "};
+
+ printk("Inodes Allocated: %d\n", inodes_stat.nr_inodes);
+ printk("List Inodes Used Hash Link Lock Dirt Pipe Sock"
+ " Odd? Pages\n");
+
+ spin_lock(&inode_lock);
+ accounted += show_inode_list(&inode_unused, list_types[0], &tot_pages);
+ accounted += show_inode_list(&inode_in_use, list_types[1], &tot_pages);
+ /*
+ * Loop through super blocks
+ */
+ for (i = NR_SUPER; i--; sb++) {
+ if (!sb->s_dev)
+ continue;
+ accounted += show_inode_list(&sb->s_dirty, kdevname(sb->s_dev),
+ &tot_pages);
+ }
+ spin_unlock(&inode_lock);
+
+ printk("Inodes Accounted: %d Total Pages: %d\n", accounted, tot_pages);
+}
--- linux-2.1.88/drivers/char/sysrq.c.old Wed Feb 11 00:06:01 1998
+++ linux-2.1.88/drivers/char/sysrq.c Sat Feb 21 09:59:18 1998
@@ -27,6 +27,7 @@
#endif

extern void wakeup_bdflush(int);
+extern void show_inodes(void);
extern void reset_vc(unsigned int);
extern int console_loglevel;
extern struct vfsmount *vfsmntlist;
@@ -103,7 +104,11 @@
printk("Show State\n");
show_state();
break;
- case 'm': /* M -- show memory info */
+ case 'i': /* I -- show inodes */
+ printk("Show Inodes\n");
+ show_inodes();
+ break;
+ case 'm': /* M -- show memory info */
printk("Show Memory\n");
show_mem();
break;
@@ -116,11 +121,13 @@
send_sig_all(SIGTERM, 0);
orig_log_level = 8; /* We probably have killed syslogd */
break;
+#if 0
case 'i': /* I -- kill all user processes */
printk("Kill All Tasks\n");
send_sig_all(SIGKILL, 0);
orig_log_level = 8;
break;
+#endif
case 'l': /* L -- kill all processes including init */
printk("Kill ALL Tasks (even init)\n");
send_sig_all(SIGKILL, 1);
\
 
 \ /
  Last update: 2005-03-22 13:41    [from the cache]
©2003-2014 Jasper Spaans. Advertise on this site