#include <linux/pagemap.h>
#include <linux/cdev.h>
#include <linux/bootmem.h>
+#include <linux/vs_base.h>
/*
* This is needed for the following functions:
static kmem_cache_t * inode_cachep;
-static void prune_icache(int nr_to_scan);
-
-
-#define INODE_UNUSED_THRESHOLD 15000
-#define PRUNE_BATCH_COUNT 32
-
-void try_to_clip_inodes(void)
-{
- unsigned long count = 0;
- /* if there are a LOT of unused inodes in cache, better shrink a few first */
-
- /* check lockless first to not take the lock always here; racing occasionally isn't a big deal */
- if (inodes_stat.nr_unused > INODE_UNUSED_THRESHOLD) {
- spin_lock(&inode_lock);
- if (inodes_stat.nr_unused > INODE_UNUSED_THRESHOLD)
- count = inodes_stat.nr_unused - INODE_UNUSED_THRESHOLD;
- spin_unlock(&inode_lock);
- if (count)
- prune_icache(count);
- }
-}
-
-
static struct inode *alloc_inode(struct super_block *sb)
{
static struct address_space_operations empty_aops;
static struct inode_operations empty_iops;
static struct file_operations empty_fops;
struct inode *inode;
-
+
if (sb->s_op->alloc_inode)
inode = sb->s_op->alloc_inode(sb);
else
struct address_space * const mapping = &inode->i_data;
inode->i_sb = sb;
- if (sb->s_flags & MS_TAGXID)
- inode->i_xid = current->xid;
- else
- inode->i_xid = 0; /* maybe xid -1 would be better? */
// inode->i_dqh = dqhget(sb->s_dqh);
+
+ /* essential because of inode slab reuse */
+ inode->i_xid = 0;
inode->i_blkbits = sb->s_blocksize_bits;
inode->i_flags = 0;
atomic_set(&inode->i_count, 1);
inode->i_bdev = NULL;
inode->i_cdev = NULL;
inode->i_rdev = 0;
- // inode->i_xid = 0; /* maybe not too wise ... */
inode->i_security = NULL;
inode->dirtied_when = 0;
if (security_inode_alloc(inode)) {
* and we don't want to recurse into the FS that called us
* in clear_inode() and friends..
*/
- if (gfp_mask & __GFP_FS)
- prune_icache(nr);
+ if (!(gfp_mask & __GFP_FS))
+ return -1;
+ prune_icache(nr);
}
return (inodes_stat.nr_unused / 100) * sysctl_vfs_cache_pressure;
}
* When ctime_too is specified update the ctime too.
*/
-void inode_update_time(struct inode *inode, int ctime_too)
+void inode_update_time(struct inode *inode, struct vfsmount *mnt, int ctime_too)
{
struct timespec now;
int sync_it = 0;
if (IS_NOCMTIME(inode))
return;
- if (IS_RDONLY(inode))
+ if (IS_RDONLY(inode) || MNT_IS_RDONLY(mnt))
return;
now = current_kernel_time();
#endif
-/*
- * Hashed waitqueues for wait_on_inode(). The table is pretty small - the
- * kernel doesn't lock many inodes at the same time.
- */
-#define I_WAIT_TABLE_ORDER 3
-static struct i_wait_queue_head {
- wait_queue_head_t wqh;
-} ____cacheline_aligned_in_smp i_wait_queue_heads[1<<I_WAIT_TABLE_ORDER];
-
-/*
- * Return the address of the waitqueue_head to be used for this inode
- */
-static wait_queue_head_t *i_waitq_head(struct inode *inode)
+int inode_wait(void *word)
{
- return &i_wait_queue_heads[hash_ptr(inode, I_WAIT_TABLE_ORDER)].wqh;
-}
-
-void __wait_on_inode(struct inode *inode)
-{
- DECLARE_WAITQUEUE(wait, current);
- wait_queue_head_t *wq = i_waitq_head(inode);
-
- add_wait_queue(wq, &wait);
-repeat:
- set_current_state(TASK_UNINTERRUPTIBLE);
- if (inode->i_state & I_LOCK) {
- schedule();
- goto repeat;
- }
- remove_wait_queue(wq, &wait);
- __set_current_state(TASK_RUNNING);
+ schedule();
+ return 0;
}
/*
* that it isn't found. This is because iget will immediately call
* ->read_inode, and we want to be sure that evidence of the deletion is found
* by ->read_inode.
- *
- * This call might return early if an inode which shares the waitq is woken up.
- * This is most easily handled by the caller which will loop around again
- * looking for the inode.
- *
* This is called with inode_lock held.
*/
static void __wait_on_freeing_inode(struct inode *inode)
{
- DECLARE_WAITQUEUE(wait, current);
- wait_queue_head_t *wq = i_waitq_head(inode);
+ wait_queue_head_t *wq;
+ DEFINE_WAIT_BIT(wait, &inode->i_state, __I_LOCK);
- add_wait_queue(wq, &wait);
- set_current_state(TASK_UNINTERRUPTIBLE);
+ /*
+ * I_FREEING and I_CLEAR are cleared in process context under
+ * inode_lock, so we have to give the tasks who would clear them
+ * a chance to run and acquire inode_lock.
+ */
+ if (!(inode->i_state & I_LOCK)) {
+ spin_unlock(&inode_lock);
+ yield();
+ spin_lock(&inode_lock);
+ return;
+ }
+ wq = bit_waitqueue(&inode->i_state, __I_LOCK);
+ prepare_to_wait(wq, &wait.wait, TASK_UNINTERRUPTIBLE);
spin_unlock(&inode_lock);
schedule();
- remove_wait_queue(wq, &wait);
+ finish_wait(wq, &wait.wait);
spin_lock(&inode_lock);
}
void wake_up_inode(struct inode *inode)
{
- wait_queue_head_t *wq = i_waitq_head(inode);
-
/*
* Prevent speculative execution through spin_unlock(&inode_lock);
*/
smp_mb();
- if (waitqueue_active(wq))
- wake_up_all(wq);
+ wake_up_bit(&inode->i_state, __I_LOCK);
}
static __initdata unsigned long ihash_entries;
void __init inode_init(unsigned long mempages)
{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(i_wait_queue_heads); i++)
- init_waitqueue_head(&i_wait_queue_heads[i].wqh);
-
/* inode slab cache */
inode_cachep = kmem_cache_create("inode_cache", sizeof(struct inode),
- 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, init_once,
- NULL);
+ 0, SLAB_PANIC, init_once, NULL);
set_shrinker(DEFAULT_SEEKS, shrink_icache_memory);
}