-+/* for s_op->delete_inode() */
-+void au_xino_delete_inode(struct inode *inode, const int unlinked)
-+{
-+ int err;
-+ unsigned int mnt_flags;
-+ aufs_bindex_t bindex, bbot, bi;
-+ unsigned char try_trunc;
-+ struct au_iinfo *iinfo;
-+ struct super_block *sb;
-+ struct au_hinode *hi;
-+ struct inode *h_inode;
-+ struct au_branch *br;
-+ vfs_writef_t xwrite;
-+
-+ AuDebugOn(au_is_bad_inode(inode));
-+
-+ sb = inode->i_sb;
-+ mnt_flags = au_mntflags(sb);
-+ if (!au_opt_test(mnt_flags, XINO)
-+ || inode->i_ino == AUFS_ROOT_INO)
-+ return;
-+
-+ if (unlinked) {
-+ au_xigen_inc(inode);
-+ au_xib_clear_bit(inode);
-+ }
-+
-+ iinfo = au_ii(inode);
-+ bindex = iinfo->ii_btop;
-+ if (bindex < 0)
-+ return;
-+
-+ xwrite = au_sbi(sb)->si_xwrite;
-+ try_trunc = !!au_opt_test(mnt_flags, TRUNC_XINO);
-+ hi = au_hinode(iinfo, bindex);
-+ bbot = iinfo->ii_bbot;
-+ for (; bindex <= bbot; bindex++, hi++) {
-+ h_inode = hi->hi_inode;
-+ if (!h_inode
-+ || (!unlinked && h_inode->i_nlink))
-+ continue;
-+
-+ /* inode may not be revalidated */
-+ bi = au_br_index(sb, hi->hi_id);
-+ if (bi < 0)
-+ continue;
-+
-+ br = au_sbr(sb, bi);
-+ err = au_xino_do_write(xwrite, br->br_xino.xi_file,
-+ h_inode->i_ino, /*ino*/0);
-+ if (!err && try_trunc
-+ && au_test_fs_trunc_xino(au_br_sb(br)))
-+ xino_try_trunc(sb, br);
-+ }
-+}
-+
-+/* get an unused inode number from bitmap */
-+ino_t au_xino_new_ino(struct super_block *sb)
-+{
-+ ino_t ino;
-+ unsigned long *p, pindex, ul, pend;
-+ struct au_sbinfo *sbinfo;
-+ struct file *file;
-+ int free_bit, err;
-+
-+ if (!au_opt_test(au_mntflags(sb), XINO))
-+ return iunique(sb, AUFS_FIRST_INO);
-+
-+ sbinfo = au_sbi(sb);
-+ mutex_lock(&sbinfo->si_xib_mtx);
-+ p = sbinfo->si_xib_buf;
-+ free_bit = sbinfo->si_xib_next_bit;
-+ if (free_bit < page_bits && !test_bit(free_bit, p))
-+ goto out; /* success */
-+ free_bit = find_first_zero_bit(p, page_bits);
-+ if (free_bit < page_bits)
-+ goto out; /* success */
-+
-+ pindex = sbinfo->si_xib_last_pindex;
-+ for (ul = pindex - 1; ul < ULONG_MAX; ul--) {
-+ err = xib_pindex(sb, ul);
-+ if (unlikely(err))
-+ goto out_err;
-+ free_bit = find_first_zero_bit(p, page_bits);
-+ if (free_bit < page_bits)
-+ goto out; /* success */
-+ }
-+
-+ file = sbinfo->si_xib;
-+ pend = vfsub_f_size_read(file) / PAGE_SIZE;
-+ for (ul = pindex + 1; ul <= pend; ul++) {
-+ err = xib_pindex(sb, ul);
-+ if (unlikely(err))
-+ goto out_err;
-+ free_bit = find_first_zero_bit(p, page_bits);
-+ if (free_bit < page_bits)
-+ goto out; /* success */
-+ }
-+ BUG();
-+
-+out:
-+ set_bit(free_bit, p);
-+ sbinfo->si_xib_next_bit = free_bit + 1;
-+ pindex = sbinfo->si_xib_last_pindex;
-+ mutex_unlock(&sbinfo->si_xib_mtx);
-+ ino = xib_calc_ino(pindex, free_bit);
-+ AuDbg("i%lu\n", (unsigned long)ino);
-+ return ino;
-+out_err:
-+ mutex_unlock(&sbinfo->si_xib_mtx);
-+ AuDbg("i0\n");
-+ return 0;
-+}
-+
-+/*
-+ * read @ino from xinofile for the specified branch{@sb, @bindex}
-+ * at the position of @h_ino.
-+ * if @ino does not exist and @do_new is true, get new one.
-+ */
-+int au_xino_read(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino,
-+ ino_t *ino)
-+{
-+ int err;
-+ ssize_t sz;
-+ loff_t pos;
-+ struct file *file;
-+ struct au_sbinfo *sbinfo;
-+
-+ *ino = 0;
-+ if (!au_opt_test(au_mntflags(sb), XINO))
-+ return 0; /* no xino */
-+
-+ err = 0;
-+ sbinfo = au_sbi(sb);
-+ pos = h_ino;
-+ if (unlikely(au_loff_max / sizeof(*ino) - 1 < pos)) {
-+ AuIOErr1("too large hi%lu\n", (unsigned long)h_ino);
-+ return -EFBIG;
-+ }
-+ pos *= sizeof(*ino);
-+
-+ file = au_sbr(sb, bindex)->br_xino.xi_file;
-+ if (vfsub_f_size_read(file) < pos + sizeof(*ino))
-+ return 0; /* no ino */
-+
-+ sz = xino_fread(sbinfo->si_xread, file, ino, sizeof(*ino), &pos);
-+ if (sz == sizeof(*ino))
-+ return 0; /* success */
-+
-+ err = sz;
-+ if (unlikely(sz >= 0)) {
-+ err = -EIO;
-+ AuIOErr("xino read error (%zd)\n", sz);
-+ }
-+
-+ return err;
-+}
-+
-+/* ---------------------------------------------------------------------- */
-+
-+/* create and set a new xino file */
-+
-+struct file *au_xino_create(struct super_block *sb, char *fname, int silent)
-+{
-+ struct file *file;
-+ struct dentry *h_parent, *d;
-+ struct inode *h_dir, *inode;
-+ int err;
-+
-+ /*
-+ * at mount-time, and the xino file is the default path,
-+ * hnotify is disabled so we have no notify events to ignore.
-+ * when a user specified the xino, we cannot get au_hdir to be ignored.
-+ */
-+ file = vfsub_filp_open(fname, O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE
-+ /* | __FMODE_NONOTIFY */,
-+ S_IRUGO | S_IWUGO);
-+ if (IS_ERR(file)) {
-+ if (!silent)
-+ pr_err("open %s(%ld)\n", fname, PTR_ERR(file));
-+ return file;
-+ }
-+
-+ /* keep file count */
-+ err = 0;
-+ inode = file_inode(file);
-+ h_parent = dget_parent(file->f_path.dentry);
-+ h_dir = d_inode(h_parent);
-+ inode_lock_nested(h_dir, AuLsc_I_PARENT);
-+ /* mnt_want_write() is unnecessary here */
-+ /* no delegation since it is just created */
-+ if (inode->i_nlink)
-+ err = vfsub_unlink(h_dir, &file->f_path, /*delegated*/NULL,
-+ /*force*/0);
-+ inode_unlock(h_dir);
-+ dput(h_parent);
-+ if (unlikely(err)) {
-+ if (!silent)
-+ pr_err("unlink %s(%d)\n", fname, err);
-+ goto out;
-+ }
-+
-+ err = -EINVAL;
-+ d = file->f_path.dentry;
-+ if (unlikely(sb == d->d_sb)) {
-+ if (!silent)
-+ pr_err("%s must be outside\n", fname);
-+ goto out;
-+ }
-+ if (unlikely(au_test_fs_bad_xino(d->d_sb))) {
-+ if (!silent)
-+ pr_err("xino doesn't support %s(%s)\n",
-+ fname, au_sbtype(d->d_sb));
-+ goto out;
-+ }
-+ return file; /* success */
-+
-+out:
-+ fput(file);
-+ file = ERR_PTR(err);
-+ return file;
-+}
-+
-+/*
-+ * find another branch who is on the same filesystem of the specified
-+ * branch{@btgt}. search until @bbot.
-+ */
-+static int is_sb_shared(struct super_block *sb, aufs_bindex_t btgt,
-+ aufs_bindex_t bbot)
-+{
-+ aufs_bindex_t bindex;
-+ struct super_block *tgt_sb = au_sbr_sb(sb, btgt);
-+
-+ for (bindex = 0; bindex < btgt; bindex++)
-+ if (unlikely(tgt_sb == au_sbr_sb(sb, bindex)))
-+ return bindex;
-+ for (bindex++; bindex <= bbot; bindex++)
-+ if (unlikely(tgt_sb == au_sbr_sb(sb, bindex)))
-+ return bindex;
-+ return -1;
-+}
-+