* update the access time.
*/
if (inode && count != 0) {
- inode->i_atime = CURRENT_TIME;
- inode->i_dirt = 1;
+ UPDATE_ATIME(inode);
}
return (count ? count : retval);
}
if ((ret > 0) && inode) {
inode->i_mtime = CURRENT_TIME;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
}
return ret;
}
if (!fsuser() && !in_group_p(inode->i_gid))
inode->i_mode &= ~S_ISGID;
}
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
}
}
static void autofs_write_inode(struct inode *inode)
{
- inode->i_dirt = 0;
}
return -EACCES;
}
- if ( !oz_mode && S_ISDIR(res->i_mode) && res->i_sb == dir->i_sb ) {
+ if ( !oz_mode && S_ISDIR(res->i_mode) && res->i_dentry->d_covers == res->i_dentry ) {
/* Not a mount point yet, call 1-800-DAEMON */
DPRINTK(("autofs: waiting on non-mountpoint dir, inode = %lu, pid = %u, pgrp = %u\n", res->i_ino, current->pid, current->pgrp));
+ iput(res);
res = NULL;
up(&dir->i_sem);
status = autofs_wait(sbi,str);
/* Finally dump the task struct. Not be used by gdb, but could be useful */
set_fs(KERNEL_DS);
DUMP_WRITE(current,sizeof(*current));
- inode->i_status |= ST_MODIFIED;
close_coredump:
if (file.f_op->release)
file.f_op->release(inode,&file);
*/
static int dump_write(struct file *file, const void *addr, int nr)
{
- file->f_inode->i_status |= ST_MODIFIED;
return file->f_op->write(file->f_inode, file, addr, nr) == nr;
}
if (filp->f_op->write(filp->f_inode, filp,
(char *)&dquot->dq_dqb, sizeof(struct dqblk)) == sizeof(struct dqblk))
dquot->dq_flags &= ~DQ_MOD;
- /* inode->i_status |= ST_MODIFIED is willingly *not* done here */
up(&dquot->dq_mnt->mnt_sem);
set_fs(fs);
offset = 0;
brelse (bh);
}
- if (DO_UPDATE_ATIME(inode)) {
- inode->i_atime = CURRENT_TIME;
- inode->i_dirt = 1;
- }
+ UPDATE_ATIME(inode);
return 0;
}
mode &= inode->i_mode;
if (mode && !suser()) {
inode->i_mode &= ~mode;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
}
}
inode->u.ext2_i.i_osync--;
inode->i_ctime = inode->i_mtime = CURRENT_TIME;
filp->f_pos = pos;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
return written;
}
es->s_free_inodes_count =
cpu_to_le32(le32_to_cpu(es->s_free_inodes_count) + 1);
mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
- inode->i_dirt = 0;
+ mark_inode_dirty(inode);
}
mark_buffer_dirty(bh, 1);
if (sb->s_flags & MS_SYNCHRONOUS) {
int mode)
{
inode->u.ext2_i.i_version++;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
return;
}
mode |= S_ISGID;
} else
inode->i_gid = current->fsgid;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
inode->i_ino = j;
inode->i_blksize = PAGE_SIZE; /* This is the optimal IO size (for stat), not the fs block size */
inode->i_blocks = 0;
inode->i_ino == EXT2_ACL_DATA_INO)
return;
inode->u.ext2_i.i_dtime = CURRENT_TIME;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
ext2_update_inode(inode, IS_SYNC(inode));
inode->i_size = 0;
if (inode->i_blocks)
if (IS_SYNC(inode) || inode->u.ext2_i.i_osync)
ext2_sync_inode (inode);
else
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
return result;
}
}
inode->i_ctime = CURRENT_TIME;
inode->i_blocks += blocks;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
inode->u.ext2_i.i_next_alloc_block = new_block;
inode->u.ext2_i.i_next_alloc_goal = tmp;
brelse (bh);
else for (block = 0; block < EXT2_N_BLOCKS; block++)
raw_inode->i_block[block] = cpu_to_le32(inode->u.ext2_i.i_data[block]);
mark_buffer_dirty(bh, 1);
- inode->i_dirt = 0;
if (do_sync) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
inode->i_flags &= ~S_IMMUTABLE;
inode->u.ext2_i.i_flags &= ~EXT2_IMMUTABLE_FL;
}
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
return 0;
}
else
inode->i_flags &= ~MS_NOATIME;
inode->i_ctime = CURRENT_TIME;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
return 0;
case EXT2_IOC_GETVERSION:
return put_user(inode->u.ext2_i.i_version, (int *) arg);
if (get_user(inode->u.ext2_i.i_version, (int *) arg))
return -EFAULT;
inode->i_ctime = CURRENT_TIME;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
return 0;
default:
return -ENOTTY;
de->inode = le32_to_cpu(0);
de->rec_len = le16_to_cpu(sb->s_blocksize);
dir->i_size = offset + sb->s_blocksize;
- dir->i_dirt = 1;
+ mark_inode_dirty(dir);
} else {
ext2_debug ("skipping to next block\n");
* and/or different from the directory change time.
*/
dir->i_mtime = dir->i_ctime = CURRENT_TIME;
- dir->i_dirt = 1;
+ mark_inode_dirty(dir);
dir->i_version = ++event;
mark_buffer_dirty(bh, 1);
*res_dir = de;
inode->i_op = &ext2_file_inode_operations;
inode->i_mode = mode;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
if (!bh) {
inode->i_nlink--;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
iput (inode);
return err;
}
init_fifo(inode);
if (S_ISBLK(mode) || S_ISCHR(mode))
inode->i_rdev = to_kdev_t(rdev);
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
if (!bh) {
inode->i_nlink--;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
iput(inode);
return err;
}
dir_block = ext2_bread (inode, 0, 1, &err);
if (!dir_block) {
inode->i_nlink--;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
iput (inode);
return err;
}
inode->i_mode = S_IFDIR | (mode & (S_IRWXUGO|S_ISVTX) & ~current->fs->umask);
if (dir->i_mode & S_ISGID)
inode->i_mode |= S_ISGID;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
if (!bh) {
inode->i_nlink = 0;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
iput (inode);
return err;
}
wait_on_buffer (bh);
}
dir->i_nlink++;
- dir->i_dirt = 1;
+ mark_inode_dirty(dir);
d_instantiate(dentry, inode, D_DIR);
brelse (bh);
return 0;
inode->i_nlink);
inode->i_version = ++event;
inode->i_nlink = 0;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
dir->i_nlink--;
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
- dir->i_dirt = 1;
+ mark_inode_dirty(dir);
d_delete(dentry);
end_rmdir:
wait_on_buffer (bh);
}
dir->i_ctime = dir->i_mtime = CURRENT_TIME;
- dir->i_dirt = 1;
+ mark_inode_dirty(dir);
inode->i_nlink--;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
inode->i_ctime = dir->i_ctime;
retval = 0;
d_delete(dentry); /* This also frees the inode */
name_block = ext2_bread (inode, 0, 1, &err);
if (!name_block) {
inode->i_nlink--;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
iput (inode);
return err;
}
brelse (name_block);
}
inode->i_size = i;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
if (!bh) {
inode->i_nlink--;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
iput (inode);
return err;
}
brelse (bh);
inode->i_nlink++;
inode->i_ctime = CURRENT_TIME;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
atomic_inc(&inode->i_count);
d_instantiate(dentry, inode, 0);
return 0;
if (new_inode) {
new_inode->i_nlink--;
new_inode->i_ctime = CURRENT_TIME;
- new_inode->i_dirt = 1;
+ mark_inode_dirty(new_inode);
}
old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
- old_dir->i_dirt = 1;
+ mark_inode_dirty(old_dir);
if (dir_bh) {
PARENT_INO(dir_bh->b_data) = le32_to_cpu(new_dir->i_ino);
mark_buffer_dirty(dir_bh, 1);
old_dir->i_nlink--;
- old_dir->i_dirt = 1;
+ mark_inode_dirty(old_dir);
if (new_inode) {
new_inode->i_nlink--;
- new_inode->i_dirt = 1;
+ mark_inode_dirty(new_inode);
} else {
new_dir->i_nlink++;
- new_dir->i_dirt = 1;
+ mark_inode_dirty(new_dir);
}
}
mark_buffer_dirty(old_bh, 1);
}
link = bh->b_data;
}
- if (!IS_RDONLY(inode)) {
- inode->i_atime = CURRENT_TIME;
- inode->i_dirt = 1;
- }
+ UPDATE_ATIME(inode);
base = lookup_dentry(link, base, 1);
if (bh)
brelse(bh);
i++;
if (copy_to_user(buffer, link, i))
i = -EFAULT;
- if (DO_UPDATE_ATIME(inode)) {
- inode->i_atime = CURRENT_TIME;
- inode->i_dirt = 1;
- }
+ UPDATE_ATIME(inode);
if (bh)
brelse (bh);
return i;
}
*p = 0;
inode->i_blocks -= blocks;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
bforget(bh);
if (free_count == 0) {
block_to_free = tmp;
}
/* ext2_free_blocks (inode, tmp, 1); */
inode->i_blocks -= blocks;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
}
if (free_count > 0)
ext2_free_blocks (inode, block_to_free, free_count);
tmp = *p;
*p = 0;
inode->i_blocks -= blocks;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
ext2_free_blocks (inode, tmp, 1);
}
if (IS_SYNC(inode) && buffer_dirty(ind_bh)) {
}
/* ext2_free_blocks (inode, tmp, 1); */
inode->i_blocks -= blocks;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
}
if (free_count > 0)
ext2_free_blocks (inode, block_to_free, free_count);
tmp = le32_to_cpu(*p);
*p = cpu_to_le32(0);
inode->i_blocks -= blocks;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
ext2_free_blocks (inode, tmp, 1);
}
if (IS_SYNC(inode) && buffer_dirty(ind_bh)) {
tmp = *p;
*p = 0;
inode->i_blocks -= blocks;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
ext2_free_blocks (inode, tmp, 1);
}
if (IS_SYNC(inode) && buffer_dirty(dind_bh)) {
tmp = le32_to_cpu(*p);
*p = cpu_to_le32(0);
inode->i_blocks -= blocks;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
ext2_free_blocks (inode, tmp, 1);
}
if (IS_SYNC(inode) && buffer_dirty(dind_bh)) {
tmp = *p;
*p = 0;
inode->i_blocks -= blocks;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
ext2_free_blocks (inode, tmp, 1);
}
if (IS_SYNC(inode) && buffer_dirty(tind_bh)) {
retry |= trunc_tindirect (inode);
if (!retry)
break;
- if (IS_SYNC(inode) && inode->i_dirt)
+ if (IS_SYNC(inode) && test_bit(I_DIRTY, &inode->i_state))
ext2_sync_inode (inode);
current->counter = 0;
schedule ();
}
}
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
}
/*
- * fs/inode.c
+ * linux/fs/inode.c
*
- * Complete reimplementation
- * (C) 1997 Thomas Schoebel-Theuer
+ * (C) 1997 Linus Torvalds
*/
-/* Everything here is intended to be MP-safe. However, other parts
- * of the kernel are not yet MP-safe, in particular the inode->i_count++
- * that are spread over everywhere. These should be replaced by
- * iinc() as soon as possible. Since I have no MP machine, I could
- * not test it.
- */
-#include <linux/config.h>
-#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/kernel.h>
-#include <linux/dlists.h>
#include <linux/dalloc.h>
-#include <linux/omirr.h>
-
-/* #define DEBUG */
-
-#define HASH_SIZE 1024 /* must be a power of 2 */
-#define NR_LEVELS 4
-
-#define ST_AGED 1
-#define ST_HASHED 2
-#define ST_EMPTY 4
-#define ST_TO_READ 8
-#define ST_TO_WRITE 16
-#define ST_TO_PUT 32
-#define ST_TO_DROP 64
-#define ST_IO (ST_TO_READ|ST_TO_WRITE|ST_TO_PUT|ST_TO_DROP)
-#define ST_WAITING 128
-#define ST_FREEING 256
-#define ST_IBASKET 512
-
-/* The idea is to keep empty inodes in a separate list, so no search
- * is required as long as empty inodes exit.
- * All reusable inodes occurring in the hash table with i_count==0
- * are also registered in the ringlist aged_i[level], but in LRU order.
- * Used inodes with i_count>0 are kept solely in the hashtable and in
- * all_i, but in no other list.
- * The level is used for multilevel aging to avoid thrashing; each
- * time i_count decreases to 0, the inode is inserted into the next level
- * ringlist. Cache reusage is simply by taking the _last_ element from the
- * lowest-level ringlist that contains inodes.
- * In contrast to the old code, there isn't any O(n) search overhead now
- * in iget/iput (if you make HASH_SIZE large enough).
+#include <linux/list.h>
+
+/*
+ * New inode.c implementation.
+ *
+ * This implementation has the basic premise of trying
+ * to be extremely low-overhead and SMP-safe, yet be
+ * simple enough to be "obviously correct".
+ *
+ * Famous last words.
+ */
+
+/*
+ * Inode lookup is no longer as critical as it used to be:
+ * most of the lookups are going to be through the dcache.
+ */
+#define HASH_BITS 8
+#define HASH_SIZE (1UL << HASH_BITS)
+#define HASH_MASK (HASH_SIZE-1)
+
+/*
+ * Each inode can be on two separate lists. One is
+ * the hash list of the inode, used for lookups. The
+ * other linked list is the "type" list:
+ * "in_use" - valid inode, hashed
+ * "dirty" - valid inode, hashed, dirty.
+ * "unused" - ready to be re-used. Not hashed.
+ *
+ * The two first versions also have a dirty list, allowing
+ * for low-overhead inode sync() operations.
+ */
+
+LIST_HEAD(inode_in_use);
+LIST_HEAD(inode_dirty);
+LIST_HEAD(inode_unused);
+struct list_head inode_hashtable[HASH_SIZE];
+
+/*
+ * A simple spinlock to protect the list manipulations
+ */
+spinlock_t inode_lock = SPIN_LOCK_UNLOCKED;
+
+/*
+ * Statistics gathering.. Not actually done yet.
*/
-static struct inode * hashtable[HASH_SIZE];/* linked with i_hash_{next,prev} */
-static struct inode * all_i = NULL; /* linked with i_{next,prev} */
-static struct inode * empty_i = NULL; /* linked with i_{next,prev} */
-static struct inode * aged_i[NR_LEVELS+1]; /* linked with i_lru_{next,prev} */
-static int aged_reused[NR_LEVELS+1]; /* # removals from aged_i[level] */
-static int age_table[NR_LEVELS+1] = { /* You may tune this. */
- 1, 4, 10, 100, 1000
-}; /* after which # of uses to increase to the next level */
-
-/* This is for kernel/sysctl.c */
-
-/* Just aligning plain ints and arrays thereof doesn't work reliably.. */
struct {
int nr_inodes;
int nr_free_inodes;
- int aged_count[NR_LEVELS+1]; /* # in each level */
+ int dummy[10];
} inodes_stat;
int max_inodes = NR_INODE;
-unsigned long last_inode = 0;
-void inode_init(void)
+void __mark_inode_dirty(struct inode *inode)
{
- memset(hashtable, 0, sizeof(hashtable));
- memset(aged_i, 0, sizeof(aged_i));
- memset(aged_reused, 0, sizeof(aged_reused));
- memset(&inodes_stat, 0, sizeof(inodes_stat));
+ spin_lock(&inode_lock);
+ list_del(&inode->i_list);
+ list_add(&inode->i_list, &inode_dirty);
+ spin_unlock(&inode_lock);
}
-/* Intended for short locks of the above global data structures.
- * Could be replaced with spinlocks completely, since there is
- * no blocking during manipulation of the static data; however the
- * lock in invalidate_inodes() may last relatively long.
- */
-#ifdef __SMP__
-struct semaphore vfs_sem = MUTEX;
-#endif
-
-DEF_INSERT(all,struct inode,i_next,i_prev)
-DEF_REMOVE(all,struct inode,i_next,i_prev)
-
-DEF_INSERT(lru,struct inode,i_lru_next,i_lru_prev)
-DEF_REMOVE(lru,struct inode,i_lru_next,i_lru_prev)
+static inline void unlock_inode(struct inode *inode)
+{
+ clear_bit(I_LOCK, &inode->i_state);
+ wake_up(&inode->i_wait);
+}
-DEF_INSERT(hash,struct inode,i_hash_next,i_hash_prev)
-DEF_REMOVE(hash,struct inode,i_hash_next,i_hash_prev)
+static void __wait_on_inode(struct inode * inode)
+{
+ struct wait_queue wait = { current, NULL };
-DEF_INSERT(ibasket,struct inode,i_basket_next,i_basket_prev)
-DEF_REMOVE(ibasket,struct inode,i_basket_next,i_basket_prev)
+ add_wait_queue(&inode->i_wait, &wait);
+repeat:
+ current->state = TASK_UNINTERRUPTIBLE;
+ if (test_bit(I_LOCK, &inode->i_state)) {
+ schedule();
+ goto repeat;
+ }
+ remove_wait_queue(&inode->i_wait, &wait);
+ current->state = TASK_RUNNING;
+}
-#ifdef DEBUG
-extern void printpath(struct dentry * entry);
-struct inode * xtst[15000];
-int xcnt = 0;
+static inline void wait_on_inode(struct inode *inode)
+{
+ if (test_bit(I_LOCK, &inode->i_state))
+ __wait_on_inode(inode);
+}
-void xcheck(char * txt, struct inode * p)
+/*
+ * These are initializations that only need to be done
+ * once, because the fields are idempotent across use
+ * of the inode..
+ */
+static inline void init_once(struct inode * inode)
{
- int i;
- for(i=xcnt-1; i>=0; i--)
- if (xtst[i] == p)
- return;
- printk("Bogus inode %p in %s\n", p, txt);
+ memset(inode, 0, sizeof(*inode));
+ init_waitqueue(&inode->i_wait);
+ sema_init(&inode->i_sem, 1);
}
-#else
-#define xcheck(t,p) /*nothing*/
-#endif
-static inline struct inode * grow_inodes(void)
+
+/*
+ * Look out! This returns with the inode lock held if
+ * it got an inode..
+ */
+static struct inode * grow_inodes(void)
{
- struct inode * res;
- struct inode * inode = res = (struct inode*)__get_free_page(GFP_KERNEL);
- int size = PAGE_SIZE;
- if (!inode)
- return NULL;
-
- size -= sizeof(struct inode);
- inode++;
- inodes_stat.nr_inodes++;
-#ifdef DEBUG
-xtst[xcnt++]=res;
-#endif
- while(size >= sizeof(struct inode)) {
-#ifdef DEBUG
-xtst[xcnt++]=inode;
-#endif
- inodes_stat.nr_inodes++;
- inodes_stat.nr_free_inodes++;
- insert_all(&empty_i, inode);
- inode->i_status = ST_EMPTY;
- inode++;
- size -= sizeof(struct inode);
+ struct inode * inode = (struct inode *)__get_free_page(GFP_KERNEL);
+
+ if (inode) {
+ int size;
+ struct inode * tmp;
+
+ spin_lock(&inode_lock);
+ size = PAGE_SIZE - 2*sizeof(struct inode);
+ tmp = inode;
+ do {
+ tmp++;
+ init_once(tmp);
+ list_add(&tmp->i_list, &inode_unused);
+ size -= sizeof(struct inode);
+ } while (size >= 0);
+ init_once(inode);
}
- return res;
+ return inode;
}
-static inline int hash(dev_t i_dev, unsigned long i_ino)
+static inline void write_inode(struct inode *inode)
{
- return ((int)i_ino ^ ((int)i_dev << 6)) & (HASH_SIZE-1);
+ if (inode->i_sb && inode->i_sb->s_op && inode->i_sb->s_op->write_inode)
+ inode->i_sb->s_op->write_inode(inode);
}
-static inline blocking void wait_io(struct inode * inode, unsigned short flags)
+static inline void sync_list(struct list_head *head, struct list_head *clean)
{
- while(inode->i_status & flags) {
- struct wait_queue wait = {current, NULL};
- inode->i_status |= ST_WAITING;
- vfs_unlock();
- add_wait_queue(&inode->i_wait, &wait);
- sleep_on(&inode->i_wait);
- remove_wait_queue(&inode->i_wait, &wait);
- vfs_lock();
- }
+ struct list_head * tmp;
+
+ while ((tmp = head->prev) != head) {
+ struct inode *inode = list_entry(tmp, struct inode, i_list);
+ list_del(tmp);
+
+ /*
+ * If the inode is locked, it's already being written out.
+ * We have to wait for it, though.
+ */
+ if (test_bit(I_LOCK, &inode->i_state)) {
+ list_add(tmp, head);
+ spin_unlock(&inode_lock);
+ __wait_on_inode(inode);
+ } else {
+ list_add(tmp, clean);
+ clear_bit(I_DIRTY, &inode->i_state);
+ set_bit(I_LOCK, &inode->i_state);
+ spin_unlock(&inode_lock);
+ write_inode(inode);
+ unlock_inode(inode);
+ }
+ spin_lock(&inode_lock);
+ }
}
-static inline blocking void set_io(struct inode * inode,
- unsigned short waitflags,
- unsigned short setflags)
+/*
+ * "sync_inodes()" goes through the dirty list
+ * and writes them out and puts them back on
+ * the normal list.
+ */
+void sync_inodes(kdev_t dev)
{
- wait_io(inode, waitflags);
- inode->i_status |= setflags;
- vfs_unlock();
+ spin_lock(&inode_lock);
+ sync_list(&inode_dirty, &inode_in_use);
+ spin_unlock(&inode_lock);
}
-static inline blocking int release_io(struct inode * inode, unsigned short flags)
+/*
+ * This is called by the filesystem to tell us
+ * that the inode is no longer useful. We just
+ * terminate it with extreme predjudice.
+ */
+void clear_inode(struct inode *inode)
{
- int res = 0;
- vfs_lock();
- inode->i_status &= ~flags;
- if (inode->i_status & ST_WAITING) {
- inode->i_status &= ~ST_WAITING;
- vfs_unlock();
- wake_up(&inode->i_wait);
- res = 1;
- }
- return res;
+ truncate_inode_pages(inode, 0);
+ wait_on_inode(inode);
+ if (IS_WRITABLE(inode) && inode->i_sb && inode->i_sb->dq_op)
+ inode->i_sb->dq_op->drop(inode);
+
+ spin_lock(&inode_lock);
+ inode->i_state = 0;
+ list_del(&inode->i_hash);
+ list_del(&inode->i_list);
+ list_add(&inode->i_list, &inode_unused);
+ spin_unlock(&inode_lock);
}
-static inline blocking void _io(void (*op)(struct inode*), struct inode * inode,
- unsigned short waitflags, unsigned short setflags)
+#define CAN_UNUSE(inode) \
+ ((atomic_read(&(inode)->i_count) == 0) && \
+ ((inode)->i_nrpages == 0) && \
+ (!test_bit(I_LOCK, &(inode)->i_state)))
+
+static void invalidate_list(struct list_head *head, kdev_t dev)
{
- /* Do nothing if the same op is already in progress. */
- if (op && !(inode->i_status & setflags)) {
- set_io(inode, waitflags, setflags);
- op(inode);
- if (release_io(inode, setflags)) {
- /* Somebody grabbed my inode from under me. */
-#ifdef DEBUG
- printk("_io grab!\n");
-#endif
- vfs_lock();
- }
+ struct list_head *next;
+
+ next = head->next;
+ for (;;) {
+ struct list_head * tmp = next;
+ struct inode * inode;
+
+ next = next->next;
+ if (tmp == head)
+ break;
+ inode = list_entry(tmp, struct inode, i_list);
+ if (inode->i_dev != dev)
+ continue;
+ if (!CAN_UNUSE(inode))
+ continue;
+ list_del(&inode->i_hash);
+ list_del(&inode->i_list);
+ list_add(&inode->i_list, &inode_unused);
}
}
-blocking void _clear_inode(struct inode * inode, int external, int verbose)
+void invalidate_inodes(kdev_t dev)
{
-xcheck("_clear_inode",inode);
- if (inode->i_status & ST_IBASKET) {
- struct super_block * sb = inode->i_sb;
- remove_ibasket(&sb->s_ibasket, inode);
- sb->s_ibasket_count--;
- inode->i_status &= ~ST_IBASKET;
-#if 0
-printpath(inode->i_dentry);
-printk(" put_inode\n");
-#endif
- _io(sb->s_op->put_inode, inode, ST_TO_PUT|ST_TO_WRITE, ST_TO_PUT);
- if (inode->i_status & ST_EMPTY)
- return;
- }
- if (inode->i_status & ST_HASHED)
- remove_hash(&hashtable[hash(inode->i_dev, inode->i_ino)], inode);
- if (inode->i_status & ST_AGED) {
- /* "cannot happen" when called from an fs because at least
- * the caller must use it. Can happen when called from
- * invalidate_inodes(). */
- if (verbose)
- printk("VFS: clearing aged inode\n");
- if (atomic_read(&inode->i_count))
- printk("VFS: aged inode is in use\n");
- remove_lru(&aged_i[inode->i_level], inode);
- inodes_stat.aged_count[inode->i_level]--;
- }
- if (!external && inode->i_status & ST_IO) {
- printk("VFS: clearing inode during IO operation\n");
- }
- if (!(inode->i_status & ST_EMPTY)) {
- remove_all(&all_i, inode);
- inode->i_status = ST_EMPTY;
- if (inode->i_pages) {
- vfs_unlock(); /* may block, can that be revised? */
- truncate_inode_pages(inode, 0);
- vfs_lock();
- }
- insert_all(&empty_i, inode);
- inodes_stat.nr_free_inodes++;
- } else if(external)
- printk("VFS: empty inode is unnecessarily cleared multiple "
- "times by an fs\n");
- else
- printk("VFS: clearing empty inode\n");
- inode->i_status = ST_EMPTY;
- /* The inode is not really cleared any more here, but only once
- * when taken from empty_i. This saves instructions and processor
- * cache pollution.
- */
+ spin_lock(&inode_lock);
+ invalidate_list(&inode_in_use, dev);
+ invalidate_list(&inode_dirty, dev);
+ spin_unlock(&inode_lock);
}
-void insert_inode_hash(struct inode * inode)
+/*
+ * This is called with the inode lock held. It just looks at the last
+ * inode on the in-use list, and if the inode is trivially freeable
+ * we just move it to the unused list.
+ *
+ * Otherwise we just move the inode to be the first inode and expect to
+ * get back to the problem later..
+ */
+static void try_to_free_inodes(void)
{
-xcheck("insert_inode_hash",inode);
- vfs_lock();
- if (!(inode->i_status & ST_HASHED)) {
- insert_hash(&hashtable[hash(inode->i_dev, inode->i_ino)], inode);
- inode->i_status |= ST_HASHED;
- } else
- printk("VFS: trying to hash an inode again\n");
- vfs_unlock();
+ struct list_head * tmp;
+ struct list_head *head = &inode_in_use;
+
+ tmp = head->prev;
+ if (tmp != head) {
+ struct inode * inode;
+
+ list_del(tmp);
+ inode = list_entry(tmp, struct inode, i_list);
+ if (CAN_UNUSE(inode)) {
+ list_del(&inode->i_hash);
+ head = &inode_unused;
+ }
+ list_add(tmp, head);
+ }
}
+
-blocking struct inode * _get_empty_inode(void)
+static struct inode * find_inode(struct super_block * sb, unsigned long ino, struct list_head *head)
{
+ struct list_head *tmp;
struct inode * inode;
- int retry = 0;
-retry:
- inode = empty_i;
- if (inode) {
- remove_all(&empty_i, inode);
- inodes_stat.nr_free_inodes--;
- } else if(inodes_stat.nr_inodes < max_inodes || retry > 2) {
- inode = grow_inodes();
- }
- if (!inode) {
- int level;
- int usable = 0;
- for(level = 0; level <= NR_LEVELS; level++)
- if (aged_i[level]) {
- inode = aged_i[level]->i_lru_prev;
- /* Here is the picking strategy, tune this */
- if (aged_reused[level] < (usable++ ?
- inodes_stat.aged_count[level] :
- 2))
- break;
- aged_reused[level] = 0;
- }
- if (inode) {
- if (!(inode->i_status & ST_AGED))
- printk("VFS: inode aging inconsistency\n");
- if (atomic_read(&inode->i_count))
- printk("VFS: i_count of aged inode is not zero\n");
- if (inode->i_dirt)
- printk("VFS: Hey, somebody made my aged inode dirty\n");
- _clear_inode(inode, 0, 0);
- goto retry;
- }
+ tmp = head;
+ for (;;) {
+ tmp = tmp->next;
+ inode = NULL;
+ if (tmp == head)
+ break;
+ inode = list_entry(tmp, struct inode, i_hash);
+ if (inode->i_sb != sb)
+ continue;
+ if (inode->i_ino != ino)
+ continue;
+ atomic_inc(&inode->i_count);
+ break;
}
- if (!inode) {
- vfs_unlock();
- schedule();
- if (retry > 10)
- panic("VFS: cannot repair inode shortage");
- if (retry > 2)
- printk("VFS: no free inodes\n");
- retry++;
- vfs_lock();
- goto retry;
- }
-xcheck("get_empty_inode",inode);
- memset(inode, 0, sizeof(struct inode));
- atomic_set(&inode->i_count, 1);
+ return inode;
+}
+
+/*
+ * This just initializes the inode fields
+ * to known values before returning the inode..
+ *
+ * i_sb, i_ino, i_count, i_state and the lists have
+ * been initialized elsewhere..
+ */
+void clean_inode(struct inode *inode)
+{
+ memset(&inode->u, 0, sizeof(inode->u));
+ inode->i_pipe = 0;
+ inode->i_sock = 0;
+ inode->i_op = NULL;
inode->i_nlink = 1;
+ memset(&inode->i_dquot, 0, sizeof(inode->i_dquot));
sema_init(&inode->i_sem, 1);
- inode->i_ino = ++last_inode;
- inode->i_version = ++event;
- insert_all(&all_i, inode);
- return inode;
}
-static inline blocking struct inode * _get_empty_inode_hashed(dev_t i_dev,
- unsigned long i_ino)
+/*
+ * This gets called with I_LOCK held: it needs
+ * to read the inode and then unlock it
+ */
+static inline void read_inode(struct inode *inode, struct super_block *sb)
{
- struct inode ** base = &hashtable[hash(i_dev, i_ino)];
- struct inode * inode = *base;
- if (inode) do {
- if (inode->i_ino == i_ino && inode->i_dev == i_dev) {
- atomic_inc(&inode->i_count);
- printk("VFS: inode %lx is already in use\n", i_ino);
- return inode;
- }
- inode = inode->i_hash_next;
- } while(inode != *base);
- inode = _get_empty_inode();
- inode->i_dev = i_dev;
- inode->i_ino = i_ino;
- insert_hash(base, inode);
- inode->i_status |= ST_HASHED;
- return inode;
+ sb->s_op->read_inode(inode);
+ unlock_inode(inode);
}
-blocking struct inode * get_empty_inode_hashed(dev_t i_dev, unsigned long i_ino)
+struct inode * get_empty_inode(void)
{
+ static unsigned long last_ino = 0;
struct inode * inode;
+ struct list_head * tmp = inode_unused.next;
+
+ if (tmp != &inode_unused) {
+ list_del(tmp);
+ inode = list_entry(tmp, struct inode, i_list);
+add_new_inode:
+ INIT_LIST_HEAD(&inode->i_list);
+ INIT_LIST_HEAD(&inode->i_hash);
+ inode->i_sb = NULL;
+ inode->i_ino = ++last_ino;
+ atomic_set(&inode->i_count, 1);
+ inode->i_state = 0;
+ clean_inode(inode);
+ return inode;
+ }
- vfs_lock();
- inode = _get_empty_inode_hashed(i_dev, i_ino);
- vfs_unlock();
+ /*
+ * Warning: if this succeeded, we will now
+ * return with the inode lock, and we need to
+ * unlock it.
+ */
+ inode = grow_inodes();
+ if (inode) {
+ spin_unlock(&inode_lock);
+ goto add_new_inode;
+ }
return inode;
}
-void _get_inode(struct inode * inode)
+struct inode * get_pipe_inode(void)
{
- if (inode->i_status & ST_IBASKET) {
- inode->i_status &= ~ST_IBASKET;
- remove_ibasket(&inode->i_sb->s_ibasket, inode);
- inode->i_sb->s_ibasket_count--;
- }
- if (inode->i_status & ST_AGED) {
- inode->i_status &= ~ST_AGED;
- remove_lru(&aged_i[inode->i_level], inode);
- inodes_stat.aged_count[inode->i_level]--;
- aged_reused[inode->i_level]++;
- if (S_ISDIR(inode->i_mode))
- /* make dirs less thrashable */
- inode->i_level = NR_LEVELS-1;
- else if(inode->i_nlink > 1)
- /* keep hardlinks totally separate */
- inode->i_level = NR_LEVELS;
- else if(++inode->i_reuse_count >= age_table[inode->i_level]
- && inode->i_level < NR_LEVELS-1)
- inode->i_level++;
- if (atomic_read(&inode->i_count) != 1)
- printk("VFS: inode count was not zero (%d after ++)\n", atomic_read(&inode->i_count));
- } else if(inode->i_status & ST_EMPTY)
- printk("VFS: invalid reuse of empty inode\n");
-}
+ extern struct inode_operations pipe_inode_operations;
+ struct inode *inode = get_empty_inode();
-blocking struct inode * iget(struct super_block * sb, unsigned long i_ino)
-{
- struct inode ** base;
- struct inode * inode;
- dev_t i_dev;
-
- if (!sb)
- panic("VFS: iget with sb == NULL");
- i_dev = sb->s_dev;
- if (!i_dev)
- panic("VFS: sb->s_dev is NULL\n");
- base = &hashtable[hash(i_dev, i_ino)];
- vfs_lock();
- inode = *base;
- if (inode) do {
- if (inode->i_ino == i_ino && inode->i_dev == i_dev) {
- atomic_inc(&inode->i_count);
- _get_inode(inode);
-
- /* Allow concurrent writes/puts. This is in particular
- * useful e.g. when syncing large chunks.
- * I hope the i_dirty flag is everywhere set as soon
- * as _any_ modifcation is made and _before_
- * giving up control, so no harm should occur if data
- * is modified during writes, because it will be
- * rewritten again (does a short inconsistency on the
- * disk harm?)
- */
- wait_io(inode, ST_TO_READ);
- vfs_unlock();
- goto done;
+ if (inode) {
+ unsigned long page = __get_free_page(GFP_USER);
+
+ if (!page) {
+ iput(inode);
+ inode = NULL;
+ } else {
+ PIPE_BASE(*inode) = (char *) page;
+ inode->i_op = &pipe_inode_operations;
+ atomic_set(&inode->i_count, 1);
+ PIPE_WAIT(*inode) = NULL;
+ PIPE_START(*inode) = PIPE_LEN(*inode) = 0;
+ PIPE_RD_OPENERS(*inode) = PIPE_WR_OPENERS(*inode) = 0;
+ PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 1;
+ PIPE_LOCK(*inode) = 0;
+ inode->i_pipe = 1;
+ inode->i_mode |= S_IFIFO | S_IRUSR | S_IWUSR;
+ inode->i_uid = current->fsuid;
+ inode->i_gid = current->fsgid;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_blksize = PAGE_SIZE;
}
- inode = inode->i_hash_next;
- } while(inode != *base);
- inode = _get_empty_inode_hashed(i_dev, i_ino);
- inode->i_sb = sb;
- inode->i_flags = sb->s_flags;
- if (sb->s_op && sb->s_op->read_inode) {
- set_io(inode, 0, ST_TO_READ); /* do not wait at all */
- sb->s_op->read_inode(inode);
- if (release_io(inode, ST_TO_READ))
- goto done;
}
- vfs_unlock();
-done:
return inode;
}
-blocking void __iput(struct inode * inode)
+/*
+ * This is called with the inode lock held.. Be careful.
+ */
+static struct inode * get_new_inode(struct super_block *sb, unsigned long ino, struct list_head *head)
{
- struct super_block * sb;
-xcheck("_iput",inode);
-
- if (atomic_read(&inode->i_count) < 0)
- printk("VFS: i_count is negative\n");
-
- if (atomic_read(&inode->i_count) || (inode->i_status & ST_FREEING))
- return;
-
- inode->i_status |= ST_FREEING;
- if (inode->i_pipe) {
- free_page((unsigned long)PIPE_BASE(*inode));
- PIPE_BASE(*inode)= NULL;
- }
- if ((sb = inode->i_sb)) {
- if (sb->s_op) {
- if (inode->i_nlink <= 0 &&
- !(inode->i_status & (ST_EMPTY|ST_IBASKET))) {
- _clear_inode(inode, 0, 1);
- goto done;
- }
- if (inode->i_dirt) {
- inode->i_dirt = 0;
- _io(sb->s_op->write_inode, inode,
- ST_TO_PUT|ST_TO_WRITE, ST_TO_WRITE);
- if (atomic_read(&inode->i_count))
- goto done;
- }
- }
- if (IS_WRITABLE(inode) && sb->dq_op) {
- /* can operate in parallel to other ops ? */
- _io(sb->dq_op->drop, inode, 0, ST_TO_DROP);
- if (atomic_read(&inode->i_count))
- goto done;
- }
- }
- if (inode->i_mmap)
- printk("VFS: inode has mappings\n");
- if (inode->i_status & ST_AGED) {
- printk("VFS: reaging inode\n");
-#if defined(DEBUG)
-printpath(inode->i_dentry);
-printk("\n");
-#endif
- goto done;
- }
- if (!(inode->i_status & (ST_HASHED|ST_EMPTY))) {
- _clear_inode(inode, 0, 1);
- goto done;
+ struct inode * inode;
+ struct list_head * tmp = inode_unused.next;
+
+ if (tmp != &inode_unused) {
+ list_del(tmp);
+ inode = list_entry(tmp, struct inode, i_list);
+add_new_inode:
+ list_add(&inode->i_list, &inode_in_use);
+ list_add(&inode->i_hash, head);
+ inode->i_sb = sb;
+ inode->i_dev = sb->s_dev;
+ inode->i_ino = ino;
+ inode->i_flags = sb->s_flags;
+ atomic_set(&inode->i_count, 1);
+ inode->i_state = 1 << I_LOCK;
+ spin_unlock(&inode_lock);
+ clean_inode(inode);
+ read_inode(inode, sb);
+ return inode;
}
- if (inode->i_status & ST_EMPTY) {
- printk("VFS: aging an empty inode\n");
- goto done;
+
+ /*
+ * Uhhuh.. We need to expand. Unlock for the allocation,
+ * but note that "grow_inodes()" will return with the
+ * lock held again if the allocation succeeded.
+ */
+ spin_unlock(&inode_lock);
+ inode = grow_inodes();
+ if (inode) {
+ /* We released the lock, so.. */
+ struct inode * old = find_inode(sb, ino, head);
+ if (!old)
+ goto add_new_inode;
+ list_add(&inode->i_list, &inode_unused);
+ spin_unlock(&inode_lock);
+ wait_on_inode(old);
+ return old;
}
- insert_lru(&aged_i[inode->i_level], inode);
- inodes_stat.aged_count[inode->i_level]++;
- inode->i_status |= ST_AGED;
-done:
- inode->i_status &= ~ST_FREEING;
+ return inode;
}
-blocking void _iput(struct inode * inode)
+static inline unsigned long hash(struct super_block *sb, unsigned long i_ino)
{
- vfs_lock();
- __iput(inode);
- vfs_unlock();
+ unsigned long tmp = i_ino | (unsigned long) sb;
+ tmp = tmp + (tmp >> HASH_BITS) + (tmp >> HASH_BITS*2);
+ return tmp & HASH_MASK;
}
-blocking void sync_inodes(kdev_t dev)
+struct inode *iget(struct super_block *sb, unsigned long ino)
{
+ struct list_head * head = inode_hashtable + hash(sb,ino);
struct inode * inode;
- vfs_lock();
- inode = all_i;
- if (inode) do {
-xcheck("sync_inodes",inode);
- if (inode->i_dirt && (inode->i_dev == dev || !dev)) {
- if (inode->i_sb && inode->i_sb->s_op &&
- !(inode->i_status & ST_FREEING)) {
- inode->i_dirt = 0;
- _io(inode->i_sb->s_op->write_inode, inode,
- ST_IO, ST_TO_WRITE);
- }
- }
- inode = inode->i_next;
- } while(inode != all_i);
- vfs_unlock();
+
+ spin_lock(&inode_lock);
+ inode = find_inode(sb, ino, head);
+ if (!inode) {
+ try_to_free_inodes();
+ return get_new_inode(sb, ino, head);
+ }
+ spin_unlock(&inode_lock);
+ wait_on_inode(inode);
+ return inode;
}
-blocking int _check_inodes(kdev_t dev, int complain)
+void insert_inode_hash(struct inode *inode)
{
- struct inode * inode;
- int bad = 0;
-
- vfs_lock();
-startover:
- inode = all_i;
- if (inode) do {
- struct inode * next;
-xcheck("_check_inodes",inode);
- next = inode->i_next;
- if (inode->i_dev == dev) {
- if (inode->i_dirt || atomic_read(&inode->i_count)) {
- bad++;
- } else {
- _clear_inode(inode, 0, 0);
-
- /* _clear_inode() may recursively clear other
- * inodes, probably also the next one.
- */
- if (next->i_status & ST_EMPTY)
- goto startover;
- }
- }
- inode = next;
- } while(inode != all_i);
- vfs_unlock();
- if (complain && bad)
- printk("VFS: %d inode(s) busy on removed device `%s'\n",
- bad, kdevname(dev));
- return (bad == 0);
+ struct list_head *head = inode_hashtable + hash(inode->i_sb, inode->i_ino);
+ list_add(&inode->i_hash, head);
}
-/*inline*/ void invalidate_inodes(kdev_t dev)
+void iput(struct inode *inode)
{
- /* Requires two passes, because of the new dcache holding
- * directories with i_count > 1.
- */
- (void)_check_inodes(dev, 0);
- (void)_check_inodes(dev, 1);
+ if (inode) {
+ if (inode->i_pipe)
+ wake_up_interruptible(&PIPE_WAIT(*inode));
+
+ /*
+ * Last user dropping the inode?
+ */
+ if (atomic_read(&inode->i_count) == 1) {
+ void (*put)(struct inode *);
+ if (inode->i_sb && inode->i_sb->s_op) {
+ put = inode->i_sb->s_op->put_inode;
+ if (put)
+ put(inode);
+ }
+ }
+ atomic_dec(&inode->i_count);
+ }
}
-/*inline*/ int fs_may_mount(kdev_t dev)
+int bmap(struct inode * inode, int block)
{
- return _check_inodes(dev, 0);
+ if (inode->i_op && inode->i_op->bmap)
+ return inode->i_op->bmap(inode, block);
+ return 0;
}
-int fs_may_remount_ro(kdev_t dev)
+/*
+ * Initialize the hash tables
+ */
+void inode_init(void)
{
- (void)dev;
- return 1; /* not checked any more */
+ int i;
+ struct list_head *head = inode_hashtable;
+
+ i = HASH_SIZE;
+ do {
+ INIT_LIST_HEAD(head);
+ head++;
+ i--;
+ } while (i);
}
-int fs_may_umount(kdev_t dev, struct dentry * root)
+/*
+ * FIXME! These need to go through the in-use inodes to
+ * check whether we can mount/umount/remount.
+ */
+int fs_may_mount(kdev_t dev)
{
- struct inode * inode;
- vfs_lock();
- inode = all_i;
- if (inode) do {
- if (inode->i_dev == dev && atomic_read(&inode->i_count))
- if (inode != root->d_inode) {
- vfs_unlock();
- return 0;
- }
- inode = inode->i_next;
- } while(inode != all_i);
- vfs_unlock();
return 1;
}
-extern struct inode_operations pipe_inode_operations;
-
-blocking struct inode * get_pipe_inode(void)
+int fs_may_umount(kdev_t dev, struct dentry * root)
{
- struct inode * inode = get_empty_inode();
-
- PIPE_BASE(*inode) = (char*)__get_free_page(GFP_USER);
- if (!(PIPE_BASE(*inode))) {
- iput(inode);
- return NULL;
- }
- inode->i_blksize = PAGE_SIZE;
- inode->i_pipe = 1;
- inode->i_mode = S_IFIFO | S_IRUSR | S_IWUSR;
- atomic_inc(&inode->i_count);
- inode->i_uid = current->fsuid;
- inode->i_gid = current->fsgid;
- inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- inode->i_op = &pipe_inode_operations;
- PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 1;
-
- return inode;
+ return 0;
}
-int bmap(struct inode * inode, int block)
+int fs_may_remount_ro(kdev_t dev)
{
- if (inode->i_op && inode->i_op->bmap)
- return inode->i_op->bmap(inode, block);
return 0;
}
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
isofs_bmap, /* bmap */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
generic_readpage, /* readpage */
NULL, /* writepage */
isofs_bmap, /* bmap */
s->u.isofs_sb.s_mode = opt.mode & 0777;
s->s_blocksize = opt.blocksize;
s->s_blocksize_bits = blocksize_bits;
- s->s_mounted = iget(s, (isonum_733(rootp->extent) +
+ s->s_root = d_alloc_root(iget(s, (isonum_733(rootp->extent) +
isonum_711(rootp->ext_attr_length))
- << s -> u.isofs_sb.s_log_zone_size);
+ << s -> u.isofs_sb.s_log_zone_size), NULL);
unlock_super(s);
- if (!(s->s_mounted)) {
+ if (!(s->s_root)) {
s->s_dev = 0;
printk("get root inode failed\n");
MOD_DEC_USE_COUNT;
return NULL;
}
-int isofs_lookup(struct inode * dir,const char * name, int len,
- struct inode ** result)
+int isofs_lookup(struct inode * dir, struct qstr *name,
+ struct inode ** result)
{
unsigned long ino, ino_back;
struct buffer_head * bh;
char *lcname;
+ struct inode *inode;
#ifdef DEBUG
- printk("lookup: %x %d\n",dir->i_ino, len);
+ printk("lookup: %x %d\n",dir->i_ino, name->len);
#endif
- *result = NULL;
if (!dir)
return -ENOENT;
- if (!S_ISDIR(dir->i_mode)) {
- iput(dir);
+ if (!S_ISDIR(dir->i_mode))
return -ENOENT;
- }
/* If mounted with check=relaxed (and most likely norock),
* then first convert this name to lower case.
*/
if (dir->i_sb->u.isofs_sb.s_name_check == 'r' &&
- (lcname = kmalloc(len, GFP_KERNEL)) != NULL) {
+ (lcname = kmalloc(name->len, GFP_KERNEL)) != NULL) {
int i;
char c;
- for (i=0; i<len; i++) {
- c = name[i];
+ for (i=0; i<name->len; i++) {
+ c = name->name[i];
if (c >= 'A' && c <= 'Z') c |= 0x20;
lcname[i] = c;
}
- bh = isofs_find_entry(dir,lcname,len, &ino, &ino_back);
+ bh = isofs_find_entry(dir, lcname, name->len,
+ &ino, &ino_back);
kfree(lcname);
} else
- bh = isofs_find_entry(dir,name,len, &ino, &ino_back);
+ bh = isofs_find_entry(dir, name->name,
+ name->len, &ino, &ino_back);
- if (!bh) {
- iput(dir);
+ if (!bh)
return -ENOENT;
- }
brelse(bh);
- if (!(*result = iget(dir->i_sb,ino))) {
- iput(dir);
+ inode = iget(dir->i_sb,ino);
+ if (!inode)
return -EACCES;
- }
/* We need this backlink for the ".." entry unless the name that we
* are looking up traversed a mount point (in which case the inode
* may not even be on an iso9660 filesystem, and writing to
* u.isofs_i would only cause memory corruption).
*/
- if (ino_back && !(*result)->i_pipe && (*result)->i_sb == dir->i_sb)
- (*result)->u.isofs_i.i_backlink = ino_back;
+ if (ino_back && !inode->i_pipe && inode->i_sb == dir->i_sb)
+ inode->u.isofs_i.i_backlink = ino_back;
+
+ *result = inode;
- iput(dir);
return 0;
}
minix_mknod, /* mknod */
minix_rename, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
generic_readpage, /* readpage */
NULL, /* writepage */
minix_bmap, /* bmap */
#include <linux/string.h>
#include <linux/stat.h>
#include <linux/locks.h>
+#include <linux/dalloc.h>
#include <linux/init.h>
#include <asm/system.h>
* it really _is_ a minix filesystem, and to check the size
* of the directory entry.
*/
-static const char * minix_checkroot(struct super_block *s)
+static const char * minix_checkroot(struct super_block *s, struct inode *dir)
{
- struct inode * dir;
struct buffer_head *bh;
struct minix_dir_entry *de;
const char * errmsg;
int dirsize;
- dir = s->s_mounted;
if (!S_ISDIR(dir->i_mode))
return "root directory is not a directory";
int i, block;
kdev_t dev = s->s_dev;
const char * errmsg;
-
+ struct inode *root_inode;
+
if (32 != sizeof (struct minix_inode))
panic("bad V1 i-node size");
if (64 != sizeof(struct minix2_inode))
/* set up enough so that it can read an inode */
s->s_dev = dev;
s->s_op = &minix_sops;
- s->s_mounted = iget(s,MINIX_ROOT_INO);
- if (!s->s_mounted) {
+ root_inode = iget(s,MINIX_ROOT_INO);
+ s->s_root = d_alloc_root(root_inode, NULL);
+ if (!s->s_root) {
s->s_dev = 0;
brelse(bh);
if (!silent)
return NULL;
}
- errmsg = minix_checkroot(s);
+ errmsg = minix_checkroot(s, root_inode);
if (errmsg) {
if (!silent)
printk("MINIX-fs: %s\n", errmsg);
- iput (s->s_mounted);
+ d_delete(s->s_root); /* XXX Is this enough? */
s->s_dev = 0;
brelse (bh);
MOD_DEC_USE_COUNT;
return NULL;
}
-int minix_lookup(struct inode * dir,const char * name, int len,
+int minix_lookup(struct inode * dir, struct qstr *name,
struct inode ** result)
{
int ino;
*result = NULL;
if (!dir)
return -ENOENT;
- if (!S_ISDIR(dir->i_mode)) {
- iput(dir);
+ if (!S_ISDIR(dir->i_mode))
return -ENOENT;
- }
- if (!(bh = minix_find_entry(dir,name,len,&de))) {
- iput(dir);
+ if (!(bh = minix_find_entry(dir, name->name, name->len, &de)))
return -ENOENT;
- }
ino = de->inode;
brelse(bh);
- if (!(*result = iget(dir->i_sb,ino))) {
- iput(dir);
+ if (!(*result = iget(dir->i_sb,ino)))
return -EACCES;
- }
- iput(dir);
return 0;
}
return 0;
}
-int minix_create(struct inode * dir,const char * name, int len, int mode,
- struct inode ** result)
+int minix_create(struct inode * dir, struct dentry *dentry, int mode)
{
int error;
struct inode * inode;
struct buffer_head * bh;
struct minix_dir_entry * de;
- *result = NULL;
if (!dir)
return -ENOENT;
inode = minix_new_inode(dir);
- if (!inode) {
- iput(dir);
+ if (!inode)
return -ENOSPC;
- }
inode->i_op = &minix_file_inode_operations;
inode->i_mode = mode;
inode->i_dirt = 1;
- error = minix_add_entry(dir,name,len, &bh ,&de);
+ error = minix_add_entry(dir, dentry->d_name.name,
+ dentry->d_name.len, &bh ,&de);
if (error) {
inode->i_nlink--;
inode->i_dirt = 1;
iput(inode);
- iput(dir);
return error;
}
de->inode = inode->i_ino;
mark_buffer_dirty(bh, 1);
brelse(bh);
- iput(dir);
- *result = inode;
+ d_instantiate(dentry, inode, 0);
return 0;
}
-int minix_mknod(struct inode * dir, const char * name, int len, int mode, int rdev)
+int minix_mknod(struct inode * dir, struct dentry *dentry, int mode, int rdev)
{
int error;
struct inode * inode;
if (!dir)
return -ENOENT;
- bh = minix_find_entry(dir,name,len,&de);
+ bh = minix_find_entry(dir, dentry->d_name.name,
+ dentry->d_name.len, &de);
if (bh) {
brelse(bh);
- iput(dir);
return -EEXIST;
}
inode = minix_new_inode(dir);
- if (!inode) {
- iput(dir);
+ if (!inode)
return -ENOSPC;
- }
inode->i_uid = current->fsuid;
inode->i_mode = mode;
inode->i_op = NULL;
if (S_ISBLK(mode) || S_ISCHR(mode))
inode->i_rdev = to_kdev_t(rdev);
inode->i_dirt = 1;
- error = minix_add_entry(dir, name, len, &bh, &de);
+ error = minix_add_entry(dir, dentry->d_name.name, dentry->d_name.len, &bh, &de);
if (error) {
inode->i_nlink--;
inode->i_dirt = 1;
iput(inode);
- iput(dir);
return error;
}
de->inode = inode->i_ino;
mark_buffer_dirty(bh, 1);
brelse(bh);
- iput(dir);
- iput(inode);
+ d_instantiate(dentry, inode, 0);
return 0;
}
-int minix_mkdir(struct inode * dir, const char * name, int len, int mode)
+int minix_mkdir(struct inode * dir, struct dentry *dentry, int mode)
{
int error;
struct inode * inode;
struct minix_dir_entry * de;
struct minix_sb_info * info;
- if (!dir || !dir->i_sb) {
- iput(dir);
+ if (!dir || !dir->i_sb)
return -EINVAL;
- }
info = &dir->i_sb->u.minix_sb;
- bh = minix_find_entry(dir,name,len,&de);
+ bh = minix_find_entry(dir, dentry->d_name.name,
+ dentry->d_name.len, &de);
if (bh) {
brelse(bh);
- iput(dir);
return -EEXIST;
}
- if (dir->i_nlink >= MINIX_LINK_MAX) {
- iput(dir);
+ if (dir->i_nlink >= MINIX_LINK_MAX)
return -EMLINK;
- }
inode = minix_new_inode(dir);
- if (!inode) {
- iput(dir);
+ if (!inode)
return -ENOSPC;
- }
inode->i_op = &minix_dir_inode_operations;
inode->i_size = 2 * info->s_dirsize;
dir_block = minix_bread(inode,0,1);
if (!dir_block) {
- iput(dir);
inode->i_nlink--;
inode->i_dirt = 1;
iput(inode);
if (dir->i_mode & S_ISGID)
inode->i_mode |= S_ISGID;
inode->i_dirt = 1;
- error = minix_add_entry(dir, name, len, &bh, &de);
+ error = minix_add_entry(dir, dentry->d_name.name,
+ dentry->d_name.len, &bh, &de);
if (error) {
- iput(dir);
inode->i_nlink=0;
iput(inode);
return error;
mark_buffer_dirty(bh, 1);
dir->i_nlink++;
dir->i_dirt = 1;
- iput(dir);
- iput(inode);
brelse(bh);
+ d_instantiate(dentry, inode, D_DIR);
return 0;
}
return 1;
}
-int minix_rmdir(struct inode * dir, const char * name, int len)
+int minix_rmdir(struct inode * dir, struct dentry *dentry)
{
int retval;
struct inode * inode;
struct minix_dir_entry * de;
inode = NULL;
- bh = minix_find_entry(dir,name,len,&de);
+ bh = minix_find_entry(dir, dentry->d_name.name,
+ dentry->d_name.len, &de);
retval = -ENOENT;
if (!bh)
goto end_rmdir;
retval = -EPERM;
- if (!(inode = iget(dir->i_sb, de->inode)))
- goto end_rmdir;
+ inode = dentry->d_inode;
+
if ((dir->i_mode & S_ISVTX) && !fsuser() &&
current->fsuid != inode->i_uid &&
current->fsuid != dir->i_uid)
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
dir->i_nlink--;
dir->i_dirt=1;
+ d_delete(dentry);
retval = 0;
end_rmdir:
- iput(dir);
- iput(inode);
brelse(bh);
return retval;
}
-int minix_unlink(struct inode * dir, const char * name, int len)
+int minix_unlink(struct inode * dir, struct dentry *dentry)
{
int retval;
struct inode * inode;
repeat:
retval = -ENOENT;
inode = NULL;
- bh = minix_find_entry(dir,name,len,&de);
+ bh = minix_find_entry(dir, dentry->d_name.name,
+ dentry->d_name.len, &de);
if (!bh)
goto end_unlink;
- if (!(inode = iget(dir->i_sb, de->inode)))
- goto end_unlink;
+ inode = dentry->d_inode;
+
retval = -EPERM;
if (S_ISDIR(inode->i_mode))
goto end_unlink;
if (de->inode != inode->i_ino) {
- iput(inode);
brelse(bh);
current->counter = 0;
schedule();
inode->i_nlink--;
inode->i_ctime = dir->i_ctime;
inode->i_dirt = 1;
+ d_delete(dentry); /* This also frees the inode */
retval = 0;
end_unlink:
brelse(bh);
- iput(inode);
- iput(dir);
return retval;
}
-int minix_symlink(struct inode * dir, const char * name, int len, const char * symname)
+int minix_symlink(struct inode * dir, struct dentry *dentry,
+ const char * symname)
{
struct minix_dir_entry * de;
struct inode * inode = NULL;
int i;
char c;
- if (!(inode = minix_new_inode(dir))) {
- iput(dir);
+ if (!(inode = minix_new_inode(dir)))
return -ENOSPC;
- }
+
inode->i_mode = S_IFLNK | 0777;
inode->i_op = &minix_symlink_inode_operations;
name_block = minix_bread(inode,0,1);
if (!name_block) {
- iput(dir);
inode->i_nlink--;
inode->i_dirt = 1;
iput(inode);
brelse(name_block);
inode->i_size = i;
inode->i_dirt = 1;
- bh = minix_find_entry(dir,name,len,&de);
+ bh = minix_find_entry(dir, dentry->d_name.name,
+ dentry->d_name.len, &de);
if (bh) {
inode->i_nlink--;
inode->i_dirt = 1;
iput(inode);
brelse(bh);
- iput(dir);
return -EEXIST;
}
- i = minix_add_entry(dir, name, len, &bh, &de);
+ i = minix_add_entry(dir, dentry->d_name.name,
+ dentry->d_name.len, &bh, &de);
if (i) {
inode->i_nlink--;
inode->i_dirt = 1;
iput(inode);
- iput(dir);
return i;
}
de->inode = inode->i_ino;
mark_buffer_dirty(bh, 1);
brelse(bh);
- iput(dir);
- iput(inode);
+ d_instantiate(dentry, inode, 0);
return 0;
}
-int minix_link(struct inode * oldinode, struct inode * dir, const char * name, int len)
+int minix_link(struct inode * inode, struct inode * dir,
+ struct dentry *dentry)
{
int error;
struct minix_dir_entry * de;
struct buffer_head * bh;
- if (S_ISDIR(oldinode->i_mode)) {
- iput(oldinode);
- iput(dir);
+ if (S_ISDIR(inode->i_mode))
return -EPERM;
- }
- if (oldinode->i_nlink >= MINIX_LINK_MAX) {
- iput(oldinode);
- iput(dir);
+
+ if (inode->i_nlink >= MINIX_LINK_MAX)
return -EMLINK;
- }
- bh = minix_find_entry(dir,name,len,&de);
+
+ bh = minix_find_entry(dir, dentry->d_name.name,
+ dentry->d_name.len, &de);
if (bh) {
brelse(bh);
- iput(dir);
- iput(oldinode);
return -EEXIST;
}
- error = minix_add_entry(dir, name, len, &bh, &de);
+ error = minix_add_entry(dir, dentry->d_name.name,
+ dentry->d_name.len, &bh, &de);
if (error) {
- iput(dir);
- iput(oldinode);
+ brelse(bh);
return error;
}
- de->inode = oldinode->i_ino;
+ de->inode = inode->i_ino;
mark_buffer_dirty(bh, 1);
brelse(bh);
- iput(dir);
- oldinode->i_nlink++;
- oldinode->i_ctime = CURRENT_TIME;
- oldinode->i_dirt = 1;
- iput(oldinode);
+ inode->i_nlink++;
+ inode->i_ctime = CURRENT_TIME;
+ inode->i_dirt = 1;
+ d_instantiate(dentry, inode, 0);
return 0;
}
if (new_inode->i_dev != old_inode->i_dev)
break;
ino = new_inode->i_ino;
- if (minix_lookup(new_inode,"..",2,&new_inode))
+ if (minix_lookup(new_inode,
+ &(struct qstr) { "..", 2, 0 },
+ &new_inode))
break;
if (new_inode->i_ino == ino)
break;
* Anybody can rename anything with this: the permission checks are left to the
* higher-level routines.
*/
-static int do_minix_rename(struct inode * old_dir, const char * old_name, int old_len,
- struct inode * new_dir, const char * new_name, int new_len)
+static int do_minix_rename(struct inode * old_dir, struct dentry *old_dentry,
+ struct inode * new_dir, struct dentry *new_dentry)
{
struct inode * old_inode, * new_inode;
struct buffer_head * old_bh, * new_bh, * dir_bh;
brelse(old_bh);
brelse(new_bh);
brelse(dir_bh);
- iput(old_inode);
- iput(new_inode);
current->counter = 0;
schedule();
start_up:
old_inode = new_inode = NULL;
old_bh = new_bh = dir_bh = NULL;
- old_bh = minix_find_entry(old_dir,old_name,old_len,&old_de);
+ old_bh = minix_find_entry(old_dir, old_dentry->d_name.name,
+ old_dentry->d_name.len, &old_de);
retval = -ENOENT;
if (!old_bh)
goto end_rename;
- old_inode = __iget(old_dir->i_sb, old_de->inode);
- if (!old_inode)
- goto end_rename;
+ old_inode = old_dentry->d_inode;
retval = -EPERM;
if ((old_dir->i_mode & S_ISVTX) &&
current->fsuid != old_inode->i_uid &&
current->fsuid != old_dir->i_uid && !fsuser())
goto end_rename;
- new_bh = minix_find_entry(new_dir,new_name,new_len,&new_de);
+ new_inode = new_dentry->d_inode;
+ new_bh = minix_find_entry(new_dir, new_dentry->d_name.name,
+ new_dentry->d_name.len, &new_de);
if (new_bh) {
- new_inode = __iget(new_dir->i_sb, new_de->inode);
if (!new_inode) {
brelse(new_bh);
new_bh = NULL;
goto end_rename;
}
if (!new_bh) {
- retval = minix_add_entry(new_dir,new_name,new_len,&new_bh,&new_de);
+ retval = minix_add_entry(new_dir,
+ new_dentry->d_name.name,
+ new_dentry->d_name.len,
+ &new_bh, &new_de);
if (retval)
goto end_rename;
}
new_dir->i_dirt = 1;
}
}
+ /* Update the dcache */
+ d_move(old_dentry, new_dentry->d_parent, &new_dentry->d_name);
+ d_delete(new_dentry);
retval = 0;
end_rename:
brelse(dir_bh);
brelse(old_bh);
brelse(new_bh);
- iput(old_inode);
- iput(new_inode);
- iput(old_dir);
- iput(new_dir);
return retval;
}
* the same device that races occur: many renames can happen at once, as long
* as they are on different partitions.
*/
-int minix_rename(struct inode * old_dir, const char * old_name, int old_len,
- struct inode * new_dir, const char * new_name, int new_len)
+int minix_rename(struct inode * old_dir, struct dentry *old_dentry,
+ struct inode * new_dir, struct dentry *new_dentry)
{
static struct wait_queue * wait = NULL;
static int lock = 0;
while (lock)
sleep_on(&wait);
lock = 1;
- result = do_minix_rename(old_dir, old_name, old_len,
- new_dir, new_name, new_len);
+ result = do_minix_rename(old_dir, old_dentry,
+ new_dir, new_dentry);
lock = 0;
wake_up(&wait);
return result;
nfs_truncate_dirty_pages(inode, sattr.size);
nfs_refresh_inode(inode, &fattr);
}
- inode->i_dirt = 0;
return error;
}
vmtruncate(inode, length);
if (inode->i_op && inode->i_op->truncate)
inode->i_op->truncate(inode);
- inode->i_status |= ST_MODIFIED;
}
up(&inode->i_sem);
return error;
mode = inode->i_mode;
newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
- inode->i_dirt = 1;
err = notify_change(inode, &newattrs);
-#ifdef CONFIG_OMIRR
- if(!err)
- omirr_printall(inode, " M %ld %ld ", CURRENT_TIME, newattrs.ia_mode);
-#endif
out:
unlock_kernel();
return err;
mode = inode->i_mode;
newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
- inode->i_dirt = 1;
error = notify_change(inode, &newattrs);
-#ifdef CONFIG_OMIRR
- if(!error)
- omirr_printall(inode, " M %ld %ld ", CURRENT_TIME, newattrs.ia_mode);
-#endif
iput_and_out:
iput(inode);
out:
newattrs.ia_mode &= ~S_ISGID;
newattrs.ia_valid |= ATTR_MODE;
}
- inode->i_dirt = 1;
if (inode->i_sb && inode->i_sb->dq_op) {
inode->i_sb->dq_op->initialize(inode, -1);
error = -EDQUOT;
inode->i_sb->dq_op->transfer(inode, &newattrs, 1);
} else
error = notify_change(inode, &newattrs);
-#ifdef CONFIG_OMIRR
- if(!error)
- omirr_printall(inode, " O %d %d ", CURRENT_TIME,
- newattrs.ia_uid, newattrs.ia_gid);
-#endif
out:
unlock_kernel();
return error;
newattrs.ia_mode &= ~S_ISGID;
newattrs.ia_valid |= ATTR_MODE;
}
- inode->i_dirt = 1;
if (inode->i_sb->dq_op) {
inode->i_sb->dq_op->initialize(inode, -1);
error = -EDQUOT;
inode->i_sb->dq_op->transfer(inode, &newattrs, 1);
} else
error = notify_change(inode, &newattrs);
-#ifdef CONFIG_OMIRR
- if(!error)
- omirr_printall(inode, " O %d %d ", CURRENT_TIME,
- newattrs.ia_uid, newattrs.ia_gid);
-#endif
iput_and_out:
iput(inode);
out:
PIPE_LOCK(*inode)--;
wake_up_interruptible(&PIPE_WAIT(*inode));
if (read) {
- if (DO_UPDATE_ATIME(inode)) {
- inode->i_atime = CURRENT_TIME;
- inode->i_dirt = 1;
- }
+ UPDATE_ATIME(inode);
return read;
}
if (PIPE_WRITERS(*inode))
free = 1;
}
inode->i_ctime = inode->i_mtime = CURRENT_TIME;
- inode->i_dirt = 1;
+ mark_inode_dirty(inode);
return written;
}
j = error;
f1->f_inode = f2->f_inode = inode;
+
/* read file */
f1->f_pos = f2->f_pos = 0;
f1->f_flags = O_RDONLY;
f1->f_op = &read_pipe_fops;
f1->f_mode = 1;
+
/* write file */
f2->f_flags = O_WRONLY;
f2->f_op = &write_pipe_fops;
void proc_write_inode(struct inode * inode)
{
- inode->i_dirt=0;
}
goto out;
down(&inode->i_sem);
error = write(inode,file,buf,count);
- inode->i_status |= ST_MODIFIED;
up(&inode->i_sem);
out:
fput(file, inode);
if (nr != len)
break;
}
- if(fn == (IO_fn_t) file->f_op->write)
- inode->i_status |= ST_MODIFIED;
if (iov != iovstack)
kfree(iov);
return retval;
iput(inode);
goto out;
}
- if (!IS_RDONLY(inode)) {
- inode->i_atime = CURRENT_TIME;
- inode->i_dirt = 1;
- }
+ UPDATE_ATIME(inode);
error = inode->i_op->readlink(inode,buf,bufsiz);
iput(inode);
out:
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* follow_link */
generic_readpage, /* readpage */
NULL, /* writepage */
ufs_bmap, /* bmap */
}
/* XXX - this is a mess, especially for endianity */
-int ufs_lookup (struct inode * dir, const char * name, int len,
+int ufs_lookup (struct inode * dir, struct qstr *qname,
struct inode ** result)
{
unsigned long int lfragno, fragno;
struct buffer_head * bh;
struct ufs_direct * d;
+ const char *name = qname->name;
+ int len = qname->len;
if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG)
printk("Passed name: %s\nPassed length: %d\n", name, len);
sb->u.ufs_sb.s_lmask = ~((ufs_swab32(usb->fs_fmask) - ufs_swab32(usb->fs_bmask))
>> ufs_swab32(usb->fs_fshift));
sb->u.ufs_sb.s_fsfrag = ufs_swab32(usb->fs_frag); /* XXX - rename this later */
- sb->s_mounted = iget(sb, UFS_ROOTINO);
+ sb->s_root = d_alloc_root(iget(sb, UFS_ROOTINO), NULL);
#ifdef DEBUG_UFS_SUPER
printk("ufs_read_super: inopb %u\n", sb->u.ufs_sb.s_inopb);
#include <linux/net.h>
#include <linux/kdev_t.h>
#include <linux/ioctl.h>
+#include <linux/list.h>
#include <asm/atomic.h>
#include <asm/bitops.h>
*/
#define FS_IBASKET 8 /* FS does callback to free_ibasket() if space gets low. */
-/* public flags for i_status */
-#define ST_MODIFIED 1024
-
/*
* These are the fs-independent mount-flags: up to 16 flags are supported
*/
#define IS_APPEND(inode) ((inode)->i_flags & S_APPEND)
#define IS_IMMUTABLE(inode) ((inode)->i_flags & S_IMMUTABLE)
#define IS_NOATIME(inode) ((inode)->i_flags & MS_NOATIME)
-#define DO_UPDATE_ATIME(inode) (!IS_NOATIME(inode) && !IS_RDONLY(inode))
+
+#define UPDATE_ATIME(inode) \
+ if (!IS_NOATIME(inode) && !IS_RDONLY(inode)) { \
+ inode->i_atime = CURRENT_TIME; \
+ mark_inode_dirty(inode); \
+ }
/* the read-only stuff doesn't really belong here, but any other place is
probably as bad and I don't want to create yet another include file. */
#include <linux/quota.h>
struct inode {
- struct inode *i_hash_next;
- struct inode *i_hash_prev;
- struct inode *i_next;
- struct inode *i_prev;
+ struct list_head i_hash;
+ struct list_head i_list;
unsigned long i_ino;
kdev_t i_dev;
struct page *i_pages;
struct dquot *i_dquot[MAXQUOTAS];
- struct inode *i_lru_next;
- struct inode *i_lru_prev;
-
- struct inode *i_basket_next;
- struct inode *i_basket_prev;
struct dentry *i_dentry;
- unsigned short i_status;
- unsigned short i_reuse_count;
+ unsigned int i_state;
unsigned int i_flags;
- unsigned char i_lock;
- unsigned char i_dirt;
unsigned char i_pipe;
unsigned char i_sock;
- unsigned char i_level;
- unsigned short i_fill;
-
int i_writecount;
unsigned int i_attr_flags;
union {
} u;
};
+/* Inode state bits.. */
+#define I_DIRTY 0
+#define I_LOCK 1
+
+extern void __mark_inode_dirty(struct inode *);
+static inline void mark_inode_dirty(struct inode *inode)
+{
+ if (!test_and_set_bit(I_DIRTY, &inode->i_state))
+ __mark_inode_dirty(inode);
+}
+
struct file {
struct file *f_next, **f_pprev;
struct inode *f_inode;
/* Not to be used by ordinary vfs users */
extern void _get_inode(struct inode * inode);
-extern blocking void __iput(struct inode * inode);
-
-extern blocking void _iput(struct inode * inode);
-extern inline blocking void iput(struct inode * inode)
-{
- if (inode) {
- extern void wake_up_interruptible(struct wait_queue **q);
-
- if (inode->i_pipe)
- wake_up_interruptible(&inode->u.pipe_i.wait);
-
- /* It does not matter if somebody re-increments it in between,
- * only the _last_ user needs to call _iput().
- */
- if (atomic_dec_and_test(&inode->i_count))
- _iput(inode);
- }
-}
+extern void iput(struct inode * inode);
extern blocking struct inode * iget(struct super_block * sb, unsigned long nr);
-extern blocking void _clear_inode(struct inode * inode, int external, int verbose);
-extern blocking inline void clear_inode(struct inode * inode)
-{
- vfs_lock();
- _clear_inode(inode, 1, 1);
- vfs_unlock();
-}
-extern blocking struct inode * _get_empty_inode(void);
-extern inline blocking struct inode * get_empty_inode(void)
-{
- struct inode * inode;
- vfs_lock();
- inode = _get_empty_inode();
- vfs_unlock();
- return inode;
-}
+extern blocking void clear_inode(struct inode * inode);
+extern blocking struct inode * get_empty_inode(void);
+
/* Please prefer to use this function in future, instead of using
* a get_empty_inode()/insert_inode_hash() combination.
* It allows for better checking and less race conditions.
extern int isofs_open(struct inode * inode, struct file * filp);
extern void isofs_release(struct inode * inode, struct file * filp);
-extern int isofs_lookup(struct inode * dir,const char * name, int len,
+extern int isofs_lookup(struct inode * dir, struct qstr *dentry,
struct inode ** result);
extern unsigned long isofs_count_free_inodes(struct super_block *sb);
extern int isofs_new_block(int dev);
--- /dev/null
+#ifndef _LINUX_LIST_H
+#define _LINUX_LIST_H
+
+/*
+ * Simple doubly linked list implementation.
+ */
+struct list_head {
+ struct list_head *next, *prev;
+};
+
+#define LIST_HEAD(name) \
+ struct list_head name = { &name, &name }
+
+#define INIT_LIST_HEAD(ptr) do { \
+ (ptr)->next = (ptr); (ptr)->prev = (ptr); \
+} while (0)
+
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+ struct list_head *next = head->next;
+ next->prev = new;
+ new->next = next;
+ new->prev = head;
+ head->next = new;
+}
+
+static inline void list_del(struct list_head *entry)
+{
+ struct list_head *next, *prev;
+ next = entry->next;
+ prev = entry->prev;
+ next->prev = prev;
+ prev->next = next;
+}
+
+#define list_entry(ptr, type, member) \
+ ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
+
+#endif
#ifdef __KERNEL__
-extern int minix_lookup(struct inode * dir,const char * name, int len,
+extern int minix_lookup(struct inode * dir, struct qstr *name,
struct inode ** result);
-extern int minix_create(struct inode * dir,const char * name, int len, int mode,
- struct inode ** result);
-extern int minix_mkdir(struct inode * dir, const char * name, int len, int mode);
-extern int minix_rmdir(struct inode * dir, const char * name, int len);
-extern int minix_unlink(struct inode * dir, const char * name, int len);
-extern int minix_symlink(struct inode * inode, const char * name, int len,
+extern int minix_create(struct inode * dir, struct dentry *dentry, int mode);
+extern int minix_mkdir(struct inode * dir, struct dentry *dentry, int mode);
+extern int minix_rmdir(struct inode * dir, struct dentry *dentry);
+extern int minix_unlink(struct inode * dir, struct dentry *dentry);
+extern int minix_symlink(struct inode * inode, struct dentry *dentry,
const char * symname);
-extern int minix_link(struct inode * oldinode, struct inode * dir, const char * name, int len);
-extern int minix_mknod(struct inode * dir, const char * name, int len, int mode, int rdev);
-extern int minix_rename(struct inode * old_dir, const char * old_name, int old_len,
- struct inode * new_dir, const char * new_name, int new_len);
+extern int minix_link(struct inode * oldinode, struct inode * dir, struct dentry *dentry);
+extern int minix_mknod(struct inode * dir, struct dentry *dentry, int mode, int rdev);
+extern int minix_rename(struct inode * old_dir, struct dentry *old_dentry,
+ struct inode * new_dir, struct dentry *new_dentry);
extern struct inode * minix_new_inode(const struct inode * dir);
extern void minix_free_inode(struct inode * inode);
extern unsigned long minix_count_free_inodes(struct super_block *sb);
extern void ufs_print_inode (struct inode *);
/* ufs_namei.c */
-extern int ufs_lookup (struct inode *, const char *, int, struct inode **);
+extern int ufs_lookup (struct inode *, struct qstr *, struct inode **);
/* ufs_super.c */
extern void ufs_warning (struct super_block *, const char *, const char *, ...)
EXPORT_SYMBOL(putname);
EXPORT_SYMBOL(__fput);
EXPORT_SYMBOL(iget);
-EXPORT_SYMBOL(_iput);
+EXPORT_SYMBOL(iput);
EXPORT_SYMBOL(__namei);
EXPORT_SYMBOL(lookup_dentry);
EXPORT_SYMBOL(open_namei);
EXPORT_SYMBOL(sys_tz);
EXPORT_SYMBOL(__wait_on_super);
EXPORT_SYMBOL(file_fsync);
-EXPORT_SYMBOL(_clear_inode);
+EXPORT_SYMBOL(clear_inode);
EXPORT_SYMBOL(refile_buffer);
EXPORT_SYMBOL(nr_async_pages);
EXPORT_SYMBOL(___strtok);
EXPORT_SYMBOL(blkdev_inode_operations);
EXPORT_SYMBOL(read_ahead);
EXPORT_SYMBOL(get_hash_table);
-EXPORT_SYMBOL(_get_empty_inode);
+EXPORT_SYMBOL(get_empty_inode);
EXPORT_SYMBOL(insert_inode_hash);
EXPORT_SYMBOL(event);
EXPORT_SYMBOL(__down);
acct_file.f_op->write(acct_file.f_inode, &acct_file,
(char *)&ac, sizeof(struct acct));
- /* inode->i_status |= ST_MODIFIED is willingly *not* done here */
-
set_fs(fs);
}
return 0;
filp->f_reada = 1;
if (page_cache)
free_page(page_cache);
- if (DO_UPDATE_ATIME(inode)) {
- inode->i_atime = CURRENT_TIME;
- inode->i_dirt = 1;
- }
+ UPDATE_ATIME(inode)
if (!read)
read = error;
return read;
retval = -EIO;
if (size == file->f_op->write(inode, file, (const char *) page, size))
retval = 0;
- /* inode->i_status |= ST_MODIFIED is willingly *not* done here */
set_fs(old_fs);
return retval;
}
return -EACCES;
if (!inode->i_op || !inode->i_op->readpage)
return -ENOEXEC;
- if (DO_UPDATE_ATIME(inode)) {
- inode->i_atime = CURRENT_TIME;
- inode->i_dirt = 1;
- }
+ UPDATE_ATIME(inode);
vma->vm_inode = inode;
atomic_inc(&inode->i_count);
vma->vm_ops = ops;