patch-2.4.10 linux/fs/inode.c
Next file: linux/fs/isofs/rock.c
Previous file: linux/fs/hpfs/inode.c
Back to the patch index
Back to the overall index
- Lines: 325
- Date:
Sat Sep 22 20:35:43 2001
- Orig file:
v2.4.9/linux/fs/inode.c
- Orig date:
Sun Aug 12 13:28:00 2001
diff -u --recursive --new-file v2.4.9/linux/fs/inode.c linux/fs/inode.c
@@ -15,6 +15,8 @@
#include <linux/cache.h>
#include <linux/swap.h>
#include <linux/swapctl.h>
+#include <linux/prefetch.h>
+#include <linux/locks.h>
/*
* New inode.c implementation.
@@ -77,7 +79,7 @@
((struct inode *) kmem_cache_alloc(inode_cachep, SLAB_KERNEL))
static void destroy_inode(struct inode *inode)
{
- if (!list_empty(&inode->i_dirty_buffers))
+ if (inode_has_buffers(inode))
BUG();
kmem_cache_free(inode_cachep, (inode));
}
@@ -103,6 +105,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);
sema_init(&inode->i_sem, 1);
sema_init(&inode->i_zombie, 1);
spin_lock_init(&inode->i_data.i_shared_lock);
@@ -125,14 +129,18 @@
/**
* __mark_inode_dirty - internal function
* @inode: inode to mark
- *
- * Mark an inode as dirty. Callers should use mark_inode_dirty.
+ * @flags: what kind of dirty (i.e. I_DIRTY_SYNC)
+ * Mark an inode as dirty. Callers should use mark_inode_dirty or
+ * mark_inode_dirty_sync.
*/
void __mark_inode_dirty(struct inode *inode, int flags)
{
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)
@@ -271,27 +279,18 @@
}
}
-static inline int try_to_sync_unused_list(struct list_head *head)
+static inline int try_to_sync_unused_list(struct list_head *head, int nr_inodes)
{
struct list_head *tmp = head;
struct inode *inode;
- while ((tmp = tmp->prev) != head) {
+ while (nr_inodes && (tmp = tmp->prev) != head) {
inode = list_entry(tmp, struct inode, i_list);
if (!atomic_read(&inode->i_count)) {
- /*
- * 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
- */
+ __sync_one(inode, 0);
+ nr_inodes--;
- 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.
@@ -299,7 +298,8 @@
tmp = head;
}
}
- return 1;
+
+ return nr_inodes;
}
void sync_inodes_sb(struct super_block *sb)
@@ -395,26 +395,25 @@
}
}
-/*
- * Called with the spinlock already held..
- */
-static void try_to_sync_unused_inodes(void)
+static void try_to_sync_unused_inodes(void * arg)
{
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 (; sb != sb_entry(&super_blocks); sb = sb_entry(sb->s_list.next)) {
- if (!sb->s_dev)
- continue;
+ for (; nr_inodes && sb != sb_entry(&super_blocks); sb = sb_entry(sb->s_list.next)) {
spin_unlock(&sb_lock);
- if (!try_to_sync_unused_list(&sb->s_dirty))
- return;
+ nr_inodes = try_to_sync_unused_list(&sb->s_dirty, nr_inodes);
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
@@ -433,9 +432,11 @@
while (inode->i_state & I_DIRTY)
sync_one(inode, sync);
spin_unlock(&inode_lock);
+ if (sync)
+ wait_on_inode(inode);
}
else
- printk("write_inode_now: no super block\n");
+ printk(KERN_ERR "write_inode_now: no super block\n");
}
/**
@@ -447,9 +448,9 @@
* O_SYNC flag set, to flush dirty writes to disk.
*/
-int generic_osync_inode(struct inode *inode, int datasync)
+int generic_osync_inode(struct inode *inode, int what)
{
- int err;
+ int err = 0, err2 = 0, need_write_inode_now = 0;
/*
* WARNING
@@ -472,23 +473,24 @@
* every O_SYNC write, not just the synchronous I/Os. --sct
*/
-#ifdef WRITERS_QUEUE_IO
- err = osync_inode_buffers(inode);
-#else
- err = fsync_inode_buffers(inode);
-#endif
+ if (what & OSYNC_METADATA)
+ err = fsync_inode_buffers(inode);
+ if (what & OSYNC_DATA)
+ err2 = fsync_inode_data_buffers(inode);
+ if (!err)
+ err = err2;
spin_lock(&inode_lock);
- if (!(inode->i_state & I_DIRTY))
- goto out;
- if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
- goto out;
+ if ((inode->i_state & I_DIRTY) &&
+ ((what & OSYNC_INODE) || (inode->i_state & I_DIRTY_DATASYNC)))
+ need_write_inode_now = 1;
spin_unlock(&inode_lock);
- write_inode_now(inode, 1);
- return err;
- out:
- spin_unlock(&inode_lock);
+ if (need_write_inode_now)
+ write_inode_now(inode, 1);
+ else
+ wait_on_inode(inode);
+
return err;
}
@@ -503,8 +505,7 @@
void clear_inode(struct inode *inode)
{
- if (!list_empty(&inode->i_dirty_buffers))
- invalidate_inode_buffers(inode);
+ invalidate_inode_buffers(inode);
if (inode->i_data.nrpages)
BUG();
@@ -513,15 +514,12 @@
if (inode->i_state & I_CLEAR)
BUG();
wait_on_inode(inode);
- if (IS_QUOTAINIT(inode))
- DQUOT_DROP(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) {
- bdput(inode->i_bdev);
- inode->i_bdev = NULL;
- }
- if (inode->i_cdev) {
+ if (inode->i_bdev)
+ bd_forget(inode);
+ else if (inode->i_cdev) {
cdput(inode->i_cdev);
inode->i_cdev = NULL;
}
@@ -631,6 +629,13 @@
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);
}
@@ -659,12 +664,11 @@
{
LIST_HEAD(list);
struct list_head *entry, *freeable = &list;
- int count, synced = 0;
+ int count;
struct inode * inode;
spin_lock(&inode_lock);
-free_unused:
count = 0;
entry = inode_unused.prev;
while (entry != &inode_unused)
@@ -694,18 +698,13 @@
dispose_list(freeable);
/*
- * If we freed enough clean inodes, avoid writing
- * dirty ones. Also giveup if we already tried to
- * sync dirty inodes.
+ * 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 (!goal || synced)
- return;
-
- synced = 1;
-
- spin_lock(&inode_lock);
- try_to_sync_unused_inodes();
- goto free_unused;
+ if (goal)
+ schedule_task(&unused_inodes_flush_task);
}
int shrink_icache_memory(int priority, int gfp_mask)
@@ -722,7 +721,7 @@
if (!(gfp_mask & __GFP_FS))
return 0;
- count = inodes_stat.nr_unused >> priority;
+ count = inodes_stat.nr_unused / priority;
prune_icache(count);
kmem_cache_shrink(inode_cachep);
@@ -777,6 +776,7 @@
inode->i_nlink = 1;
atomic_set(&inode->i_writecount, 0);
inode->i_size = 0;
+ inode->i_blocks = 0;
inode->i_generation = 0;
memset(&inode->i_dquot, 0, sizeof(inode->i_dquot));
inode->i_pipe = NULL;
@@ -806,6 +806,8 @@
static unsigned long last_ino;
struct inode * inode;
+ spin_lock_prefetch(&inode_lock);
+
inode = alloc_inode();
if (inode)
{
@@ -1027,6 +1029,9 @@
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)
@@ -1049,6 +1054,8 @@
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
@@ -1161,6 +1168,8 @@
NULL);
if (!inode_cachep)
panic("cannot create inode slab cache");
+
+ unused_inodes_flush_task.routine = try_to_sync_unused_inodes;
}
/**
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)