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

aufs: export via NFS 2/2



The main part is in previous commit.
This commit handles the generation of aufs objects, to make sure the
inode in the file handle is still valid.
In order not to confuse NFSD, the various operation returns ESTALE for
NFSD where it used to return EBUSY.

See also the document in this commit.
Signed-off-by: default avatarJ. R. Okajima <hooanon05g@gmail.com>
parent c470ddd6
# Copyright (C) 2005-2019 Junjiro R. Okajima
Export Aufs via NFS
----------------------------------------------------------------------
Here is an approach.
- like xino/xib, add a new file 'xigen' which stores aufs inode
generation.
- iget_locked(): initialize aufs inode generation for a new inode, and
store it in xigen file.
- destroy_inode(): increment aufs inode generation and store it in xigen
file. it is necessary even if it is not unlinked, because any data of
inode may be changed by UDBA.
- encode_fh(): for a root dir, simply return FILEID_ROOT. otherwise
build file handle by
+ branch id (4 bytes)
+ superblock generation (4 bytes)
+ inode number (4 or 8 bytes)
+ parent dir inode number (4 or 8 bytes)
+ inode generation (4 bytes))
+ return value of exportfs_encode_fh() for the parent on a branch (4
bytes)
+ file handle for a branch (by exportfs_encode_fh())
- fh_to_dentry():
+ find the index of a branch from its id in handle, and check it is
still exist in aufs.
+ 1st level: get the inode number from handle and search it in cache.
+ 2nd level: if not found in cache, get the parent inode number from
the handle and search it in cache. and then open the found parent
dir, find the matching inode number by vfs_readdir() and get its
name, and call lookup_one_len() for the target dentry.
+ 3rd level: if the parent dir is not cached, call
exportfs_decode_fh() for a branch and get the parent on a branch,
build a pathname of it, convert it a pathname in aufs, call
path_lookup(). now aufs gets a parent dir dentry, then handle it as
the 2nd level.
+ to open the dir, aufs needs struct vfsmount. aufs keeps vfsmount
for every branch, but not itself. to get this, (currently) aufs
searches in current->nsproxy->mnt_ns list. it may not be a good
idea, but I didn't get other approach.
+ test the generation of the gotten inode.
- every inode operation: they may get EBUSY due to UDBA. in this case,
convert it into ESTALE for NFSD.
- readdir(): call lockdep_on/off() because filldir in NFSD calls
lookup_one_len(), vfs_getattr(), encode_fh() and others.
...@@ -319,7 +319,7 @@ static int au_h_verify_dentry(struct dentry *h_dentry, struct dentry *h_parent, ...@@ -319,7 +319,7 @@ static int au_h_verify_dentry(struct dentry *h_dentry, struct dentry *h_parent,
if (unlikely(h_d != h_dentry if (unlikely(h_d != h_dentry
|| d_inode(h_d) != h_inode || d_inode(h_d) != h_inode
|| (h_inode && au_iattr_test(&ia, h_inode)))) || (h_inode && au_iattr_test(&ia, h_inode))))
err = -EBUSY; err = au_busy_or_stale();
dput(h_d); dput(h_d);
out: out:
......
...@@ -37,7 +37,7 @@ struct file *au_h_open(struct dentry *dentry, aufs_bindex_t bindex, int flags, ...@@ -37,7 +37,7 @@ struct file *au_h_open(struct dentry *dentry, aufs_bindex_t bindex, int flags,
/* a race condition can happen between open and unlink/rmdir */ /* a race condition can happen between open and unlink/rmdir */
h_file = ERR_PTR(-ENOENT); h_file = ERR_PTR(-ENOENT);
h_dentry = au_h_dptr(dentry, bindex); h_dentry = au_h_dptr(dentry, bindex);
if (!h_dentry || d_is_negative(h_dentry)) if (au_test_nfsd() && (!h_dentry || d_is_negative(h_dentry)))
goto out; goto out;
h_inode = d_inode(h_dentry); h_inode = d_inode(h_dentry);
spin_lock(&h_dentry->d_lock); spin_lock(&h_dentry->d_lock);
......
...@@ -186,7 +186,7 @@ int au_do_pin(struct au_pin *p) ...@@ -186,7 +186,7 @@ int au_do_pin(struct au_pin *p)
out_err: out_err:
pr_err("err %d\n", err); pr_err("err %d\n", err);
err = -EBUSY; err = au_busy_or_stale();
out: out:
return err; return err;
} }
......
...@@ -55,7 +55,9 @@ struct inode *au_iget_locked(struct super_block *sb, ino_t ino) ...@@ -55,7 +55,9 @@ struct inode *au_iget_locked(struct super_block *sb, ino_t ino)
if (!(inode->i_state & I_NEW)) if (!(inode->i_state & I_NEW))
goto out; goto out;
err = au_iinfo_init(inode); err = au_xigen_new(inode);
if (!err)
err = au_iinfo_init(inode);
if (!err) if (!err)
inode_inc_iversion(inode); inode_inc_iversion(inode);
else { else {
......
...@@ -1557,6 +1557,7 @@ void au_xino_clr(struct super_block *sb) ...@@ -1557,6 +1557,7 @@ void au_xino_clr(struct super_block *sb)
{ {
struct au_sbinfo *sbinfo; struct au_sbinfo *sbinfo;
au_xigen_clr(sb);
xino_clear_xib(sb); xino_clear_xib(sb);
xino_clear_br(sb); xino_clear_br(sb);
sbinfo = au_sbi(sb); sbinfo = au_sbi(sb);
...@@ -1581,6 +1582,8 @@ int au_xino_set(struct super_block *sb, struct au_opt_xino *xiopt) ...@@ -1581,6 +1582,8 @@ int au_xino_set(struct super_block *sb, struct au_opt_xino *xiopt)
au_opt_set(sbinfo->si_mntflags, XINO); au_opt_set(sbinfo->si_mntflags, XINO);
err = au_xino_set_xib(sb, path); err = au_xino_set_xib(sb, path);
/* si_x{read,write} are set */ /* si_x{read,write} are set */
if (!err)
err = au_xigen_set(sb, path);
if (!err) if (!err)
err = au_xino_set_br(sb, path); err = au_xino_set_br(sb, path);
if (!err) if (!err)
......
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