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) ...@@ -191,6 +191,8 @@ int au_iinfo_init(struct inode *inode)
nbr = 1; nbr = 1;
hi = kmalloc_array(nbr, sizeof(*iinfo->ii_hinode), GFP_NOFS); hi = kmalloc_array(nbr, sizeof(*iinfo->ii_hinode), GFP_NOFS);
if (hi) { if (hi) {
au_lcnt_inc(&au_sbi(sb)->si_ninodes);
iinfo->ii_hinode = hi; iinfo->ii_hinode = hi;
for (i = 0; i < nbr; i++, hi++) for (i = 0; i < nbr; i++, hi++)
au_hinode_init(hi); au_hinode_init(hi);
...@@ -237,6 +239,7 @@ void au_iinfo_fin(struct inode *inode) ...@@ -237,6 +239,7 @@ void au_iinfo_fin(struct inode *inode)
AuDebugOn(au_is_bad_inode(inode)); AuDebugOn(au_is_bad_inode(inode));
sb = inode->i_sb; sb = inode->i_sb;
au_lcnt_dec(&au_sbi(sb)->si_ninodes);
if (si_pid_test(sb)) if (si_pid_test(sb))
au_xino_delete_inode(inode, unlinked); au_xino_delete_inode(inode, unlinked);
else { else {
......
...@@ -24,6 +24,9 @@ void au_si_free(struct kobject *kobj) ...@@ -24,6 +24,9 @@ void au_si_free(struct kobject *kobj)
AuDebugOn(!hlist_bl_empty(sbinfo->si_plink + i)); AuDebugOn(!hlist_bl_empty(sbinfo->si_plink + i));
AuDebugOn(atomic_read(&sbinfo->si_nowait.nw_len)); 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_rw_write_lock(&sbinfo->si_rwsem);
au_br_free(sbinfo); au_br_free(sbinfo);
au_rw_write_unlock(&sbinfo->si_rwsem); au_rw_write_unlock(&sbinfo->si_rwsem);
...@@ -32,6 +35,7 @@ void au_si_free(struct kobject *kobj) ...@@ -32,6 +35,7 @@ void au_si_free(struct kobject *kobj)
mutex_destroy(&sbinfo->si_xib_mtx); mutex_destroy(&sbinfo->si_xib_mtx);
AuRwDestroy(&sbinfo->si_rwsem); AuRwDestroy(&sbinfo->si_rwsem);
au_lcnt_wait_for_fin(&sbinfo->si_ninodes);
au_kfree_rcu(sbinfo); au_kfree_rcu(sbinfo);
} }
...@@ -57,6 +61,8 @@ int au_si_alloc(struct super_block *sb) ...@@ -57,6 +61,8 @@ int au_si_alloc(struct super_block *sb)
au_nwt_init(&sbinfo->si_nowait); au_nwt_init(&sbinfo->si_nowait);
au_rw_init_wlock(&sbinfo->si_rwsem); au_rw_init_wlock(&sbinfo->si_rwsem);
au_lcnt_init(&sbinfo->si_ninodes, /*release*/NULL);
sbinfo->si_bbot = -1; sbinfo->si_bbot = -1;
sbinfo->si_last_br_id = AUFS_BRANCH_MAX / 2; sbinfo->si_last_br_id = AUFS_BRANCH_MAX / 2;
......
...@@ -8,7 +8,9 @@ ...@@ -8,7 +8,9 @@
*/ */
#include <linux/iversion.h> #include <linux/iversion.h>
#include <linux/mm.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/vmalloc.h>
#include "aufs.h" #include "aufs.h"
/* /*
...@@ -222,6 +224,90 @@ static void aufs_put_super(struct super_block *sb) ...@@ -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 */ /* stop extra interpretation of errno in mount(8), and strange error messages */
static int cvt_err(int err) static int cvt_err(int err)
{ {
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/kobject.h> #include <linux/kobject.h>
#include "hbl.h" #include "hbl.h"
#include "lcnt.h"
#include "rwsem.h" #include "rwsem.h"
#include "wkq.h" #include "wkq.h"
...@@ -63,6 +64,12 @@ struct au_sbinfo { ...@@ -63,6 +64,12 @@ struct au_sbinfo {
*/ */
struct au_rwsem si_rwsem; struct au_rwsem si_rwsem;
/*
* dirty approach to protect sb->sb_inodes from
* remount.
*/
au_lcnt_t si_ninodes;
/* branch management */ /* branch management */
unsigned int si_generation; unsigned int si_generation;
...@@ -166,6 +173,12 @@ struct au_sbinfo { ...@@ -166,6 +173,12 @@ struct au_sbinfo {
/* super.c */ /* super.c */
extern struct file_system_type aufs_fs_type; extern struct file_system_type aufs_fs_type;
struct inode *au_iget_locked(struct super_block *sb, ino_t ino); 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 */ /* sbinfo.c */
void au_si_free(struct kobject *kobj); 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