Linux Headquarters
[ Register ]
[ About us ] [ Home Page ]

[ Kernel ] [ Documentation ] [ Links ] [ Books ]

Advertisement

Kernel v2.4.13-ac8 /fs/inode.c

Filename:/fs/inode.c
Lines Added:63
Lines Deleted:64
Also changed in: (Previous) 2.4.13-ac7  2.4.13-ac6  2.4.13-ac5  2.4.13-ac4  2.4.13-ac3  2.4.13-ac1 
(Following) 2.4.15-pre6  2.4.15-pre7  2.4.15-pre8  2.4.15-pre9  2.4.15-greased-turkey  2.4.16-pre1 

Location
[  2.4.13-ac8
  [  fs
     o  inode.c

Patch

diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/inode.c linux.ac/fs/inode.c
--- linux.vanilla/fs/inode.c   Thu Oct 11 13:52:13 2001
+++ linux.ac/fs/inode.c   Thu Oct 11 15:07:26 2001
@@ -16,7 +16,6 @@
 #include <linux/swap.h>
 #include <linux/swapctl.h>
 #include <linux/prefetch.h>
-#include <linux/locks.h>
 
 /*
  * New inode.c implementation.
@@ -79,7 +78,7 @@
     ((struct inode *) kmem_cache_alloc(inode_cachep, SLAB_KERNEL))
 static void destroy_inode(struct inode *inode) 
 {
-   if (inode_has_buffers(inode))
+   if (!list_empty(&inode->i_dirty_buffers))
       BUG();
    kmem_cache_free(inode_cachep, (inode));
 }
@@ -105,8 +104,8 @@
       INIT_LIST_HEAD(&inode->i_data.locked_pages);
       INIT_LIST_HEAD(&inode->i_dentry);
       INIT_LIST_HEAD(&inode->i_dirty_buffers);
-      INIT_LIST_HEAD(&inode->i_dirty_data_buffers);
       INIT_LIST_HEAD(&inode->i_devices);
+       init_rwsem(&inode->i_truncate_sem);   
       sema_init(&inode->i_sem, 1);
       sema_init(&inode->i_zombie, 1);
       spin_lock_init(&inode->i_data.i_shared_lock);
@@ -138,9 +137,6 @@
 {
    struct super_block * sb = inode->i_sb;
 
-   if (!sb)
-      return;
-
    /* Don't do this for I_DIRTY_PAGES - that doesn't actually dirty the inode itself */
    if (flags & (I_DIRTY_SYNC | I_DIRTY_DATASYNC)) {
       if (sb->s_op && sb->s_op->dirty_inode)
@@ -279,18 +275,27 @@
    }
 }
 
-static inline int try_to_sync_unused_list(struct list_head *head, int nr_inodes)
+static inline int try_to_sync_unused_list(struct list_head *head)
 {
    struct list_head *tmp = head;
    struct inode *inode;
 
-   while (nr_inodes && (tmp = tmp->prev) != head) {
+   while ((tmp = tmp->prev) != head) {
       inode = list_entry(tmp, struct inode, i_list);
 
       if (!atomic_read(&inode->i_count)) {
-         __sync_one(inode, 0);
-         nr_inodes--;
+         /* 
+          * We're under PF_MEMALLOC here, and syncing the 
+          * inode may have to allocate memory. To avoid
+          * running into a OOM deadlock, we write one 
+          * inode synchronously and stop syncing in case 
+          * we're under freepages.low
+          */
 
+         int sync = nr_free_pages() < freepages.low;
+         __sync_one(inode, sync);
+         if (sync) 
+            return 0;
          /* 
           * __sync_one moved the inode to another list,
           * so we have to start looking from the list head.
@@ -298,8 +303,7 @@
          tmp = head;
       }
    }
-
-   return nr_inodes;
+   return 1;
 }
 
 void sync_inodes_sb(struct super_block *sb)
@@ -395,25 +399,26 @@
    }
 }
 
-static void try_to_sync_unused_inodes(void * arg)
+/*
+ * Called with the spinlock already held..
+ */
+static void try_to_sync_unused_inodes(void)
 {
    struct super_block * sb;
-   int nr_inodes = inodes_stat.nr_unused;
 
-   spin_lock(&inode_lock);
    spin_lock(&sb_lock);
    sb = sb_entry(super_blocks.next);
-   for (; nr_inodes && sb != sb_entry(&super_blocks); sb = sb_entry(sb->s_list.next)) {
+   for (; sb != sb_entry(&super_blocks); sb = sb_entry(sb->s_list.next)) {
+      if (!sb->s_dev)
+         continue;
       spin_unlock(&sb_lock);
-      nr_inodes = try_to_sync_unused_list(&sb->s_dirty, nr_inodes);
+      if (!try_to_sync_unused_list(&sb->s_dirty))
+         return;
       spin_lock(&sb_lock);
    }
    spin_unlock(&sb_lock);
-   spin_unlock(&inode_lock);
 }
 
-static struct tq_struct unused_inodes_flush_task;
-
 /**
  *   write_inode_now   -   write an inode to disk
  *   @inode: inode to write to disk
@@ -432,8 +437,6 @@
       while (inode->i_state & I_DIRTY)
          sync_one(inode, sync);
       spin_unlock(&inode_lock);
-      if (sync)
-         wait_on_inode(inode);
    }
    else
       printk(KERN_ERR "write_inode_now: no super block\n");
@@ -448,9 +451,9 @@
  * O_SYNC flag set, to flush dirty writes to disk.  
  */
 
-int generic_osync_inode(struct inode *inode, int what)
+int generic_osync_inode(struct inode *inode, int datasync)
 {
-   int err = 0, err2 = 0, need_write_inode_now = 0;
+   int err;
    
    /* 
     * WARNING
@@ -473,24 +476,23 @@
     * every O_SYNC write, not just the synchronous I/Os.  --sct
     */
 
-   if (what & OSYNC_METADATA)
-      err = fsync_inode_buffers(inode);
-   if (what & OSYNC_DATA)
-      err2 = fsync_inode_data_buffers(inode);
-   if (!err)
-      err = err2;
+#ifdef WRITERS_QUEUE_IO
+   err = osync_inode_buffers(inode);
+#else
+   err = fsync_inode_buffers(inode);
+#endif
 
    spin_lock(&inode_lock);
-   if ((inode->i_state & I_DIRTY) &&
-       ((what & OSYNC_INODE) || (inode->i_state & I_DIRTY_DATASYNC)))
-      need_write_inode_now = 1;
+   if (!(inode->i_state & I_DIRTY))
+      goto out;
+   if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
+      goto out;
    spin_unlock(&inode_lock);
+   write_inode_now(inode, 1);
+   return err;
 
-   if (need_write_inode_now)
-      write_inode_now(inode, 1);
-   else
-      wait_on_inode(inode);
-
+ out:
+   spin_unlock(&inode_lock);
    return err;
 }
 
@@ -505,7 +507,8 @@
  
 void clear_inode(struct inode *inode)
 {
-   invalidate_inode_buffers(inode);
+   if (!list_empty(&inode->i_dirty_buffers))
+      invalidate_inode_buffers(inode);
        
    if (inode->i_data.nrpages)
       BUG();
@@ -514,7 +517,8 @@
    if (inode->i_state & I_CLEAR)
       BUG();
    wait_on_inode(inode);
-   DQUOT_DROP(inode);
+   if (IS_QUOTAINIT(inode))
+      DQUOT_DROP(inode);
    if (inode->i_sb && inode->i_sb->s_op && inode->i_sb->s_op->clear_inode)
       inode->i_sb->s_op->clear_inode(inode);
    if (inode->i_bdev)
@@ -629,12 +633,6 @@
    res = 0;
    sb = get_super(dev);
    if (sb) {
-      /*
-       * no need to lock the super, get_super holds the
-       * read semaphore so the filesystem cannot go away
-       * under us (->put_super runs with the write lock
-       * hold).
-       */
       shrink_dcache_sb(sb);
       res = invalidate_inodes(sb);
       drop_super(sb);
@@ -664,11 +662,12 @@
 {
    LIST_HEAD(list);
    struct list_head *entry, *freeable = &list;
-   int count;
+   int count, synced = 0;
    struct inode * inode;
 
    spin_lock(&inode_lock);
 
+free_unused:
    count = 0;
    entry = inode_unused.prev;
    while (entry != &inode_unused)
@@ -698,16 +697,21 @@
    dispose_list(freeable);
 
    /* 
-    * If we didn't freed enough clean inodes schedule
-    * a sync of the dirty inodes, we cannot do it
-    * from here or we're either synchronously dogslow
-    * or we deadlock with oom.
+    * If we freed enough clean inodes, avoid writing 
+    * dirty ones. Also giveup if we already tried to
+    * sync dirty inodes.
     */
-   if (goal)
-      schedule_task(&unused_inodes_flush_task);
+   if (!goal || synced)
+      return;
+   
+   synced = 1;
+
+   spin_lock(&inode_lock);
+   try_to_sync_unused_inodes();
+   goto free_unused;
 }
 
-int shrink_icache_memory(int priority, int gfp_mask)
+void shrink_icache_memory(int priority, int gfp_mask)
 {
    int count = 0;
 
@@ -719,13 +723,13 @@
     * in clear_inode() and friends..
     */
    if (!(gfp_mask & __GFP_FS))
-      return 0;
+      return;
 
-   count = inodes_stat.nr_unused / priority;
+   if (priority)
+      count = inodes_stat.nr_unused / priority;
 
    prune_icache(count);
    kmem_cache_shrink(inode_cachep);
-   return 0;
 }
 
 /*
@@ -777,6 +781,7 @@
    atomic_set(&inode->i_writecount, 0);
    inode->i_size = 0;
    inode->i_blocks = 0;
+   inode->i_bytes = 0;
    inode->i_generation = 0;
    memset(&inode->i_dquot, 0, sizeof(inode->i_dquot));
    inode->i_pipe = NULL;
@@ -1031,9 +1036,6 @@
    if (inode) {
       struct super_operations *op = NULL;
 
-      if (inode->i_state == I_CLEAR)
-         BUG();
-
       if (inode->i_sb && inode->i_sb->s_op)
          op = inode->i_sb->s_op;
       if (op && op->put_inode)
@@ -1051,13 +1053,12 @@
          inodes_stat.nr_inodes--;
          spin_unlock(&inode_lock);
 
+         DQUOT_INIT(inode);
          if (inode->i_data.nrpages)
             truncate_inode_pages(&inode->i_data, 0);
 
          if (op && op->delete_inode) {
             void (*delete)(struct inode *) = op->delete_inode;
-            if (!is_bad_inode(inode))
-               DQUOT_INIT(inode);
             /* s_op->delete_inode internally recalls clear_inode() */
             delete(inode);
          } else
@@ -1170,8 +1171,6 @@
                 NULL);
    if (!inode_cachep)
       panic("cannot create inode slab cache");
-
-   unused_inodes_flush_task.routine = try_to_sync_unused_inodes;
 }
 
 /**


Comments: webmaster (at) linuxhq.com.
Advertising: banners (at) linuxhq.com.
Compilation ©1998-2008 Linux Headquarters, Inc.