int au_cpdown_dirs(struct dentry *dentry, aufs_bindex_t bdst) { int err; struct au_cpdown_dir_args args = { .parent = dget_parent(dentry), .flags = 0 }; err = au_cp_dirs(dentry, bdst, au_cpdown_dir, &args); dput(args.parent); return err; } /* ---------------------------------------------------------------------- */ /* policies for create */ static int au_wbr_nonopq(struct dentry *dentry, aufs_bindex_t bindex) { int err, i, j, ndentry; aufs_bindex_t bopq; struct au_dcsub_pages dpages; struct au_dpage *dpage; struct dentry **dentries, *parent, *d; err = au_dpages_init(&dpages, GFP_NOFS); if (unlikely(err)) goto out; parent = dget_parent(dentry); err = au_dcsub_pages_rev_aufs(&dpages, parent, /*do_include*/0); if (unlikely(err)) goto out_free; err = bindex; for (i = 0; i < dpages.ndpage; i++) { dpage = dpages.dpages + i; dentries = dpage->dentries; ndentry = dpage->ndentry; for (j = 0; j < ndentry; j++) { d = dentries[j]; di_read_lock_parent2(d, !AuLock_IR); bopq = au_dbdiropq(d); di_read_unlock(d, !AuLock_IR); if (bopq >= 0 && bopq < err) err = bopq; } } out_free: dput(parent); au_dpages_free(&dpages); out: return err; }
/* * On success: * fills dentry object appropriate values and returns NULL. * On fail (== error) * returns error ptr * * @dir : Parent inode. It is locked (dir->i_mutex) * @dentry : Target dentry to lookup. we should set each of fields. * (dentry->d_name is initialized already) * @nd : nameidata of parent inode */ struct dentry *sdcardfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) { struct dentry *ret = NULL, *parent; struct path lower_parent_path; int err = 0; const struct cred *saved_cred = NULL; parent = dget_parent(dentry); if(!check_caller_access_to_name(parent->d_inode, dentry->d_name.name)) { ret = ERR_PTR(-EACCES); printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" " dentry: %s, task:%s\n", __func__, dentry->d_name.name, current->comm); goto out_err; } /* save current_cred and override it */ OVERRIDE_CRED_PTR(SDCARDFS_SB(dir->i_sb), saved_cred); sdcardfs_get_lower_path(parent, &lower_parent_path); /* allocate dentry private data. We free it in ->d_release */ err = new_dentry_private_data(dentry); if (err) { ret = ERR_PTR(err); goto out; } ret = __sdcardfs_lookup(dentry, flags, &lower_parent_path); if (IS_ERR(ret)) { goto out; } if (ret) dentry = ret; if (dentry->d_inode) { fsstack_copy_attr_times(dentry->d_inode, sdcardfs_lower_inode(dentry->d_inode)); /* get drived permission */ get_derived_permission(parent, dentry); fix_derived_permission(dentry->d_inode); } /* update parent directory's atime */ fsstack_copy_attr_atime(parent->d_inode, sdcardfs_lower_inode(parent->d_inode)); out: sdcardfs_put_lower_path(parent, &lower_parent_path); REVERT_CRED(saved_cred); out_err: dput(parent); return ret; }
void au_dbg_verify_nondir_parent(struct dentry *dentry, unsigned int sigen) { struct dentry *parent; struct inode *inode; parent = dget_parent(dentry); inode = dentry->d_inode; AuDebugOn(inode && S_ISDIR(dentry->d_inode->i_mode)); AuDebugOn(au_digen_test(parent, sigen)); dput(parent); }
static int sdcardfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { struct dentry *lower_dentry; struct inode *inode; struct inode *lower_inode; struct path lower_path; struct dentry *parent; struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); struct sdcardfs_inode_info *info; parent = dget_parent(dentry); if(!check_caller_access_to_name(parent->d_inode, dentry->d_name.name, sbi->options.derive, 0, 0)) { printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" " dentry: %s, task:%s\n", __func__, dentry->d_name.name, current->comm); dput(parent); return -EACCES; } dput(parent); inode = dentry->d_inode; sdcardfs_get_lower_path(dentry, &lower_path); lower_dentry = lower_path.dentry; lower_inode = sdcardfs_lower_inode(inode); info = SDCARDFS_I(inode); if (!strcmp(dentry->d_name.name, "ApkScript")) printk(KERN_ERR "dj enter_getattr_Apk--lower_inode->i_mode=%o, inode->i_mode=%o, info->d_mode=%o\n",lower_inode->i_mode, inode->i_mode, info->d_mode); if(!strcmp(dentry->d_name.name, "ShellScript")) printk(KERN_ERR "dj enter_getattr_Shell--lower_inode->i_mode=%o, inode->i_mode=%o, info->d_mode=%o\n",lower_inode->i_mode, inode->i_mode, info->d_mode); /* need to get inode->i_mutex */ mutex_lock(&inode->i_mutex); sdcardfs_copy_inode_attr(inode, lower_inode); fsstack_copy_inode_size(inode, lower_inode); /* if the dentry has been moved from other location * so, on this stage, its derived permission must be * rechecked from its private field. */ fix_derived_permission(inode); mutex_unlock(&inode->i_mutex); generic_fillattr(inode, stat); if (!strcmp(dentry->d_name.name, "ApkScript")) printk(KERN_ERR "dj_end_getattr_apk stat->stmode=%o, inode->i_mode=%o, info->d_mode=%o\n",stat->mode, inode->i_mode, info->d_mode); if(!strcmp(dentry->d_name.name, "ShellScript")) printk(KERN_ERR "dj_end_getattr_shell stat->stmode=%o, inode->i_mode=%o, info->d_mode=%o\n",stat->mode, inode->i_mode, info->d_mode); sdcardfs_put_lower_path(dentry, &lower_path); return 0; }
int need_graft_path(struct dentry *dentry) { int ret = 0; struct dentry *parent = dget_parent(dentry); struct sdcardfs_inode_info *parent_info= SDCARDFS_I(parent->d_inode); if(parent_info->perm == PERM_ANDROID && !strcasecmp(dentry->d_name.name, "obb")) { ret = 1; } dput(parent); return ret; }
/** * nfs_do_submount - set up mountpoint when crossing a filesystem boundary * @dentry - parent directory * @fh - filehandle for new root dentry * @fattr - attributes for new root inode * @authflavor - security flavor to use when performing the mount * */ struct vfsmount *nfs_do_submount(struct dentry *dentry, struct nfs_fh *fh, struct nfs_fattr *fattr, rpc_authflavor_t authflavor) { struct nfs_clone_mount mountdata = { .sb = dentry->d_sb, .dentry = dentry, .fh = fh, .fattr = fattr, .authflavor = authflavor, }; struct vfsmount *mnt = ERR_PTR(-ENOMEM); char *page = (char *) __get_free_page(GFP_USER); char *devname; dprintk("--> nfs_do_submount()\n"); dprintk("%s: submounting on %s/%s\n", __func__, dentry->d_parent->d_name.name, dentry->d_name.name); if (page == NULL) goto out; devname = nfs_devname(dentry, page, PAGE_SIZE); mnt = (struct vfsmount *)devname; if (IS_ERR(devname)) goto free_page; mnt = nfs_do_clone_mount(NFS_SB(dentry->d_sb), devname, &mountdata); free_page: free_page((unsigned long)page); out: dprintk("%s: done\n", __func__); dprintk("<-- nfs_do_submount() = %p\n", mnt); return mnt; } EXPORT_SYMBOL_GPL(nfs_do_submount); struct vfsmount *nfs_submount(struct nfs_server *server, struct dentry *dentry, struct nfs_fh *fh, struct nfs_fattr *fattr) { int err; struct dentry *parent = dget_parent(dentry); /* Look it up again to get its attributes */ err = server->nfs_client->rpc_ops->lookup(parent->d_inode, &dentry->d_name, fh, fattr); dput(parent); if (err != 0) return ERR_PTR(err); return nfs_do_submount(dentry, fh, fattr, server->client->cl_auth->au_flavor); }
static int ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { int rc; struct dentry *lower_old_dentry; struct vfsmount *lower_old_mnt; struct dentry *lower_new_dentry; struct vfsmount *lower_new_mnt; struct dentry *lower_old_dir_dentry; struct dentry *lower_new_dir_dentry; lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry); lower_old_mnt = ecryptfs_dentry_to_lower_mnt(old_dentry); lower_new_dentry = ecryptfs_dentry_to_lower(new_dentry); lower_new_mnt = ecryptfs_dentry_to_lower_mnt(new_dentry); dget(lower_old_dentry); dget(lower_new_dentry); lower_old_dir_dentry = dget_parent(lower_old_dentry); lower_new_dir_dentry = dget_parent(lower_new_dentry); lock_rename(lower_old_dir_dentry, lower_new_dir_dentry); rc = vfs_rename(lower_old_dir_dentry->d_inode, lower_old_dentry, lower_old_mnt, lower_new_dir_dentry->d_inode, lower_new_dentry, lower_new_mnt); if (rc) goto out_lock; fsstack_copy_attr_all(new_dir, lower_new_dir_dentry->d_inode, NULL); if (new_dir != old_dir) fsstack_copy_attr_all(old_dir, lower_old_dir_dentry->d_inode, NULL); out_lock: unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry); dput(lower_new_dentry->d_parent); dput(lower_old_dentry->d_parent); dput(lower_new_dentry); dput(lower_old_dentry); return rc; }
struct dentry *unionfs_dget_parent(struct dentry *child, int line, const char *file) { struct dentry *ptr; ptr = dget_parent(child); atomic_inc(&unionfs_dget_counter); atomic_inc(&unionfs_dgets_outstanding); printk("DG:%d:%d:%d:%p:%d:%s\n", atomic_read(&unionfs_dget_counter), atomic_read(&unionfs_dgets_outstanding), atomic_read(&ptr->d_count), ptr, line, file); return ptr; }
int au_reval_dpath(struct dentry *dentry, unsigned int sigen) { int err; struct dentry *d, *parent; struct inode *inode; if (!au_ftest_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIRS)) return simple_reval_dpath(dentry, sigen); /* slow loop, keep it simple and stupid */ /* cf: au_cpup_dirs() */ err = 0; parent = NULL; while (au_digen(dentry) != sigen || au_iigen(dentry->d_inode) != sigen) { d = dentry; while (1) { dput(parent); parent = dget_parent(d); if (au_digen(parent) == sigen && au_iigen(parent->d_inode) == sigen) break; d = parent; } inode = d->d_inode; if (d != dentry) di_write_lock_child(d); /* someone might update our dentry while we were sleeping */ if (au_digen(d) != sigen || au_iigen(d->d_inode) != sigen) { di_read_lock_parent(parent, AuLock_IR); /* returns a number of positive dentries */ err = au_refresh_hdentry(d, inode->i_mode & S_IFMT); if (err >= 0) err = au_refresh_hinode(inode, d); di_read_unlock(parent, AuLock_IR); } if (d != dentry) di_write_unlock(d); dput(parent); if (unlikely(err)) break; } return err; }
int au_reval_dpath(struct dentry *dentry, unsigned int sigen) { int err; struct dentry *d, *parent; struct inode *inode; if (!au_ftest_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIR)) return simple_reval_dpath(dentry, sigen); /* slow loop, keep it simple and stupid */ /* cf: au_cpup_dirs() */ err = 0; parent = NULL; while (au_digen_test(dentry, sigen)) { d = dentry; while (1) { dput(parent); parent = dget_parent(d); if (!au_digen_test(parent, sigen)) break; d = parent; } inode = d->d_inode; if (d != dentry) di_write_lock_child2(d); /* someone might update our dentry while we were sleeping */ if (au_digen_test(d, sigen)) { /* * todo: consolidate with simple_reval_dpath(), * do_refresh() and au_reval_for_attr(). */ di_read_lock_parent(parent, AuLock_IR); err = au_refresh_dentry(d, parent); di_read_unlock(parent, AuLock_IR); } if (d != dentry) di_write_unlock(d); dput(parent); if (unlikely(err)) break; } return err; }
static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd) { struct dentry *parent = NULL; struct inode *inode = dentry->d_inode; struct inode *dir; unsigned long verifier; int openflags, ret = 0; /* NFS only supports OPEN for regular files */ if (inode && !S_ISREG(inode->i_mode)) goto no_open; parent = dget_parent(dentry); dir = parent->d_inode; if (!is_atomic_open(dir, nd)) goto no_open; openflags = nd->intent.open.flags; if (openflags & O_CREAT) { /* If this is a negative dentry, just drop it */ if (!inode) goto out; /* If this is exclusive open, just revalidate */ if (openflags & O_EXCL) goto no_open; } /* We can't create new files, or truncate existing ones here */ openflags &= ~(O_CREAT|O_TRUNC); /* * Note: we're not holding inode->i_sem and so may be racing with * operations that change the directory. We therefore save the * change attribute *before* we do the RPC call. */ lock_kernel(); verifier = nfs_save_change_attribute(dir); ret = nfs4_open_revalidate(dir, dentry, openflags); if (!ret) nfs_set_verifier(dentry, verifier); unlock_kernel(); out: dput(parent); if (!ret) d_drop(dentry); return ret; no_open: dput(parent); return nfs_lookup_revalidate(dentry, nd); }
/* open the highest priority file for a given upper file */ static int open_highest_file(struct file *file, bool willwrite) { int bindex, bstart, bend, err = 0; struct file *lower_file; struct dentry *lower_dentry; struct dentry *dentry = file->f_path.dentry; struct dentry *parent = dget_parent(dentry); struct inode *parent_inode = parent->d_inode; struct super_block *sb = dentry->d_sb; bstart = dbstart(dentry); bend = dbend(dentry); lower_dentry = unionfs_lower_dentry(dentry); if (willwrite && IS_WRITE_FLAG(file->f_flags) && is_robranch(dentry)) { for (bindex = bstart - 1; bindex >= 0; bindex--) { err = copyup_file(parent_inode, file, bstart, bindex, i_size_read(dentry->d_inode)); if (!err) break; } atomic_set(&UNIONFS_F(file)->generation, atomic_read(&UNIONFS_I(dentry->d_inode)-> generation)); goto out; } dget(lower_dentry); unionfs_mntget(dentry, bstart); lower_file = dentry_open(lower_dentry, unionfs_lower_mnt_idx(dentry, bstart), file->f_flags, current_cred()); if (IS_ERR(lower_file)) { err = PTR_ERR(lower_file); goto out; } branchget(sb, bstart); unionfs_set_lower_file(file, lower_file); /* Fix up the position. */ lower_file->f_pos = file->f_pos; memcpy(&lower_file->f_ra, &file->f_ra, sizeof(struct file_ra_state)); out: dput(parent); return err; }
/* * Validate dentries for encrypted directories to make sure we aren't * potentially caching stale data after a key has been added or * removed. */ static int fscrypt_d_revalidate(struct dentry *dentry, unsigned int flags) { struct dentry *dir; struct fscrypt_info *ci; int dir_has_key, cached_with_key; if (flags & LOOKUP_RCU) return -ECHILD; dir = dget_parent(dentry); if (!d_inode(dir)->i_sb->s_cop->is_encrypted(d_inode(dir))) { dput(dir); return 0; } ci = d_inode(dir)->i_crypt_info; if (ci && ci->ci_keyring_key && (ci->ci_keyring_key->flags & ((1 << KEY_FLAG_INVALIDATED) | (1 << KEY_FLAG_REVOKED) | (1 << KEY_FLAG_DEAD)))) ci = NULL; /* this should eventually be an flag in d_flags */ spin_lock(&dentry->d_lock); cached_with_key = dentry->d_flags & DCACHE_ENCRYPTED_WITH_KEY; spin_unlock(&dentry->d_lock); dir_has_key = (ci != NULL); dput(dir); /* * If the dentry was cached without the key, and it is a * negative dentry, it might be a valid name. We can't check * if the key has since been made available due to locking * reasons, so we fail the validation so ext4_lookup() can do * this check. * * We also fail the validation if the dentry was created with * the key present, but we no longer have the key, or vice versa. */ if ((!cached_with_key && d_is_negative(dentry)) || (!cached_with_key && dir_has_key) || (cached_with_key && !dir_has_key)) return 0; return 1; }
/* todo: consolidate with do_refresh() and au_reval_for_attr() */ static int simple_reval_dpath(struct dentry *dentry, unsigned int sigen) { int err; struct dentry *parent; if (!au_digen_test(dentry, sigen)) return 0; parent = dget_parent(dentry); di_read_lock_parent(parent, AuLock_IR); AuDebugOn(au_digen_test(parent, sigen)); au_dbg_verify_gen(parent, sigen); err = au_refresh_dentry(dentry, parent); di_read_unlock(parent, AuLock_IR); dput(parent); AuTraceErr(err); return err; }
/* * returns the number of found lower positive dentries, * otherwise an error. */ int au_refresh_hdentry(struct dentry *dentry, mode_t type) { int npositive, err; unsigned int sigen; aufs_bindex_t bstart; struct au_dinfo *dinfo; struct super_block *sb; struct dentry *parent; DiMustWriteLock(dentry); sb = dentry->d_sb; AuDebugOn(IS_ROOT(dentry)); sigen = au_sigen(sb); parent = dget_parent(dentry); AuDebugOn(au_digen(parent) != sigen || au_iigen(parent->d_inode) != sigen); dinfo = au_di(dentry); err = au_di_realloc(dinfo, au_sbend(sb) + 1); npositive = err; if (unlikely(err)) goto out; au_do_refresh_hdentry(dinfo->di_hdentry + dinfo->di_bstart, dinfo, parent); npositive = 0; bstart = au_dbstart(parent); if (type != S_IFDIR && dinfo->di_bstart == bstart) goto out_dgen; /* success */ npositive = au_lkup_dentry(dentry, bstart, type, /*nd*/NULL); if (npositive < 0) goto out; if (dinfo->di_bwh >= 0 && dinfo->di_bwh <= dinfo->di_bstart) d_drop(dentry); out_dgen: au_update_digen(dentry); out: dput(parent); AuTraceErr(npositive); return npositive; }
/* todo: consolidate with do_refresh() and simple_reval_dpath() */ static int au_reval_for_attr(struct dentry *dentry, unsigned int sigen) { int err; struct inode *inode; struct dentry *parent; err = 0; inode = dentry->d_inode; if (au_digen_test(dentry, sigen)) { parent = dget_parent(dentry); di_read_lock_parent(parent, AuLock_IR); err = au_refresh_dentry(dentry, parent); di_read_unlock(parent, AuLock_IR); dput(parent); } AuTraceErr(err); return err; }
int need_graft_path_lollipop(struct dentry *dentry) { int ret = 0; struct dentry *parent = dget_parent(dentry); struct sdcardfslp_inode_info *parent_info= SDCARDFSLP_I(parent->d_inode); struct sdcardfslp_sb_info *sbi = SDCARDFSLP_SB(dentry->d_sb); if(parent_info->perm == PERM_ANDROID && !strcasecmp(dentry->d_name.name, "obb")) { /* /Android/obb is the base obbpath of DERIVED_UNIFIED */ if(!(sbi->options.derive == DERIVE_UNIFIED && parent_info->userid == 0)) { ret = 1; } } dput(parent); return ret; }
/** * nfs_do_submount - set up mountpoint when crossing a filesystem boundary * @dentry - parent directory * @fh - filehandle for new root dentry * @fattr - attributes for new root inode * @authflavor - security flavor to use when performing the mount * */ struct vfsmount *nfs_do_submount(struct dentry *dentry, struct nfs_fh *fh, struct nfs_fattr *fattr, rpc_authflavor_t authflavor) { struct nfs_clone_mount mountdata = { .sb = dentry->d_sb, .dentry = dentry, .fh = fh, .fattr = fattr, .authflavor = authflavor, }; struct vfsmount *mnt; char *page = (char *) __get_free_page(GFP_USER); char *devname; if (page == NULL) return ERR_PTR(-ENOMEM); devname = nfs_devname(dentry, page, PAGE_SIZE); if (IS_ERR(devname)) mnt = (struct vfsmount *)devname; else mnt = nfs_do_clone_mount(NFS_SB(dentry->d_sb), devname, &mountdata); free_page((unsigned long)page); return mnt; } EXPORT_SYMBOL_GPL(nfs_do_submount); struct vfsmount *nfs_submount(struct nfs_server *server, struct dentry *dentry, struct nfs_fh *fh, struct nfs_fattr *fattr) { int err; struct dentry *parent = dget_parent(dentry); /* Look it up again to get its attributes */ err = server->nfs_client->rpc_ops->lookup(d_inode(parent), &dentry->d_name, fh, fattr, NULL); dput(parent); if (err != 0) return ERR_PTR(err); return nfs_do_submount(dentry, fh, fattr, server->client->cl_auth->au_flavor); }
/** * fscrypt_file_open - prepare to open a possibly-encrypted regular file * @inode: the inode being opened * @filp: the struct file being set up * * Currently, an encrypted regular file can only be opened if its encryption key * is available; access to the raw encrypted contents is not supported. * Therefore, we first set up the inode's encryption key (if not already done) * and return an error if it's unavailable. * * We also verify that if the parent directory (from the path via which the file * is being opened) is encrypted, then the inode being opened uses the same * encryption policy. This is needed as part of the enforcement that all files * in an encrypted directory tree use the same encryption policy, as a * protection against certain types of offline attacks. Note that this check is * needed even when opening an *unencrypted* file, since it's forbidden to have * an unencrypted file in an encrypted directory. * * Return: 0 on success, -ENOKEY if the key is missing, or another -errno code */ int fscrypt_file_open(struct inode *inode, struct file *filp) { int err; struct dentry *dir; err = fscrypt_require_key(inode); if (err) return err; dir = dget_parent(file_dentry(filp)); if (IS_ENCRYPTED(d_inode(dir)) && !fscrypt_has_permitted_context(d_inode(dir), inode)) { fscrypt_warn(inode->i_sb, "inconsistent encryption contexts: %lu/%lu", d_inode(dir)->i_ino, inode->i_ino); err = -EPERM; } dput(dir); return err; }
static int wrapfs_open(struct inode *inode, struct file *file) { int err = 0; struct dentry *dentry = file->f_path.dentry; struct dentry *parent = NULL; int size; /* don't open unhashed/deleted files */ if (d_unhashed(dentry)) { err = -ENOENT; goto out_err; } file->private_data = kzalloc(sizeof(struct wrapfs_file_info), GFP_KERNEL); if (!WRAPFS_F(file)) { err = -ENOMEM; goto out_err; } atomic_set(&WRAPFS_F(file)->generation, atomic_read(&WRAPFS_I(inode)->generation)); size = sizeof(struct file *) * 2; WRAPFS_F(file)->lower_files = kzalloc(size, GFP_KERNEL); if (unlikely(!WRAPFS_F(file)->lower_files)) { err = -ENOMEM; goto out_err; } parent = dget_parent(dentry); if (S_ISDIR(inode->i_mode)) err = __open_dir(inode, file, parent); else err = __open_file(inode, file, parent); /* if(!err) fsstack_copy_attr_all(inode, wrapfs_lower_inode(inode)); */ out_err: dput(parent); return err; }
static int sdcardfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { struct dentry *lower_dentry; struct inode *inode; struct inode *lower_inode; struct path lower_path; struct dentry *parent; parent = dget_parent(dentry); if(!check_caller_access_to_name(parent->d_inode, dentry->d_name.name)) { printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" " dentry: %s, task:%s\n", __func__, dentry->d_name.name, current->comm); dput(parent); return -EACCES; } dput(parent); inode = dentry->d_inode; sdcardfs_get_lower_path(dentry, &lower_path); lower_dentry = lower_path.dentry; lower_inode = sdcardfs_lower_inode(inode); /* need to get inode->i_mutex */ mutex_lock(&inode->i_mutex); sdcardfs_copy_inode_attr(inode, lower_inode); fsstack_copy_inode_size(inode, lower_inode); /* if the dentry has been moved from other location * so, on this stage, its derived permission must be * rechecked from its private field. */ fix_derived_permission(inode); mutex_unlock(&inode->i_mutex); generic_fillattr(inode, stat); sdcardfs_put_lower_path(dentry, &lower_path); return 0; }
/* * On success: * fills dentry object appropriate values and returns NULL. * On fail (== error) * returns error ptr * * @dir : Parent inode. It is locked (dir->i_mutex) * @dentry : Target dentry to lookup. we should set each of fields. * (dentry->d_name is initialized already) * @nd : nameidata of parent inode */ struct dentry *sdcardfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { struct dentry *ret, *parent; struct path lower_parent_path; int err = 0; OVERRIDE_CRED_PTR(SDCARDFS_SB(dir->i_sb)); parent = dget_parent(dentry); sdcardfs_get_lower_path(parent, &lower_parent_path); /* allocate dentry private data. We free it in ->d_release */ err = new_dentry_private_data(dentry); if (err) { ret = ERR_PTR(err); goto out; } ret = __sdcardfs_lookup(dentry, nd, &lower_parent_path); if (IS_ERR(ret)) { goto out; } if (ret) dentry = ret; if (dentry->d_inode) fsstack_copy_attr_times(dentry->d_inode, sdcardfs_lower_inode(dentry->d_inode)); /* update parent directory's atime */ fsstack_copy_attr_atime(parent->d_inode, sdcardfs_lower_inode(parent->d_inode)); out: sdcardfs_put_lower_path(parent, &lower_parent_path); dput(parent); REVERT_CRED(); return ret; }
/* * ->setattr() and ->getattr() are called in various cases. * chmod, stat: dentry is revalidated. * fchmod, fstat: file and dentry are not revalidated, additionally they may be * unhashed. * for ->setattr(), ia->ia_file is passed from ftruncate only. */ static int au_reval_for_attr(struct dentry *dentry, unsigned int sigen) { int err; struct inode *inode; struct dentry *parent; err = 0; inode = dentry->d_inode; if (au_digen(dentry) != sigen || au_iigen(inode) != sigen) { parent = dget_parent(dentry); di_read_lock_parent(parent, AuLock_IR); /* returns a number of positive dentries */ err = au_refresh_hdentry(dentry, inode->i_mode & S_IFMT); if (err >= 0) err = au_refresh_hinode(inode, dentry); di_read_unlock(parent, AuLock_IR); dput(parent); } AuTraceErr(err); return err; }
/* top down parent */ static int au_wbr_create_tdp(struct dentry *dentry, unsigned int flags __maybe_unused) { int err; aufs_bindex_t bstart, bindex; struct super_block *sb; struct dentry *parent, *h_parent; sb = dentry->d_sb; bstart = au_dbstart(dentry); err = bstart; if (!au_br_rdonly(au_sbr(sb, bstart))) goto out; err = -EROFS; parent = dget_parent(dentry); for (bindex = au_dbstart(parent); bindex < bstart; bindex++) { h_parent = au_h_dptr(parent, bindex); if (!h_parent || !h_parent->d_inode) continue; if (!au_br_rdonly(au_sbr(sb, bindex))) { err = bindex; break; } } dput(parent); /* bottom up here */ if (unlikely(err < 0)) { err = au_wbr_bu(sb, bstart - 1); if (err >= 0) err = au_wbr_nonopq(dentry, err); } out: AuDbg("b%d\n", err); return err; }
/* * Validate dentries in encrypted directories to make sure we aren't potentially * caching stale dentries after a key has been added. */ static int fscrypt_d_revalidate(struct dentry *dentry, unsigned int flags) { struct dentry *dir; int err; int valid; /* * Plaintext names are always valid, since fscrypt doesn't support * reverting to ciphertext names without evicting the directory's inode * -- which implies eviction of the dentries in the directory. */ if (!(dentry->d_flags & DCACHE_ENCRYPTED_NAME)) return 1; /* * Ciphertext name; valid if the directory's key is still unavailable. * * Although fscrypt forbids rename() on ciphertext names, we still must * use dget_parent() here rather than use ->d_parent directly. That's * because a corrupted fs image may contain directory hard links, which * the VFS handles by moving the directory's dentry tree in the dcache * each time ->lookup() finds the directory and it already has a dentry * elsewhere. Thus ->d_parent can be changing, and we must safely grab * a reference to some ->d_parent to prevent it from being freed. */ if (flags & LOOKUP_RCU) return -ECHILD; dir = dget_parent(dentry); err = fscrypt_get_encryption_info(d_inode(dir)); valid = !fscrypt_has_encryption_key(d_inode(dir)); dput(dir); if (err < 0) return err; return valid; }
static struct xfs_inode * xfs_filestream_get_parent( struct xfs_inode *ip) { struct inode *inode = VFS_I(ip), *dir = NULL; struct dentry *dentry, *parent; dentry = d_find_alias(inode); if (!dentry) goto out; parent = dget_parent(dentry); if (!parent) goto out_dput; dir = igrab(parent->d_inode); dput(parent); out_dput: dput(dentry); out: return dir ? XFS_I(dir) : NULL; }
/* main function for updating derived permission */ inline void update_derived_permission_lollipop(struct dentry *dentry) { struct dentry *parent; if(!dentry || !dentry->d_inode) { printk(KERN_ERR "sdcardfslp: %s: invalid dentry\n", __func__); return; } /* FIXME: * 1. need to check whether the dentry is updated or not * 2. remove the root dentry update */ if(IS_ROOT(dentry)) { //setup_default_pre_root_state(dentry->d_inode); } else { parent = dget_parent(dentry); if(parent) { get_derived_permission_lollipop(parent, dentry); dput(parent); } } fix_derived_permission(dentry->d_inode); }
int au_wbr_nonopq(struct dentry *dentry, aufs_bindex_t bindex) { int err, i, j, ndentry; aufs_bindex_t bopq; struct au_dcsub_pages dpages; struct au_dpage *dpage; struct dentry **dentries, *parent, *d; err = au_dpages_init(&dpages, GFP_NOFS); if (unlikely(err)) goto out; parent = dget_parent(dentry); err = au_dcsub_pages_rev_aufs(&dpages, parent, /*do_include*/0); if (unlikely(err)) goto out_free; err = bindex; for (i = 0; i < dpages.ndpage; i++) { dpage = dpages.dpages + i; dentries = dpage->dentries; ndentry = dpage->ndentry; for (j = 0; j < ndentry; j++) { d = dentries[j]; di_read_lock_parent2(d, !AuLock_IR); bopq = au_dbdiropq(d); di_read_unlock(d, !AuLock_IR); if (bopq >= 0 && bopq < err) err = bopq; } } out_free: dput(parent); au_dpages_free(&dpages); out: return err; }
static int sdcardfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { struct dentry *lower_dentry; struct inode *inode; struct inode *lower_inode; struct path lower_path; struct dentry *parent; struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); parent = dget_parent(dentry); if(!check_caller_access_to_name(parent->d_inode, dentry->d_name.name, sbi->options.derive, 0, 0)) { dput(parent); return -EACCES; } dput(parent); inode = dentry->d_inode; sdcardfs_get_lower_path(dentry, &lower_path); lower_dentry = lower_path.dentry; lower_inode = sdcardfs_lower_inode(inode); fsstack_copy_attr_all(inode, lower_inode); fsstack_copy_inode_size(inode, lower_inode); /* if the dentry has been moved from other location * so, on this stage, its derived permission must be * rechecked from its private field. */ fix_derived_permission(inode); generic_fillattr(inode, stat); sdcardfs_put_lower_path(dentry, &lower_path); return 0; }
static int ovl_copy_up_truncate(struct dentry *dentry) { int err; struct dentry *parent; struct kstat stat; struct path lowerpath; parent = dget_parent(dentry); err = ovl_copy_up(parent); if (err) goto out_dput_parent; ovl_path_lower(dentry, &lowerpath); err = vfs_getattr(&lowerpath, &stat); if (err) goto out_dput_parent; stat.size = 0; err = ovl_copy_up_one(parent, dentry, &lowerpath, &stat); out_dput_parent: dput(parent); return err; }