Commit 2a7e7277 authored by J. R. Okajima's avatar J. R. Okajima
Browse files

aufs: white-out 1/2



The whiteout represents a logical deletion.
Although the document in this commit mentioned about rmdir(2) and
rename(2) for dir, this commit doesn't contain such functions. They will
be added in later commits.
Signed-off-by: default avatarJ. R. Okajima <hooanon05g@gmail.com>
parent 2a150b32
...@@ -129,3 +129,27 @@ whiteout base and etc. This is unrelated to a privilege. ...@@ -129,3 +129,27 @@ whiteout base and etc. This is unrelated to a privilege.
Most of aufs operation tries acquiring a rw_semaphore for aufs Most of aufs operation tries acquiring a rw_semaphore for aufs
superblock at the beginning, at the same time waits for the completion superblock at the beginning, at the same time waits for the completion
of all queued asynchronous tasks. of all queued asynchronous tasks.
Whiteout
----------------------------------------------------------------------
The whiteout in aufs is very similar to Unionfs's. That is represented
by its filename. UnionMount takes an approach of a file mode, but I am
afraid several utilities (find(1) or something) will have to support it.
Basically the whiteout represents "logical deletion" which stops aufs to
lookup further, but also it represents "dir is opaque" which also stop
further lookup.
In aufs, rmdir(2) and rename(2) for dir uses whiteout alternatively.
In order to make several functions in a single systemcall to be
revertible, aufs adopts an approach to rename a directory to a temporary
unique whiteouted name.
For example, in rename(2) dir where the target dir already existed, aufs
renames the target dir to a temporary unique whiteouted name before the
actual rename on a branch, and then handles other actions (make it opaque,
update the attributes, etc). If an error happens in these actions, aufs
simply renames the whiteouted name back and returns an error. If all are
succeeded, aufs registers a function to remove the whiteouted unique
temporary name completely and asynchronously to the system global
workqueue.
...@@ -12,7 +12,7 @@ ccflags-y += -include ${srctree}/include/uapi/linux/aufs_type.h ...@@ -12,7 +12,7 @@ ccflags-y += -include ${srctree}/include/uapi/linux/aufs_type.h
obj-$(CONFIG_AUFS_FS) += aufs.o obj-$(CONFIG_AUFS_FS) += aufs.o
aufs-y := module.o sbinfo.o super.o branch.o xino.o sysaufs.o opts.o \ aufs-y := module.o sbinfo.o super.o branch.o xino.o sysaufs.o opts.o \
wkq.o vfsub.o dcsub.o \ wkq.o vfsub.o dcsub.o \
cpup.o \ cpup.o whout.o \
dinfo.o \ dinfo.o \
iinfo.o inode.o iinfo.o inode.o
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include "super.h" #include "super.h"
#include "sysaufs.h" #include "sysaufs.h"
#include "vfsub.h" #include "vfsub.h"
#include "whout.h"
#include "wkq.h" #include "wkq.h"
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
......
...@@ -138,9 +138,9 @@ void au_dpri_dentry(struct dentry *dentry) ...@@ -138,9 +138,9 @@ void au_dpri_dentry(struct dentry *dentry)
dinfo = au_di(dentry); dinfo = au_di(dentry);
if (!dinfo) if (!dinfo)
return; return;
dpri("d-1: btop %d, bbot %d, gen %d\n", dpri("d-1: btop %d, bbot %d, bwh %d, gen %d\n",
dinfo->di_btop, dinfo->di_bbot, dinfo->di_btop, dinfo->di_bbot,
au_digen(dentry)); dinfo->di_bwh, au_digen(dentry));
if (dinfo->di_btop < 0) if (dinfo->di_btop < 0)
return; return;
for (bindex = dinfo->di_btop; bindex <= dinfo->di_bbot; bindex++) for (bindex = dinfo->di_btop; bindex <= dinfo->di_bbot; bindex++)
......
...@@ -24,7 +24,7 @@ struct au_dinfo { ...@@ -24,7 +24,7 @@ struct au_dinfo {
atomic_t di_generation; atomic_t di_generation;
struct au_rwsem di_rwsem; struct au_rwsem di_rwsem;
aufs_bindex_t di_btop, di_bbot; aufs_bindex_t di_btop, di_bbot, di_bwh;
struct au_hdentry *di_hdentry; struct au_hdentry *di_hdentry;
struct rcu_head rcu; struct rcu_head rcu;
} ____cacheline_aligned_in_smp; } ____cacheline_aligned_in_smp;
...@@ -147,6 +147,12 @@ static inline aufs_bindex_t au_dbbot(struct dentry *dentry) ...@@ -147,6 +147,12 @@ static inline aufs_bindex_t au_dbbot(struct dentry *dentry)
return au_di(dentry)->di_bbot; return au_di(dentry)->di_bbot;
} }
static inline aufs_bindex_t au_dbwh(struct dentry *dentry)
{
DiMustAnyLock(dentry);
return au_di(dentry)->di_bwh;
}
/* todo: hard/soft set? */ /* todo: hard/soft set? */
static inline void au_set_dbtop(struct dentry *dentry, aufs_bindex_t bindex) static inline void au_set_dbtop(struct dentry *dentry, aufs_bindex_t bindex)
{ {
...@@ -160,5 +166,12 @@ static inline void au_set_dbbot(struct dentry *dentry, aufs_bindex_t bindex) ...@@ -160,5 +166,12 @@ static inline void au_set_dbbot(struct dentry *dentry, aufs_bindex_t bindex)
au_di(dentry)->di_bbot = bindex; au_di(dentry)->di_bbot = bindex;
} }
static inline void au_set_dbwh(struct dentry *dentry, aufs_bindex_t bindex)
{
DiMustWriteLock(dentry);
/* dbwh can be outside of btop - bbot range */
au_di(dentry)->di_bwh = bindex;
}
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* __AUFS_DENTRY_H__ */ #endif /* __AUFS_DENTRY_H__ */
...@@ -33,6 +33,7 @@ struct au_dinfo *au_di_alloc(struct super_block *sb, unsigned int lsc) ...@@ -33,6 +33,7 @@ struct au_dinfo *au_di_alloc(struct super_block *sb, unsigned int lsc)
au_rw_write_lock_nested(&dinfo->di_rwsem, lsc); au_rw_write_lock_nested(&dinfo->di_rwsem, lsc);
dinfo->di_btop = -1; dinfo->di_btop = -1;
dinfo->di_bbot = -1; dinfo->di_bbot = -1;
dinfo->di_bwh = -1;
for (i = 0; i < nbr; i++) for (i = 0; i < nbr; i++)
dinfo->di_hdentry[i].hd_id = -1; dinfo->di_hdentry[i].hd_id = -1;
goto out; goto out;
......
...@@ -43,6 +43,12 @@ int vfsub_kern_path(const char *name, unsigned int flags, struct path *path); ...@@ -43,6 +43,12 @@ 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, struct dentry *vfsub_lookup_one_len(const char *name, struct dentry *parent,
int len); int len);
static inline struct dentry *vfsub_lkup_one(struct qstr *name,
struct dentry *parent)
{
return vfsub_lookup_one_len(name->name, parent, name->len);
}
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
static inline loff_t vfsub_f_size_read(struct file *file) static inline loff_t vfsub_f_size_read(struct file *file)
......
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2005-2019 Junjiro R. Okajima
*/
/*
* whiteout for logical deletion and opaque directory
*/
#include "aufs.h"
#define WH_MASK 0444
/*
* generate whiteout name, which is NOT terminated by NULL.
* @name: original d_name.name
* @len: original d_name.len
* @wh: whiteout qstr
* returns zero when succeeds, otherwise error.
* succeeded value as wh->name should be freed by kfree().
*/
int au_wh_name_alloc(struct qstr *wh, const struct qstr *name)
{
char *p;
if (unlikely(name->len > PATH_MAX - AUFS_WH_PFX_LEN))
return -ENAMETOOLONG;
wh->len = name->len + AUFS_WH_PFX_LEN;
p = kmalloc(wh->len, GFP_NOFS);
wh->name = p;
if (p) {
memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN);
memcpy(p + AUFS_WH_PFX_LEN, name->name, name->len);
/* smp_mb(); */
return 0;
}
return -ENOMEM;
}
/* ---------------------------------------------------------------------- */
/*
* test if the @wh_name exists under @h_parent.
* @try_sio specifies the necessary of super-io.
*/
int au_wh_test(struct dentry *h_parent, struct qstr *wh_name, int try_sio)
{
int err;
struct dentry *wh_dentry;
#if 0 /* re-commit later */
if (!try_sio)
wh_dentry = vfsub_lkup_one(wh_name, h_parent);
else
wh_dentry = au_sio_lkup_one(wh_name, h_parent);
#else
wh_dentry = ERR_PTR(-ENOENT);
#endif
err = PTR_ERR(wh_dentry);
if (IS_ERR(wh_dentry)) {
if (err == -ENAMETOOLONG)
err = 0;
goto out;
}
err = 0;
if (d_is_negative(wh_dentry))
goto out_wh; /* success */
err = 1;
if (d_is_reg(wh_dentry))
goto out_wh; /* success */
err = -EIO;
AuIOErr("%pd Invalid whiteout entry type 0%o.\n",
wh_dentry, d_inode(wh_dentry)->i_mode);
out_wh:
dput(wh_dentry);
out:
return err;
}
/* ---------------------------------------------------------------------- */
/*
* lookup whiteout dentry.
* @h_parent: lower parent dentry which must exist and be locked
* @base_name: name of dentry which will be whiteouted
* returns dentry for whiteout.
*/
struct dentry *au_wh_lkup(struct dentry *h_parent, struct qstr *base_name,
struct au_branch *br)
{
int err;
struct qstr wh_name;
struct dentry *wh_dentry;
err = au_wh_name_alloc(&wh_name, base_name);
wh_dentry = ERR_PTR(err);
if (!err) {
wh_dentry = vfsub_lkup_one(&wh_name, h_parent);
au_kfree_try_rcu(wh_name.name);
}
return wh_dentry;
}
/*
* link/create a whiteout for @dentry on @bindex.
*/
struct dentry *au_wh_create(struct dentry *dentry, aufs_bindex_t bindex,
struct dentry *h_parent)
{
struct dentry *wh_dentry;
struct super_block *sb;
int err;
sb = dentry->d_sb;
wh_dentry = au_wh_lkup(h_parent, &dentry->d_name, au_sbr(sb, bindex));
if (!IS_ERR(wh_dentry) && d_is_negative(wh_dentry)) {
/* err = link_or_create_wh(sb, bindex, wh_dentry); re-commit later */
err = 0;
if (!err)
au_set_dbwh(dentry, bindex);
else {
dput(wh_dentry);
wh_dentry = ERR_PTR(err);
}
}
return wh_dentry;
}
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2005-2019 Junjiro R. Okajima
*/
/*
* whiteout for logical deletion and opaque directory
*/
#ifndef __AUFS_WHOUT_H__
#define __AUFS_WHOUT_H__
#ifdef __KERNEL__
/* whout.c */
struct qstr;
int au_wh_name_alloc(struct qstr *wh, const struct qstr *name);
struct dentry;
int au_wh_test(struct dentry *h_parent, struct qstr *wh_name, int try_sio);
struct au_branch;
struct dentry *au_wh_lkup(struct dentry *h_parent, struct qstr *base_name,
struct au_branch *br);
struct dentry *au_wh_create(struct dentry *dentry, aufs_bindex_t bindex,
struct dentry *h_parent);
#endif /* __KERNEL__ */
#endif /* __AUFS_WHOUT_H__ */
...@@ -61,6 +61,9 @@ typedef int16_t aufs_bindex_t; ...@@ -61,6 +61,9 @@ typedef int16_t aufs_bindex_t;
#define AUFS_ROOT_INO 2 #define AUFS_ROOT_INO 2
#define AUFS_FIRST_INO 11 #define AUFS_FIRST_INO 11
#define AUFS_WH_PFX ".wh."
#define AUFS_WH_PFX_LEN ((int)sizeof(AUFS_WH_PFX) - 1)
#define AUFS_WH_TMP_LEN 4
#define AUFS_XINO_FNAME "." AUFS_NAME ".xino" #define AUFS_XINO_FNAME "." AUFS_NAME ".xino"
#define AUFS_XINO_DEFPATH "/tmp/" AUFS_XINO_FNAME #define AUFS_XINO_DEFPATH "/tmp/" AUFS_XINO_FNAME
#define AUFS_XINO_DEF_SEC 30 /* seconds */ #define AUFS_XINO_DEF_SEC 30 /* seconds */
......
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