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    [W:0.030 / U:30.876 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site