static int do_open_dir(struct file *file, int flags) { int err; aufs_bindex_t bindex, btail; struct dentry *dentry, *h_dentry; struct file *h_file; FiMustWriteLock(file); err = 0; dentry = file->f_dentry; file->f_version = dentry->d_inode->i_version; bindex = au_dbstart(dentry); au_set_fbstart(file, bindex); btail = au_dbtaildir(dentry); au_set_fbend_dir(file, btail); for (; !err && bindex <= btail; bindex++) { h_dentry = au_h_dptr(dentry, bindex); if (!h_dentry) continue; h_file = au_h_open(dentry, bindex, flags, file); if (IS_ERR(h_file)) { err = PTR_ERR(h_file); break; } au_set_h_fptr(file, bindex, h_file); } au_update_figen(file); /* todo: necessary? */ /* file->f_ra = h_file->f_ra; */ if (!err) return 0; /* success */ /* close all */ for (bindex = au_fbstart(file); bindex <= btail; bindex++) au_set_h_fptr(file, bindex, NULL); au_set_fbstart(file, -1); au_set_fbend_dir(file, -1); return err; }
int au_reopen_nondir(struct file *file) { int err; aufs_bindex_t bstart; struct dentry *dentry; struct file *h_file, *h_file_tmp; dentry = file->f_dentry; AuDebugOn(au_special_file(dentry->d_inode->i_mode)); bstart = au_dbstart(dentry); h_file_tmp = NULL; if (au_fbstart(file) == bstart) { h_file = au_hf_top(file); if (file->f_mode == h_file->f_mode) return 0; /* success */ h_file_tmp = h_file; get_file(h_file_tmp); au_set_h_fptr(file, bstart, NULL); } AuDebugOn(au_fi(file)->fi_hdir); AuDebugOn(au_fbstart(file) < bstart); h_file = au_h_open(dentry, bstart, vfsub_file_flags(file) & ~O_TRUNC, file); err = PTR_ERR(h_file); if (IS_ERR(h_file)) goto out; /* todo: close all? */ err = 0; au_set_fbstart(file, bstart); au_set_h_fptr(file, bstart, h_file); au_update_figen(file); /* todo: necessary? */ /* file->f_ra = h_file->f_ra; */ out: if (h_file_tmp) fput(h_file_tmp); return err; }
/* * after branch manipulating, refresh the file. */ static int refresh_file(struct file *file, int (*reopen)(struct file *file)) { int err, need_reopen; aufs_bindex_t bend, bindex; struct dentry *dentry; struct au_finfo *finfo; struct au_hfile *hfile; dentry = file->f_dentry; finfo = au_fi(file); if (!finfo->fi_hdir) { hfile = &finfo->fi_htop; AuDebugOn(!hfile->hf_file); bindex = au_br_index(dentry->d_sb, hfile->hf_br->br_id); AuDebugOn(bindex < 0); if (bindex != finfo->fi_btop) au_set_fbstart(file, bindex); } else { err = au_fidir_realloc(finfo, au_sbend(dentry->d_sb) + 1); if (unlikely(err)) goto out; au_do_refresh_dir(file); } err = 0; need_reopen = 1; if (!au_test_mmapped(file)) err = au_file_refresh_by_inode(file, &need_reopen); if (!err && need_reopen && !d_unlinked(dentry)) err = reopen(file); if (!err) { au_update_figen(file); goto out; /* success */ } /* error, close all lower files */ if (finfo->fi_hdir) { bend = au_fbend_dir(file); for (bindex = au_fbstart(file); bindex <= bend; bindex++) au_set_h_fptr(file, bindex, NULL); } out: return err; }
int au_do_open_nondir(struct file *file, int flags) { int err; aufs_bindex_t bindex; struct file *h_file; struct dentry *dentry; struct au_finfo *finfo; FiMustWriteLock(file); dentry = file->f_dentry; err = au_d_alive(dentry); if (unlikely(err)) goto out; finfo = au_fi(file); memset(&finfo->fi_htop, 0, sizeof(finfo->fi_htop)); finfo->fi_hvmop = NULL; bindex = au_dbstart(dentry); /* * O_TRUNC is processed already. * But it is legal the target file has its size, since someone else may * give it while we are opening. */ BUG_ON(0 && au_test_ro(dentry->d_sb, bindex, dentry->d_inode) && (flags & O_TRUNC)); h_file = au_h_open(dentry, bindex, flags, file); if (IS_ERR(h_file)) err = PTR_ERR(h_file); else { au_set_fbstart(file, bindex); au_set_h_fptr(file, bindex, h_file); au_update_figen(file); /* todo: necessary? */ /* file->f_ra = h_file->f_ra; */ } out: return err; }
void au_finfo_fin(struct file *file) { struct au_finfo *finfo; aufs_bindex_t bindex, bend; fi_write_lock(file); bend = au_fbend(file); bindex = au_fbstart(file); if (bindex >= 0) /* * calls fput() instead of filp_close(), * since no dnotify or lock for the lower file. */ for (; bindex <= bend; bindex++) au_set_h_fptr(file, bindex, NULL); finfo = au_fi(file); au_dbg_verify_hf(finfo); kfree(finfo->fi_hfile); fi_write_unlock(file); AuRwDestroy(&finfo->fi_rwsem); au_cache_free_finfo(finfo); }
static void au_do_refresh_dir(struct file *file) { aufs_bindex_t bindex, bend, new_bindex, brid; struct au_hfile *p, tmp, *q; struct au_finfo *finfo; struct super_block *sb; struct au_fidir *fidir; FiMustWriteLock(file); sb = file->f_dentry->d_sb; finfo = au_fi(file); fidir = finfo->fi_hdir; AuDebugOn(!fidir); p = fidir->fd_hfile + finfo->fi_btop; brid = p->hf_br->br_id; bend = fidir->fd_bbot; for (bindex = finfo->fi_btop; bindex <= bend; bindex++, p++) { if (!p->hf_file) continue; new_bindex = au_br_index(sb, p->hf_br->br_id); if (new_bindex == bindex) continue; if (new_bindex < 0) { au_set_h_fptr(file, bindex, NULL); continue; } /* swap two lower inode, and loop again */ q = fidir->fd_hfile + new_bindex; tmp = *q; *q = *p; *p = tmp; if (tmp.hf_file) { bindex--; p--; } } p = fidir->fd_hfile; if (!au_test_mmapped(file) && !d_unlinked(file->f_dentry)) { bend = au_sbend(sb); for (finfo->fi_btop = 0; finfo->fi_btop <= bend; finfo->fi_btop++, p++) if (p->hf_file) { if (p->hf_file->f_dentry && p->hf_file->f_dentry->d_inode) break; else au_hfput(p, file); } } else { bend = au_br_index(sb, brid); for (finfo->fi_btop = 0; finfo->fi_btop < bend; finfo->fi_btop++, p++) if (p->hf_file) au_hfput(p, file); bend = au_sbend(sb); } p = fidir->fd_hfile + bend; for (fidir->fd_bbot = bend; fidir->fd_bbot >= finfo->fi_btop; fidir->fd_bbot--, p--) if (p->hf_file) { if (p->hf_file->f_dentry && p->hf_file->f_dentry->d_inode) break; else au_hfput(p, file); } AuDebugOn(fidir->fd_bbot < finfo->fi_btop); }
static int au_file_refresh_by_inode(struct file *file, int *need_reopen) { int err; struct au_pin pin; struct au_finfo *finfo; struct dentry *parent, *hi_wh; struct inode *inode; struct super_block *sb; struct au_cp_generic cpg = { .dentry = file->f_dentry, .bdst = -1, .bsrc = -1, .len = -1, .pin = &pin, .flags = AuCpup_DTIME }; FiMustWriteLock(file); err = 0; finfo = au_fi(file); sb = cpg.dentry->d_sb; inode = cpg.dentry->d_inode; cpg.bdst = au_ibstart(inode); if (cpg.bdst == finfo->fi_btop || IS_ROOT(cpg.dentry)) goto out; parent = dget_parent(cpg.dentry); if (au_test_ro(sb, cpg.bdst, inode)) { di_read_lock_parent(parent, !AuLock_IR); err = AuWbrCopyup(au_sbi(sb), cpg.dentry); cpg.bdst = err; di_read_unlock(parent, !AuLock_IR); if (unlikely(err < 0)) goto out_parent; err = 0; } di_read_lock_parent(parent, AuLock_IR); hi_wh = au_hi_wh(inode, cpg.bdst); if (!S_ISDIR(inode->i_mode) && au_opt_test(au_mntflags(sb), PLINK) && au_plink_test(inode) && !d_unhashed(cpg.dentry) && cpg.bdst < au_dbstart(cpg.dentry)) { err = au_test_and_cpup_dirs(cpg.dentry, cpg.bdst); if (unlikely(err)) goto out_unlock; /* always superio. */ err = au_pin(&pin, cpg.dentry, cpg.bdst, AuOpt_UDBA_NONE, AuPin_DI_LOCKED | AuPin_MNT_WRITE); if (!err) { err = au_sio_cpup_simple(&cpg); au_unpin(&pin); } } else if (hi_wh) { /* already copied-up after unlink */ err = au_reopen_wh(file, cpg.bdst, hi_wh); *need_reopen = 0; } out_unlock: di_read_unlock(parent, AuLock_IR); out_parent: dput(parent); out: return err; } static void au_do_refresh_dir(struct file *file) { aufs_bindex_t bindex, bend, new_bindex, brid; struct au_hfile *p, tmp, *q; struct au_finfo *finfo; struct super_block *sb; struct au_fidir *fidir; FiMustWriteLock(file); sb = file->f_dentry->d_sb; finfo = au_fi(file); fidir = finfo->fi_hdir; AuDebugOn(!fidir); p = fidir->fd_hfile + finfo->fi_btop; brid = p->hf_br->br_id; bend = fidir->fd_bbot; for (bindex = finfo->fi_btop; bindex <= bend; bindex++, p++) { if (!p->hf_file) continue; new_bindex = au_br_index(sb, p->hf_br->br_id); if (new_bindex == bindex) continue; if (new_bindex < 0) { au_set_h_fptr(file, bindex, NULL); continue; } /* swap two lower inode, and loop again */ q = fidir->fd_hfile + new_bindex; tmp = *q; *q = *p; *p = tmp; if (tmp.hf_file) { bindex--; p--; } } p = fidir->fd_hfile; if (!au_test_mmapped(file) && !d_unlinked(file->f_dentry)) { bend = au_sbend(sb); for (finfo->fi_btop = 0; finfo->fi_btop <= bend; finfo->fi_btop++, p++) if (p->hf_file) { if (file_inode(p->hf_file)) break; else au_hfput(p, file); } } else { bend = au_br_index(sb, brid); for (finfo->fi_btop = 0; finfo->fi_btop < bend; finfo->fi_btop++, p++) if (p->hf_file) au_hfput(p, file); bend = au_sbend(sb); } p = fidir->fd_hfile + bend; for (fidir->fd_bbot = bend; fidir->fd_bbot >= finfo->fi_btop; fidir->fd_bbot--, p--) if (p->hf_file) { if (file_inode(p->hf_file)) break; else au_hfput(p, file); } AuDebugOn(fidir->fd_bbot < finfo->fi_btop); }