Commit 6fe05098 authored by J. R. Okajima's avatar J. R. Okajima
Browse files

aufs: xino 1/2, core



XINO and XIB files are to maintain the inode numbers in aufs
(cf. struct.txt and aufs manual in aufs-util.git).

XINO file contains just a sequence of the inode numbers, and their
offset in the file is real_inum x sizeof(inum).  So the size is limited
by s_maxbytes of the filesystem where XINO file is located.  In order to
support the larger inum, aufs stores XINO files as an internal array.

Sometimes the size of XINO file can be a problem, ie. too big,
particularly when XINO files are located on tmpfs. In this case, another
separate patch tmpfs-ino.patch in aufs4-standalone.git is recommended
(as well as vfs-ino.patch). The patch makes tmpfs to maintain inode
number within itself and suppress its discontiguous distribution.

See also the document in next commit.
Signed-off-by: default avatarJ. R. Okajima <hooanon05g@gmail.com>
parent f04356cb
......@@ -10,7 +10,7 @@ ccflags-y += -DDEBUG
ccflags-y += -include ${srctree}/include/uapi/linux/aufs_type.h
obj-$(CONFIG_AUFS_FS) += aufs.o
aufs-y := module.o sbinfo.o super.o branch.o opts.o \
aufs-y := module.o sbinfo.o super.o branch.o xino.o opts.o \
wkq.o vfsub.o dcsub.o \
cpup.o \
dinfo.o \
......
......@@ -27,6 +27,7 @@
#include "dcsub.h"
#include "dentry.h"
#include "fstype.h"
#include "hbl.h"
#include "inode.h"
#include "lcnt.h"
#include "module.h"
......
......@@ -18,8 +18,30 @@
/* ---------------------------------------------------------------------- */
/* a xino file */
struct au_xino {
struct file **xi_file;
unsigned int xi_nfile;
struct {
spinlock_t spin;
ino_t *array;
int total;
/* reserved for future use */
/* unsigned long *bitmap; */
wait_queue_head_t wqh;
} xi_nondir;
struct mutex xi_mtx; /* protects xi_file array */
struct hlist_bl_head xi_writing;
struct kref xi_kref;
};
/* protected by superblock rwsem */
struct au_branch {
struct au_xino *br_xino;
aufs_bindex_t br_id;
int br_perm;
......@@ -44,6 +66,28 @@ static inline struct super_block *au_br_sb(struct au_branch *br)
return au_br_mnt(br)->mnt_sb;
}
static inline void au_xino_get(struct au_branch *br)
{
struct au_xino *xi;
xi = br->br_xino;
if (xi)
kref_get(&xi->xi_kref);
}
static inline int au_xino_count(struct au_branch *br)
{
int v;
struct au_xino *xi;
v = 0;
xi = br->br_xino;
if (xi)
v = kref_read(&xi->xi_kref);
return v;
}
/* ---------------------------------------------------------------------- */
/* branch.c */
......@@ -53,6 +97,56 @@ int au_br_index(struct super_block *sb, aufs_bindex_t br_id);
struct au_opt_add;
int au_br_add(struct super_block *sb, struct au_opt_add *add);
/* xino.c */
aufs_bindex_t au_xi_root(struct super_block *sb, struct dentry *dentry);
struct file *au_xino_create(struct super_block *sb, char *fpath, int silent);
struct file *au_xino_create2(struct super_block *sb, struct path *base,
struct file *copy_src);
struct au_xi_new {
struct au_xino *xi; /* switch between xino and xigen */
int idx;
struct path *base;
struct file *copy_src;
};
struct file *au_xi_new(struct super_block *sb, struct au_xi_new *xinew);
int au_xino_read(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino,
ino_t *ino);
int au_xino_write(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino,
ino_t ino);
ssize_t xino_fread(vfs_readf_t func, struct file *file, void *buf, size_t size,
loff_t *pos);
ssize_t xino_fwrite(vfs_writef_t func, struct file *file, void *buf,
size_t size, loff_t *pos);
struct au_xino *au_xino_alloc(unsigned int nfile);
int au_xino_put(struct au_branch *br);
struct file *au_xino_file1(struct au_xino *xi);
ino_t au_xino_new_ino(struct super_block *sb);
void au_xino_delete_inode(struct inode *inode, const int unlinked);
/* ---------------------------------------------------------------------- */
/* @idx is signed to accept -1 meaning the first file */
static inline struct file *au_xino_file(struct au_xino *xi, int idx)
{
struct file *file;
file = NULL;
if (!xi)
goto out;
if (idx >= 0) {
if (idx < xi->xi_nfile)
file = xi->xi_file[idx];
} else
file = au_xino_file1(xi);
out:
return file;
}
/* ---------------------------------------------------------------------- */
/* Superblock to branch */
......
......@@ -51,12 +51,19 @@ AuStubInt0(au_debug_test, void)
pr_debug("DEBUG: " fmt, ##__VA_ARGS__); \
} while (0)
#define AuLabel(l) AuDbg(#l "\n")
#define AuIOErr(fmt, ...) pr_err("I/O Error, " fmt, ##__VA_ARGS__)
#define AuWarn1(fmt, ...) do { \
static unsigned char _c; \
if (!_c++) \
pr_warn(fmt, ##__VA_ARGS__); \
} while (0)
#define AuIOErr1(fmt, ...) do { \
static unsigned char _c; \
if (!_c++) \
AuIOErr(fmt, ##__VA_ARGS__); \
} while (0)
#define AuTraceErr(e) do { \
if (unlikely((e) < 0)) \
AuDbg("err %d\n", (int)(e)); \
......
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2017-2019 Junjiro R. Okajima
*/
/*
* helpers for hlist_bl.h
*/
#ifndef __AUFS_HBL_H__
#define __AUFS_HBL_H__
#ifdef __KERNEL__
#include <linux/list_bl.h>
static inline void au_hbl_add(struct hlist_bl_node *node,
struct hlist_bl_head *hbl)
{
hlist_bl_lock(hbl);
hlist_bl_add_head(node, hbl);
hlist_bl_unlock(hbl);
}
static inline void au_hbl_del(struct hlist_bl_node *node,
struct hlist_bl_head *hbl)
{
hlist_bl_lock(hbl);
hlist_bl_del(node);
hlist_bl_unlock(hbl);
}
#define au_hbl_for_each(pos, head) \
for (pos = hlist_bl_first(head); \
pos; \
pos = pos->next)
static inline unsigned long au_hbl_count(struct hlist_bl_head *hbl)
{
unsigned long cnt;
struct hlist_bl_node *pos;
cnt = 0;
hlist_bl_lock(hbl);
au_hbl_for_each(pos, hbl)
cnt++;
hlist_bl_unlock(hbl);
return cnt;
}
#endif /* __KERNEL__ */
#endif /* __AUFS_HBL_H__ */
......@@ -14,6 +14,24 @@
#include <linux/path.h>
/* ---------------------------------------------------------------------- */
/* mount flags */
#define AuOpt_XINO 1 /* external inode number bitmap
and translation table */
#define AuOpt_Def AuOpt_XINO
#define au_opt_test(flags, name) (flags & AuOpt_##name)
#define au_opt_set(flags, name) do { \
((flags) |= AuOpt_##name); \
} while (0)
#define au_opt_clr(flags, name) do { \
((flags) &= ~AuOpt_##name); \
} while (0)
/* ---------------------------------------------------------------------- */
struct au_opt_add {
aufs_bindex_t bindex;
char *pathname;
......
......@@ -42,6 +42,20 @@ struct au_sbinfo {
/* include/asm-ia64/siginfo.h defines a macro named si_flags */
unsigned int si_mntflags;
/* external inode number (bitmap and translation table) */
vfs_readf_t si_xread;
vfs_writef_t si_xwrite;
loff_t si_ximaxent; /* max entries in a xino */
struct file *si_xib;
struct mutex si_xib_mtx; /* protect xib members */
unsigned long *si_xib_buf;
unsigned long si_xib_last_pindex;
int si_xib_next_bit;
/* reserved for future use */
/* unsigned long long si_xib_limit; */ /* Max xib file size */
/*
* sysfs and lifetime management.
* this is not a small structure and it may be a waste of memory in case
......@@ -195,5 +209,11 @@ static inline struct au_branch *au_sbr(struct super_block *sb,
return au_sbi(sb)->si_branch[0 + bindex];
}
static inline loff_t au_xi_maxent(struct super_block *sb)
{
SiMustAnyLock(sb);
return au_sbi(sb)->si_ximaxent;
}
#endif /* __KERNEL__ */
#endif /* __AUFS_SUPER_H__ */
......@@ -8,8 +8,36 @@
*/
#include <linux/namei.h>
#include <linux/cred.h>
#include <linux/security.h>
#include "aufs.h"
struct file *vfsub_dentry_open(struct path *path, int flags)
{
struct file *file;
file = dentry_open(path, flags /* | __FMODE_NONOTIFY */,
current_cred());
if (!IS_ERR_OR_NULL(file)
&& (file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
i_readcount_inc(d_inode(path->dentry));
return file;
}
struct file *vfsub_filp_open(const char *path, int oflags, int mode)
{
struct file *file;
lockdep_off();
file = filp_open(path,
oflags /* | __FMODE_NONOTIFY */,
mode);
lockdep_on();
return file;
}
int vfsub_kern_path(const char *name, unsigned int flags, struct path *path)
{
int err;
......@@ -18,3 +46,96 @@ int vfsub_kern_path(const char *name, unsigned int flags, struct path *path)
/* add more later */
return err;
}
struct dentry *vfsub_lookup_one_len(const char *name, struct dentry *parent,
int len)
{
struct path path = {
.mnt = NULL
};
/* VFS checks it too, but by WARN_ON_ONCE() */
IMustLock(d_inode(parent));
path.dentry = lookup_one_len(name, parent, len);
if (IS_ERR(path.dentry))
goto out;
out:
AuTraceErrPtr(path.dentry);
return path.dentry;
}
/* ---------------------------------------------------------------------- */
struct unlink_args {
int *errp;
struct inode *dir;
struct path *path;
struct inode **delegated_inode;
};
static void call_unlink(void *args)
{
struct unlink_args *a = args;
struct dentry *d = a->path->dentry;
struct inode *h_inode;
/* re-commit later */
const int stop_sillyrename = 0; /* (au_test_nfs(d->d_sb)
* && au_dcount(d) == 1); */
IMustLock(a->dir);
a->path->dentry = d->d_parent;
*a->errp = security_path_unlink(a->path, d);
a->path->dentry = d;
if (unlikely(*a->errp))
return;
if (!stop_sillyrename)
dget(d);
h_inode = NULL;
if (d_is_positive(d)) {
h_inode = d_inode(d);
ihold(h_inode);
}
lockdep_off();
*a->errp = vfs_unlink(a->dir, d, a->delegated_inode);
lockdep_on();
if (!stop_sillyrename)
dput(d);
if (h_inode)
iput(h_inode);
AuTraceErr(*a->errp);
}
/*
* @dir: must be locked.
* @dentry: target dentry.
*/
int vfsub_unlink(struct inode *dir, struct path *path,
struct inode **delegated_inode, int force)
{
int err;
struct unlink_args args = {
.errp = &err,
.dir = dir,
.path = path,
.delegated_inode = delegated_inode
};
if (!force)
call_unlink(&args);
else {
int wkq_err;
wkq_err = au_wkq_wait(call_unlink, &args);
if (unlikely(wkq_err))
err = wkq_err;
}
return err;
}
......@@ -15,11 +15,45 @@
#include <linux/fs.h>
#include "debug.h"
/* ---------------------------------------------------------------------- */
/* lock subclass for lower inode */
/* default MAX_LOCKDEP_SUBCLASSES(8) is not enough */
/* reduce? gave up. */
enum {
AuLsc_I_Begin = I_MUTEX_PARENT2, /* 5 */
AuLsc_I_PARENT, /* lower inode, parent first */
AuLsc_I_PARENT2, /* copyup dirs */
AuLsc_I_PARENT3, /* copyup wh */
AuLsc_I_CHILD,
AuLsc_I_CHILD2,
AuLsc_I_End
};
/* to debug easier, do not make them inlined functions */
#define MtxMustLock(mtx) AuDebugOn(!mutex_is_locked(mtx))
#define IMustLock(i) AuDebugOn(!inode_is_locked(i))
/* ---------------------------------------------------------------------- */
struct file *vfsub_dentry_open(struct path *path, int flags);
struct file *vfsub_filp_open(const char *path, int oflags, int mode);
int vfsub_kern_path(const char *name, unsigned int flags, struct path *path);
struct dentry *vfsub_lookup_one_len(const char *name, struct dentry *parent,
int len);
/* ---------------------------------------------------------------------- */
static inline loff_t vfsub_f_size_read(struct file *file)
{
return i_size_read(file_inode(file));
}
/* ---------------------------------------------------------------------- */
int vfsub_unlink(struct inode *dir, struct path *path,
struct inode **delegated_inode, int force);
#endif /* __KERNEL__ */
#endif /* __AUFS_VFSUB_H__ */
......@@ -33,6 +33,7 @@ typedef void (*au_wkq_func_t)(void *args);
/* wkq flags */
#define AuWkq_WAIT 1
#define AuWkq_NEST (1 << 1)
#define au_ftest_wkq(flags, name) ((flags) & AuWkq_##name)
#define au_fset_wkq(flags, name) \
do { (flags) |= AuWkq_##name; } while (0)
......
This diff is collapsed.
......@@ -58,6 +58,9 @@ typedef int16_t aufs_bindex_t;
#define AUFS_FSTYPE AUFS_NAME
#define AUFS_ROOT_INO 2
#define AUFS_FIRST_INO 11
#define AUFS_WKQ_NAME AUFS_NAME "d"
/* branch permissions and attributes */
......
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