Messages in this thread Patch in this message | | | Date | Sat, 21 Feb 1998 09:33:30 -0500 | From | Bill Hawes <> | Subject | Re: 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); | |