summaryrefslogtreecommitdiff
path: root/fs/aufs/inode.c
diff options
context:
space:
mode:
authorAndré Fabian Silva Delgado <emulatorman@parabola.nu>2015-09-08 01:01:14 -0300
committerAndré Fabian Silva Delgado <emulatorman@parabola.nu>2015-09-08 01:01:14 -0300
commite5fd91f1ef340da553f7a79da9540c3db711c937 (patch)
treeb11842027dc6641da63f4bcc524f8678263304a3 /fs/aufs/inode.c
parent2a9b0348e685a63d97486f6749622b61e9e3292f (diff)
Linux-libre 4.2-gnu
Diffstat (limited to 'fs/aufs/inode.c')
-rw-r--r--fs/aufs/inode.c500
1 files changed, 0 insertions, 500 deletions
diff --git a/fs/aufs/inode.c b/fs/aufs/inode.c
deleted file mode 100644
index 201e112a0..000000000
--- a/fs/aufs/inode.c
+++ /dev/null
@@ -1,500 +0,0 @@
-/*
- * Copyright (C) 2005-2015 Junjiro R. Okajima
- *
- * This program, aufs is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * inode functions
- */
-
-#include "aufs.h"
-
-struct inode *au_igrab(struct inode *inode)
-{
- if (inode) {
- AuDebugOn(!atomic_read(&inode->i_count));
- ihold(inode);
- }
- return inode;
-}
-
-static void au_refresh_hinode_attr(struct inode *inode, int do_version)
-{
- au_cpup_attr_all(inode, /*force*/0);
- au_update_iigen(inode, /*half*/1);
- if (do_version)
- inode->i_version++;
-}
-
-static int au_ii_refresh(struct inode *inode, int *update)
-{
- int err, e;
- umode_t type;
- aufs_bindex_t bindex, new_bindex;
- struct super_block *sb;
- struct au_iinfo *iinfo;
- struct au_hinode *p, *q, tmp;
-
- IiMustWriteLock(inode);
-
- *update = 0;
- sb = inode->i_sb;
- type = inode->i_mode & S_IFMT;
- iinfo = au_ii(inode);
- err = au_ii_realloc(iinfo, au_sbend(sb) + 1);
- if (unlikely(err))
- goto out;
-
- AuDebugOn(iinfo->ii_bstart < 0);
- p = iinfo->ii_hinode + iinfo->ii_bstart;
- for (bindex = iinfo->ii_bstart; bindex <= iinfo->ii_bend;
- bindex++, p++) {
- if (!p->hi_inode)
- continue;
-
- AuDebugOn(type != (p->hi_inode->i_mode & S_IFMT));
- new_bindex = au_br_index(sb, p->hi_id);
- if (new_bindex == bindex)
- continue;
-
- if (new_bindex < 0) {
- *update = 1;
- au_hiput(p);
- p->hi_inode = NULL;
- continue;
- }
-
- if (new_bindex < iinfo->ii_bstart)
- iinfo->ii_bstart = new_bindex;
- if (iinfo->ii_bend < new_bindex)
- iinfo->ii_bend = new_bindex;
- /* swap two lower inode, and loop again */
- q = iinfo->ii_hinode + new_bindex;
- tmp = *q;
- *q = *p;
- *p = tmp;
- if (tmp.hi_inode) {
- bindex--;
- p--;
- }
- }
- au_update_ibrange(inode, /*do_put_zero*/0);
- e = au_dy_irefresh(inode);
- if (unlikely(e && !err))
- err = e;
-
-out:
- AuTraceErr(err);
- return err;
-}
-
-int au_refresh_hinode_self(struct inode *inode)
-{
- int err, update;
-
- err = au_ii_refresh(inode, &update);
- if (!err)
- au_refresh_hinode_attr(inode, update && S_ISDIR(inode->i_mode));
-
- AuTraceErr(err);
- return err;
-}
-
-int au_refresh_hinode(struct inode *inode, struct dentry *dentry)
-{
- int err, e, update;
- unsigned int flags;
- umode_t mode;
- aufs_bindex_t bindex, bend;
- unsigned char isdir;
- struct au_hinode *p;
- struct au_iinfo *iinfo;
-
- err = au_ii_refresh(inode, &update);
- if (unlikely(err))
- goto out;
-
- update = 0;
- iinfo = au_ii(inode);
- p = iinfo->ii_hinode + iinfo->ii_bstart;
- mode = (inode->i_mode & S_IFMT);
- isdir = S_ISDIR(mode);
- flags = au_hi_flags(inode, isdir);
- bend = au_dbend(dentry);
- for (bindex = au_dbstart(dentry); bindex <= bend; bindex++) {
- struct inode *h_i, *h_inode;
- struct dentry *h_d;
-
- h_d = au_h_dptr(dentry, bindex);
- if (!h_d || d_is_negative(h_d))
- continue;
-
- h_inode = d_inode(h_d);
- AuDebugOn(mode != (h_inode->i_mode & S_IFMT));
- if (iinfo->ii_bstart <= bindex && bindex <= iinfo->ii_bend) {
- h_i = au_h_iptr(inode, bindex);
- if (h_i) {
- if (h_i == h_inode)
- continue;
- err = -EIO;
- break;
- }
- }
- if (bindex < iinfo->ii_bstart)
- iinfo->ii_bstart = bindex;
- if (iinfo->ii_bend < bindex)
- iinfo->ii_bend = bindex;
- au_set_h_iptr(inode, bindex, au_igrab(h_inode), flags);
- update = 1;
- }
- au_update_ibrange(inode, /*do_put_zero*/0);
- e = au_dy_irefresh(inode);
- if (unlikely(e && !err))
- err = e;
- if (!err)
- au_refresh_hinode_attr(inode, update && isdir);
-
-out:
- AuTraceErr(err);
- return err;
-}
-
-static int set_inode(struct inode *inode, struct dentry *dentry)
-{
- int err;
- unsigned int flags;
- umode_t mode;
- aufs_bindex_t bindex, bstart, btail;
- unsigned char isdir;
- struct dentry *h_dentry;
- struct inode *h_inode;
- struct au_iinfo *iinfo;
-
- IiMustWriteLock(inode);
-
- err = 0;
- isdir = 0;
- bstart = au_dbstart(dentry);
- h_dentry = au_h_dptr(dentry, bstart);
- h_inode = d_inode(h_dentry);
- mode = h_inode->i_mode;
- switch (mode & S_IFMT) {
- case S_IFREG:
- btail = au_dbtail(dentry);
- inode->i_op = &aufs_iop;
- inode->i_fop = &aufs_file_fop;
- err = au_dy_iaop(inode, bstart, h_inode);
- if (unlikely(err))
- goto out;
- break;
- case S_IFDIR:
- isdir = 1;
- btail = au_dbtaildir(dentry);
- inode->i_op = &aufs_dir_iop;
- inode->i_fop = &aufs_dir_fop;
- break;
- case S_IFLNK:
- btail = au_dbtail(dentry);
- inode->i_op = &aufs_symlink_iop;
- break;
- case S_IFBLK:
- case S_IFCHR:
- case S_IFIFO:
- case S_IFSOCK:
- btail = au_dbtail(dentry);
- inode->i_op = &aufs_iop;
- init_special_inode(inode, mode, h_inode->i_rdev);
- break;
- default:
- AuIOErr("Unknown file type 0%o\n", mode);
- err = -EIO;
- goto out;
- }
-
- /* do not set hnotify for whiteouted dirs (SHWH mode) */
- flags = au_hi_flags(inode, isdir);
- if (au_opt_test(au_mntflags(dentry->d_sb), SHWH)
- && au_ftest_hi(flags, HNOTIFY)
- && dentry->d_name.len > AUFS_WH_PFX_LEN
- && !memcmp(dentry->d_name.name, AUFS_WH_PFX, AUFS_WH_PFX_LEN))
- au_fclr_hi(flags, HNOTIFY);
- iinfo = au_ii(inode);
- iinfo->ii_bstart = bstart;
- iinfo->ii_bend = btail;
- for (bindex = bstart; bindex <= btail; bindex++) {
- h_dentry = au_h_dptr(dentry, bindex);
- if (h_dentry)
- au_set_h_iptr(inode, bindex,
- au_igrab(d_inode(h_dentry)), flags);
- }
- au_cpup_attr_all(inode, /*force*/1);
- /*
- * to force calling aufs_get_acl() every time,
- * do not call cache_no_acl() for aufs inode.
- */
-
-out:
- return err;
-}
-
-/*
- * successful returns with iinfo write_locked
- * minus: errno
- * zero: success, matched
- * plus: no error, but unmatched
- */
-static int reval_inode(struct inode *inode, struct dentry *dentry)
-{
- int err;
- unsigned int gen;
- struct au_iigen iigen;
- aufs_bindex_t bindex, bend;
- struct inode *h_inode, *h_dinode;
- struct dentry *h_dentry;
-
- /*
- * before this function, if aufs got any iinfo lock, it must be only
- * one, the parent dir.
- * it can happen by UDBA and the obsoleted inode number.
- */
- err = -EIO;
- if (unlikely(inode->i_ino == parent_ino(dentry)))
- goto out;
-
- err = 1;
- ii_write_lock_new_child(inode);
- h_dentry = au_h_dptr(dentry, au_dbstart(dentry));
- h_dinode = d_inode(h_dentry);
- bend = au_ibend(inode);
- for (bindex = au_ibstart(inode); bindex <= bend; bindex++) {
- h_inode = au_h_iptr(inode, bindex);
- if (!h_inode || h_inode != h_dinode)
- continue;
-
- err = 0;
- gen = au_iigen(inode, &iigen);
- if (gen == au_digen(dentry)
- && !au_ig_ftest(iigen.ig_flags, HALF_REFRESHED))
- break;
-
- /* fully refresh inode using dentry */
- err = au_refresh_hinode(inode, dentry);
- if (!err)
- au_update_iigen(inode, /*half*/0);
- break;
- }
-
- if (unlikely(err))
- ii_write_unlock(inode);
-out:
- return err;
-}
-
-int au_ino(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino,
- unsigned int d_type, ino_t *ino)
-{
- int err;
- struct mutex *mtx;
-
- /* prevent hardlinked inode number from race condition */
- mtx = NULL;
- if (d_type != DT_DIR) {
- mtx = &au_sbr(sb, bindex)->br_xino.xi_nondir_mtx;
- mutex_lock(mtx);
- }
- err = au_xino_read(sb, bindex, h_ino, ino);
- if (unlikely(err))
- goto out;
-
- if (!*ino) {
- err = -EIO;
- *ino = au_xino_new_ino(sb);
- if (unlikely(!*ino))
- goto out;
- err = au_xino_write(sb, bindex, h_ino, *ino);
- if (unlikely(err))
- goto out;
- }
-
-out:
- if (mtx)
- mutex_unlock(mtx);
- return err;
-}
-
-/* successful returns with iinfo write_locked */
-/* todo: return with unlocked? */
-struct inode *au_new_inode(struct dentry *dentry, int must_new)
-{
- struct inode *inode, *h_inode;
- struct dentry *h_dentry;
- struct super_block *sb;
- struct mutex *mtx;
- ino_t h_ino, ino;
- int err;
- aufs_bindex_t bstart;
-
- sb = dentry->d_sb;
- bstart = au_dbstart(dentry);
- h_dentry = au_h_dptr(dentry, bstart);
- h_inode = d_inode(h_dentry);
- h_ino = h_inode->i_ino;
-
- /*
- * stop 'race'-ing between hardlinks under different
- * parents.
- */
- mtx = NULL;
- if (!d_is_dir(h_dentry))
- mtx = &au_sbr(sb, bstart)->br_xino.xi_nondir_mtx;
-
-new_ino:
- if (mtx)
- mutex_lock(mtx);
- err = au_xino_read(sb, bstart, h_ino, &ino);
- inode = ERR_PTR(err);
- if (unlikely(err))
- goto out;
-
- if (!ino) {
- ino = au_xino_new_ino(sb);
- if (unlikely(!ino)) {
- inode = ERR_PTR(-EIO);
- goto out;
- }
- }
-
- AuDbg("i%lu\n", (unsigned long)ino);
- inode = au_iget_locked(sb, ino);
- err = PTR_ERR(inode);
- if (IS_ERR(inode))
- goto out;
-
- AuDbg("%lx, new %d\n", inode->i_state, !!(inode->i_state & I_NEW));
- if (inode->i_state & I_NEW) {
- /* verbose coding for lock class name */
- if (unlikely(d_is_symlink(h_dentry)))
- au_rw_class(&au_ii(inode)->ii_rwsem,
- au_lc_key + AuLcSymlink_IIINFO);
- else if (unlikely(d_is_dir(h_dentry)))
- au_rw_class(&au_ii(inode)->ii_rwsem,
- au_lc_key + AuLcDir_IIINFO);
- else /* likely */
- au_rw_class(&au_ii(inode)->ii_rwsem,
- au_lc_key + AuLcNonDir_IIINFO);
-
- ii_write_lock_new_child(inode);
- err = set_inode(inode, dentry);
- if (!err) {
- unlock_new_inode(inode);
- goto out; /* success */
- }
-
- /*
- * iget_failed() calls iput(), but we need to call
- * ii_write_unlock() after iget_failed(). so dirty hack for
- * i_count.
- */
- atomic_inc(&inode->i_count);
- iget_failed(inode);
- ii_write_unlock(inode);
- au_xino_write(sb, bstart, h_ino, /*ino*/0);
- /* ignore this error */
- goto out_iput;
- } else if (!must_new && !IS_DEADDIR(inode) && inode->i_nlink) {
- /*
- * horrible race condition between lookup, readdir and copyup
- * (or something).
- */
- if (mtx)
- mutex_unlock(mtx);
- err = reval_inode(inode, dentry);
- if (unlikely(err < 0)) {
- mtx = NULL;
- goto out_iput;
- }
-
- if (!err) {
- mtx = NULL;
- goto out; /* success */
- } else if (mtx)
- mutex_lock(mtx);
- }
-
- if (unlikely(au_test_fs_unique_ino(h_inode)))
- AuWarn1("Warning: Un-notified UDBA or repeatedly renamed dir,"
- " b%d, %s, %pd, hi%lu, i%lu.\n",
- bstart, au_sbtype(h_dentry->d_sb), dentry,
- (unsigned long)h_ino, (unsigned long)ino);
- ino = 0;
- err = au_xino_write(sb, bstart, h_ino, /*ino*/0);
- if (!err) {
- iput(inode);
- if (mtx)
- mutex_unlock(mtx);
- goto new_ino;
- }
-
-out_iput:
- iput(inode);
- inode = ERR_PTR(err);
-out:
- if (mtx)
- mutex_unlock(mtx);
- return inode;
-}
-
-/* ---------------------------------------------------------------------- */
-
-int au_test_ro(struct super_block *sb, aufs_bindex_t bindex,
- struct inode *inode)
-{
- int err;
- struct inode *hi;
-
- err = au_br_rdonly(au_sbr(sb, bindex));
-
- /* pseudo-link after flushed may happen out of bounds */
- if (!err
- && inode
- && au_ibstart(inode) <= bindex
- && bindex <= au_ibend(inode)) {
- /*
- * permission check is unnecessary since vfsub routine
- * will be called later
- */
- hi = au_h_iptr(inode, bindex);
- if (hi)
- err = IS_IMMUTABLE(hi) ? -EROFS : 0;
- }
-
- return err;
-}
-
-int au_test_h_perm(struct inode *h_inode, int mask)
-{
- if (uid_eq(current_fsuid(), GLOBAL_ROOT_UID))
- return 0;
- return inode_permission(h_inode, mask);
-}
-
-int au_test_h_perm_sio(struct inode *h_inode, int mask)
-{
- if (au_test_nfs(h_inode->i_sb)
- && (mask & MAY_WRITE)
- && S_ISDIR(h_inode->i_mode))
- mask |= MAY_READ; /* force permission check */
- return au_test_h_perm(h_inode, mask);
-}