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); /* * it can happen * file exists on both of rw and ro * open --> dbstart and fbstart are both 0 * prepend a branch as rw, "rw" become ro * remove rw/file * delete the top branch, "rw" becomes rw again * --> dbstart is 1, fbstart is still 0 * write --> fbstart is 0 but dbstart is 1 */ /* AuDebugOn(au_fbstart(file) < bstart); */ h_file = au_h_open(dentry, bstart, vfsub_file_flags(file) & ~O_TRUNC, file, /*force_wr*/0); err = PTR_ERR(h_file); if (IS_ERR(h_file)) { if (h_file_tmp) { atomic_inc(&au_sbr(dentry->d_sb, bstart)->br_count); au_set_h_fptr(file, bstart, h_file_tmp); h_file_tmp = NULL; } 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; }
static ssize_t au_fhsm_read(struct file *file, char __user *buf, size_t count, loff_t *pos) { ssize_t err; int readable; aufs_bindex_t nfhsm, bindex, bend; struct au_sbinfo *sbinfo; struct au_fhsm *fhsm; struct au_branch *br; struct super_block *sb; err = 0; sbinfo = file->private_data; fhsm = &sbinfo->si_fhsm; need_data: spin_lock_irq(&fhsm->fhsm_wqh.lock); if (!atomic_read(&fhsm->fhsm_readable)) { if (vfsub_file_flags(file) & O_NONBLOCK) err = -EAGAIN; else err = wait_event_interruptible_locked_irq (fhsm->fhsm_wqh, atomic_read(&fhsm->fhsm_readable)); } spin_unlock_irq(&fhsm->fhsm_wqh.lock); if (unlikely(err)) goto out; /* sb may already be dead */ au_rw_read_lock(&sbinfo->si_rwsem); readable = atomic_read(&fhsm->fhsm_readable); if (readable > 0) { sb = sbinfo->si_sb; AuDebugOn(!sb); /* exclude the bottom branch */ nfhsm = 0; bend = au_fhsm_bottom(sb); for (bindex = 0; bindex < bend; bindex++) { br = au_sbr(sb, bindex); if (au_br_fhsm(br->br_perm)) nfhsm++; } err = -EMSGSIZE; if (nfhsm * sizeof(struct aufs_stbr) <= count) { atomic_set(&fhsm->fhsm_readable, 0); err = au_fhsm_do_read(sbinfo->si_sb, (void __user *)buf, count); } } au_rw_read_unlock(&sbinfo->si_rwsem); if (!readable) goto need_data; out: return err; }
void au_hfput(struct au_hfile *hf, struct file *file) { /* todo: direct access f_flags */ if (vfsub_file_flags(file) & vfsub_fmode_to_uint(FMODE_EXEC)) allow_write_access(hf->hf_file); fput(hf->hf_file); hf->hf_file = NULL; atomic_dec(&hf->hf_br->br_count); hf->hf_br = NULL; }
int au_reopen_nondir(struct file *file) { int err; aufs_bindex_t bstart, bindex, bend; 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_h_fptr(file, bstart); 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_fbstart(file) < bstart || au_fi(file)->fi_hfile[0 + bstart].hf_file); 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; */ /* close lower files */ bend = au_fbend(file); for (bindex = bstart + 1; bindex <= bend; bindex++) au_set_h_fptr(file, bindex, NULL); au_set_fbend(file, bstart); out: if (h_file_tmp) fput(h_file_tmp); return err; }
static int reopen_dir(struct file *file) { int err; unsigned int flags; aufs_bindex_t bindex, btail, bstart; struct dentry *dentry, *h_dentry; struct file *h_file; /* open all lower dirs */ dentry = file->f_dentry; bstart = au_dbstart(dentry); for (bindex = au_fbstart(file); bindex < bstart; bindex++) au_set_h_fptr(file, bindex, NULL); au_set_fbstart(file, bstart); btail = au_dbtaildir(dentry); for (bindex = au_fbend_dir(file); btail < bindex; bindex--) au_set_h_fptr(file, bindex, NULL); au_set_fbend_dir(file, btail); flags = vfsub_file_flags(file); for (bindex = bstart; bindex <= btail; bindex++) { h_dentry = au_h_dptr(dentry, bindex); if (!h_dentry) continue; h_file = au_hf_dir(file, bindex); if (h_file) continue; h_file = au_h_open(dentry, bindex, flags, file); err = PTR_ERR(h_file); if (IS_ERR(h_file)) goto out; /* close all? */ au_set_h_fptr(file, bindex, h_file); } au_update_figen(file); /* todo: necessary? */ /* file->f_ra = h_file->f_ra; */ err = 0; out: return err; }
int au_do_open(struct file *file, int (*open)(struct file *file, int flags), struct au_fidir *fidir) { int err; struct dentry *dentry; err = au_finfo_init(file, fidir); if (unlikely(err)) goto out; dentry = file->f_dentry; di_read_lock_child(dentry, AuLock_IR); err = open(file, vfsub_file_flags(file)); di_read_unlock(dentry, AuLock_IR); fi_write_unlock(file); if (unlikely(err)) { au_fi(file)->fi_hdir = NULL; au_finfo_fin(file); } out: return err; }
int au_do_open(struct file *file, int (*open)(struct file *file, int flags)) { int err; struct dentry *dentry; struct super_block *sb; dentry = file->f_dentry; sb = dentry->d_sb; si_read_lock(sb, AuLock_FLUSH); err = au_finfo_init(file); if (unlikely(err)) goto out; di_read_lock_child(dentry, AuLock_IR); err = open(file, vfsub_file_flags(file)); di_read_unlock(dentry, AuLock_IR); fi_write_unlock(file); if (unlikely(err)) au_finfo_fin(file); out: si_read_unlock(sb); return err; }
au_sphl_add(&finfo->fi_hlist, &au_sbi(dentry->d_sb)->si_files); /* todo: necessary? */ /* file->f_ra = h_file->f_ra; */ } return err; } static int aufs_open_nondir(struct inode *inode __maybe_unused, struct file *file) { int err; struct super_block *sb; AuDbg("%pD, f_flags 0x%x, f_mode 0x%x\n", file, vfsub_file_flags(file), file->f_mode); sb = file->f_dentry->d_sb; si_read_lock(sb, AuLock_FLUSH); err = au_do_open(file, au_do_open_nondir, /*fidir*/NULL); si_read_unlock(sb); return err; } int aufs_release_nondir(struct inode *inode __maybe_unused, struct file *file) { struct au_finfo *finfo; aufs_bindex_t bindex; finfo = au_fi(file); au_sphl_del(&finfo->fi_hlist, &au_sbi(file->f_dentry->d_sb)->si_files);
/* todo: necessary? */ /* file->f_ra = h_file->f_ra; */ } out: return err; } static int aufs_open_nondir(struct inode *inode __maybe_unused, struct file *file) { int err; struct super_block *sb; AuDbg("%.*s, f_flags 0x%x, f_mode 0x%x\n", AuDLNPair(file->f_dentry), vfsub_file_flags(file), file->f_mode); sb = file->f_dentry->d_sb; si_read_lock(sb, AuLock_FLUSH); err = au_do_open(file, au_do_open_nondir, /*fidir*/NULL); si_read_unlock(sb); return err; } int aufs_release_nondir(struct inode *inode __maybe_unused, struct file *file) { struct au_finfo *finfo; aufs_bindex_t bindex; finfo = au_fi(file);
static int au_cmoo(struct dentry *dentry) { int err, cmoo; unsigned int udba; struct path h_path; struct au_pin pin; struct au_cp_generic cpg = { .dentry = dentry, .bdst = -1, .bsrc = -1, .len = -1, .pin = &pin, .flags = AuCpup_DTIME | AuCpup_HOPEN }; struct inode *inode, *delegated; struct super_block *sb; struct au_sbinfo *sbinfo; struct au_fhsm *fhsm; pid_t pid; struct au_branch *br; struct dentry *parent; struct au_hinode *hdir; DiMustWriteLock(dentry); inode = dentry->d_inode; IiMustWriteLock(inode); err = 0; if (IS_ROOT(dentry)) goto out; cpg.bsrc = au_dbstart(dentry); if (!cpg.bsrc) goto out; sb = dentry->d_sb; sbinfo = au_sbi(sb); fhsm = &sbinfo->si_fhsm; pid = au_fhsm_pid(fhsm); if (pid && (current->pid == pid || current->real_parent->pid == pid)) goto out; br = au_sbr(sb, cpg.bsrc); cmoo = au_br_cmoo(br->br_perm); if (!cmoo) goto out; if (!S_ISREG(inode->i_mode)) cmoo &= AuBrAttr_COO_ALL; if (!cmoo) goto out; parent = dget_parent(dentry); di_write_lock_parent(parent); err = au_wbr_do_copyup_bu(dentry, cpg.bsrc - 1); cpg.bdst = err; if (unlikely(err < 0)) { err = 0; /* there is no upper writable branch */ goto out_dgrade; } AuDbg("bsrc %d, bdst %d\n", cpg.bsrc, cpg.bdst); /* do not respect the coo attrib for the target branch */ err = au_cpup_dirs(dentry, cpg.bdst); if (unlikely(err)) goto out_dgrade; di_downgrade_lock(parent, AuLock_IR); udba = au_opt_udba(sb); err = au_pin(&pin, dentry, cpg.bdst, udba, AuPin_DI_LOCKED | AuPin_MNT_WRITE); if (unlikely(err)) goto out_parent; err = au_sio_cpup_simple(&cpg); au_unpin(&pin); if (unlikely(err)) goto out_parent; if (!(cmoo & AuBrWAttr_MOO)) goto out_parent; /* success */ err = au_pin(&pin, dentry, cpg.bsrc, udba, AuPin_DI_LOCKED | AuPin_MNT_WRITE); if (unlikely(err)) goto out_parent; h_path.mnt = au_br_mnt(br); h_path.dentry = au_h_dptr(dentry, cpg.bsrc); hdir = au_hi(parent->d_inode, cpg.bsrc); delegated = NULL; err = vfsub_unlink(hdir->hi_inode, &h_path, &delegated, /*force*/1); au_unpin(&pin); /* todo: keep h_dentry or not? */ if (unlikely(err == -EWOULDBLOCK)) { pr_warn("cannot retry for NFSv4 delegation" " for an internal unlink\n"); iput(delegated); } if (unlikely(err)) { pr_err("unlink %pd after coo failed (%d), ignored\n", dentry, err); err = 0; } goto out_parent; /* success */ out_dgrade: di_downgrade_lock(parent, AuLock_IR); out_parent: di_read_unlock(parent, AuLock_IR); dput(parent); out: AuTraceErr(err); return err; } int au_do_open(struct file *file, int (*open)(struct file *file, int flags), struct au_fidir *fidir) { int err; struct dentry *dentry; struct au_finfo *finfo; err = au_finfo_init(file, fidir); if (unlikely(err)) goto out; dentry = file->f_path.dentry; di_write_lock_child(dentry); err = au_cmoo(dentry); di_downgrade_lock(dentry, AuLock_IR); if (!err) err = open(file, vfsub_file_flags(file)); di_read_unlock(dentry, AuLock_IR); finfo = au_fi(file); if (!err) { finfo->fi_file = file; au_sphl_add(&finfo->fi_hlist, &au_sbi(file->f_path.dentry->d_sb)->si_files); } fi_write_unlock(file); if (unlikely(err)) { finfo->fi_hdir = NULL; au_finfo_fin(file); } out: return err; }