Commit 9dfa0bd3 authored by J. R. Okajima's avatar J. R. Okajima
Browse files

aufs: remount 1/5, an array of the cached inodes



As a part of branch-management, aufs maintains all cached inodes,
dentries, and opened files in remounting.
This commits handles the cached inodes by counting the number of cached
inodes, generating an array of their pointers. I don't like such array
approach, but I don't have another idea.
Signed-off-by: default avatarJ. R. Okajima <hooanon05g@gmail.com>
parent d11c974d
......@@ -191,6 +191,8 @@ int au_iinfo_init(struct inode *inode)
nbr = 1;
hi = kmalloc_array(nbr, sizeof(*iinfo->ii_hinode), GFP_NOFS);
if (hi) {
au_lcnt_inc(&au_sbi(sb)->si_ninodes);
iinfo->ii_hinode = hi;
for (i = 0; i < nbr; i++, hi++)
au_hinode_init(hi);
......@@ -237,6 +239,7 @@ void au_iinfo_fin(struct inode *inode)
AuDebugOn(au_is_bad_inode(inode));
sb = inode->i_sb;
au_lcnt_dec(&au_sbi(sb)->si_ninodes);
if (si_pid_test(sb))
au_xino_delete_inode(inode, unlinked);
else {
......
......@@ -24,6 +24,9 @@ void au_si_free(struct kobject *kobj)
AuDebugOn(!hlist_bl_empty(sbinfo->si_plink + i));
AuDebugOn(atomic_read(&sbinfo->si_nowait.nw_len));
AuLCntZero(au_lcnt_read(&sbinfo->si_ninodes, /*do_rev*/0));
au_lcnt_fin(&sbinfo->si_ninodes, /*do_sync*/0);
au_rw_write_lock(&sbinfo->si_rwsem);
au_br_free(sbinfo);
au_rw_write_unlock(&sbinfo->si_rwsem);
......@@ -32,6 +35,7 @@ void au_si_free(struct kobject *kobj)
mutex_destroy(&sbinfo->si_xib_mtx);
AuRwDestroy(&sbinfo->si_rwsem);
au_lcnt_wait_for_fin(&sbinfo->si_ninodes);
au_kfree_rcu(sbinfo);
}
......@@ -57,6 +61,8 @@ int au_si_alloc(struct super_block *sb)
au_nwt_init(&sbinfo->si_nowait);
au_rw_init_wlock(&sbinfo->si_rwsem);
au_lcnt_init(&sbinfo->si_ninodes, /*release*/NULL);
sbinfo->si_bbot = -1;
sbinfo->si_last_br_id = AUFS_BRANCH_MAX / 2;
......
......@@ -8,7 +8,9 @@
*/
#include <linux/iversion.h>
#include <linux/mm.h>
#include <linux/seq_file.h>
#include <linux/vmalloc.h>
#include "aufs.h"
/*
......@@ -222,6 +224,90 @@ static void aufs_put_super(struct super_block *sb)
/* ---------------------------------------------------------------------- */
void *au_array_alloc(unsigned long long *hint, au_arraycb_t cb,
struct super_block *sb, void *arg)
{
void *array;
unsigned long long n, sz;
array = NULL;
n = 0;
if (!*hint)
goto out;
if (*hint > ULLONG_MAX / sizeof(array)) {
array = ERR_PTR(-EMFILE);
pr_err("hint %llu\n", *hint);
goto out;
}
sz = sizeof(array) * *hint;
array = kzalloc(sz, GFP_NOFS);
if (unlikely(!array))
array = vzalloc(sz);
if (unlikely(!array)) {
array = ERR_PTR(-ENOMEM);
goto out;
}
n = cb(sb, array, *hint, arg);
AuDebugOn(n > *hint);
out:
*hint = n;
return array;
}
static unsigned long long au_iarray_cb(struct super_block *sb, void *a,
unsigned long long max __maybe_unused,
void *arg)
{
unsigned long long n;
struct inode **p, *inode;
struct list_head *head;
n = 0;
p = a;
head = arg;
spin_lock(&sb->s_inode_list_lock);
list_for_each_entry(inode, head, i_sb_list) {
if (!au_is_bad_inode(inode)
&& au_ii(inode)->ii_btop >= 0) {
spin_lock(&inode->i_lock);
if (atomic_read(&inode->i_count)) {
au_igrab(inode);
*p++ = inode;
n++;
AuDebugOn(n > max);
}
spin_unlock(&inode->i_lock);
}
}
spin_unlock(&sb->s_inode_list_lock);
return n;
}
struct inode **au_iarray_alloc(struct super_block *sb, unsigned long long *max)
{
struct au_sbinfo *sbi;
sbi = au_sbi(sb);
*max = au_lcnt_read(&sbi->si_ninodes, /*do_rev*/1);
return au_array_alloc(max, au_iarray_cb, sb, &sb->s_inodes);
}
void au_iarray_free(struct inode **a, unsigned long long max)
{
unsigned long long ull;
for (ull = 0; ull < max; ull++)
iput(a[ull]);
kvfree(a);
}
/* ---------------------------------------------------------------------- */
/* stop extra interpretation of errno in mount(8), and strange error messages */
static int cvt_err(int err)
{
......
......@@ -15,6 +15,7 @@
#include <linux/fs.h>
#include <linux/kobject.h>
#include "hbl.h"
#include "lcnt.h"
#include "rwsem.h"
#include "wkq.h"
......@@ -63,6 +64,12 @@ struct au_sbinfo {
*/
struct au_rwsem si_rwsem;
/*
* dirty approach to protect sb->sb_inodes from
* remount.
*/
au_lcnt_t si_ninodes;
/* branch management */
unsigned int si_generation;
......@@ -166,6 +173,12 @@ struct au_sbinfo {
/* super.c */
extern struct file_system_type aufs_fs_type;
struct inode *au_iget_locked(struct super_block *sb, ino_t ino);
typedef unsigned long long (*au_arraycb_t)(struct super_block *sb, void *array,
unsigned long long max, void *arg);
void *au_array_alloc(unsigned long long *hint, au_arraycb_t cb,
struct super_block *sb, void *arg);
struct inode **au_iarray_alloc(struct super_block *sb, unsigned long long *max);
void au_iarray_free(struct inode **a, unsigned long long max);
/* sbinfo.c */
void au_si_free(struct kobject *kobj);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment