/* * our custom d_alloc_root work-alike * * we can't use d_alloc_root if we want to use our own interpose function * unchanged, so we simply call our own "fake" d_alloc_root */ static struct dentry *sdcardfs_d_alloc_root(struct super_block *sb) { struct dentry *ret = NULL; //struct sdcardfs_sb_info *sbi = SDCARDFS_SB(sb); struct dentry *(*__d_alloc_new)(struct super_block *, const struct qstr *) = (void *)kallsyms_lookup_name("__d_alloc"); if (sb) { static const struct qstr name = { .name = "/", .len = 1 }; ret = __d_alloc_new(sb, &name); if (ret) { d_set_d_op(ret, &sdcardfs_ci_dops); ret->d_parent = ret; } } return ret; } /* * There is no need to lock the sdcardfs_super_info's rwsem as there is no * way anyone can have a reference to the superblock at this point in time. */ static int sdcardfs_read_super(struct super_block *sb, const char *dev_name, void *raw_data, int silent) { int err = 0; int debug; struct super_block *lower_sb; struct path lower_path; struct sdcardfs_sb_info *sb_info; void *pkgl_id; printk(KERN_INFO "sdcardfs version 2.0\n"); if (!dev_name) { printk(KERN_ERR "sdcardfs: read_super: missing dev_name argument\n"); err = -EINVAL; goto out; } printk(KERN_INFO "sdcardfs: dev_name -> %s\n", dev_name); printk(KERN_INFO "sdcardfs: options -> %s\n", (char *)raw_data); /* parse lower path */ err = kern_path(dev_name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &lower_path); if (err) { printk(KERN_ERR "sdcardfs: error accessing " "lower directory '%s'\n", dev_name); goto out; } /* allocate superblock private data */ sb->s_fs_info = kzalloc(sizeof(struct sdcardfs_sb_info), GFP_KERNEL); if (!SDCARDFS_SB(sb)) { printk(KERN_CRIT "sdcardfs: read_super: out of memory\n"); err = -ENOMEM; goto out_free; } sb_info = sb->s_fs_info; /* parse options */ err = parse_options(sb, raw_data, silent, &debug, &sb_info->options); if (err) { printk(KERN_ERR "sdcardfs: invalid options\n"); goto out_freesbi; } if (sb_info->options.derive != DERIVE_NONE) { pkgl_id = packagelist_create(sb_info->options.write_gid); if(IS_ERR(pkgl_id)) goto out_freesbi; else sb_info->pkgl_id = pkgl_id; } /* set the lower superblock field of upper superblock */ lower_sb = lower_path.dentry->d_sb; atomic_inc(&lower_sb->s_active); sdcardfs_set_lower_super(sb, lower_sb); /* inherit maxbytes from lower file system */ sb->s_maxbytes = lower_sb->s_maxbytes; /* * Our c/m/atime granularity is 1 ns because we may stack on file * systems whose granularity is as good. */ sb->s_time_gran = 1; sb->s_magic = SDCARDFS_SUPER_MAGIC; sb->s_op = &sdcardfs_sops; /* see comment next to the definition of sdcardfs_d_alloc_root */ sb->s_root = sdcardfs_d_alloc_root(sb); if (!sb->s_root) { err = -ENOMEM; goto out_sput; } /* link the upper and lower dentries */ sb->s_root->d_fsdata = NULL; err = new_dentry_private_data(sb->s_root); if (err) goto out_freeroot; /* set the lower dentries for s_root */ sdcardfs_set_lower_path(sb->s_root, &lower_path); /* call interpose to create the upper level inode */ err = sdcardfs_interpose(sb->s_root, sb, &lower_path); if (!err) { /* setup permission policy */ switch(sb_info->options.derive) { case DERIVE_NONE: setup_derived_state(sb->s_root->d_inode, PERM_ROOT, 0, AID_ROOT, AID_SDCARD_RW, 00775); sb_info->obbpath_s = NULL; break; case DERIVE_LEGACY: /* Legacy behavior used to support internal multiuser layout which * places user_id at the top directory level, with the actual roots * just below that. Shared OBB path is also at top level. */ setup_derived_state(sb->s_root->d_inode, PERM_LEGACY_PRE_ROOT, 0, AID_ROOT, AID_SDCARD_R, 00771); /* initialize the obbpath string and lookup the path * sb_info->obb_path will be deactivated by path_put * on sdcardfs_put_super */ sb_info->obbpath_s = kzalloc(PATH_MAX, GFP_KERNEL); snprintf(sb_info->obbpath_s, PATH_MAX, "%s/obb", dev_name); err = prepare_dir(sb_info->obbpath_s, sb_info->options.fs_low_uid, sb_info->options.fs_low_gid, 00755); if(err) printk(KERN_ERR "sdcardfs: %s: %d, error on creating %s\n", __func__,__LINE__, sb_info->obbpath_s); break; case DERIVE_UNIFIED: /* Unified multiuser layout which places secondary user_id under * /Android/user and shared OBB path under /Android/obb. */ setup_derived_state(sb->s_root->d_inode, PERM_ROOT, 0, AID_ROOT, AID_SDCARD_R, 00771); sb_info->obbpath_s = kzalloc(PATH_MAX, GFP_KERNEL); snprintf(sb_info->obbpath_s, PATH_MAX, "%s/Android/obb", dev_name); break; } fix_derived_permission(sb->s_root->d_inode); if (!silent) printk(KERN_INFO "sdcardfs: mounted on top of %s type %s\n", dev_name, lower_sb->s_type->name); goto out; } /* else error: fall through */ free_dentry_private_data(sb->s_root); out_freeroot: dput(sb->s_root); out_sput: /* drop refs we took earlier */ atomic_dec(&lower_sb->s_active); packagelist_destroy(sb_info->pkgl_id); out_freesbi: kfree(SDCARDFS_SB(sb)); sb->s_fs_info = NULL; out_free: path_put(&lower_path); out: return err; }
/* * our custom d_alloc_root work-alike * * we can't use d_alloc_root if we want to use our own interpose function * unchanged, so we simply call our own "fake" d_alloc_root */ static struct dentry *sdcardfs_d_alloc_root(struct super_block *sb) { struct dentry *ret = NULL; if (sb) { static const struct qstr name = { .name = "/", .len = 1 }; ret = __d_alloc(sb, &name); if (ret) { d_set_d_op(ret, &sdcardfs_ci_dops); ret->d_parent = ret; } } return ret; } /* * There is no need to lock the sdcardfs_super_info's rwsem as there is no * way anyone can have a reference to the superblock at this point in time. */ static int sdcardfs_read_super(struct super_block *sb, const char *dev_name, void *raw_data, int silent) { int err = 0; int debug; struct super_block *lower_sb; struct path lower_path; struct sdcardfs_sb_info *sb_info; void *pkgl_id; printk(KERN_INFO "sdcardfs: version %s\n", SDCARDFS_VERSION); if (!dev_name) { printk(KERN_ERR "sdcardfs: read_super: missing dev_name argument\n"); err = -EINVAL; goto out; } printk(KERN_INFO "sdcardfs: dev_name -> %s\n", dev_name); printk(KERN_INFO "sdcardfs: options -> %s\n", (char *)raw_data); /* parse lower path */ err = kern_path(dev_name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &lower_path); if (err) { printk(KERN_ERR "sdcardfs: error accessing " "lower directory '%s'\n", dev_name); goto out; } /* allocate superblock private data */ sb->s_fs_info = kzalloc(sizeof(struct sdcardfs_sb_info), GFP_KERNEL); if (!SDCARDFS_SB(sb)) { printk(KERN_CRIT "sdcardfs: read_super: out of memory\n"); err = -ENOMEM; goto out_free; } sb_info = sb->s_fs_info; /* parse options */ err = parse_options(sb, raw_data, silent, &debug, &sb_info->options); if (err) { printk(KERN_ERR "sdcardfs: invalid options or out of memory\n"); goto out_freesbi; } pkgl_id = packagelist_create(); if(IS_ERR(pkgl_id)) goto out_freesbi; else sb_info->pkgl_id = pkgl_id; /* set the lower superblock field of upper superblock */ lower_sb = lower_path.dentry->d_sb; atomic_inc(&lower_sb->s_active); sdcardfs_set_lower_super(sb, lower_sb); /* inherit maxbytes from lower file system */ sb->s_maxbytes = lower_sb->s_maxbytes; /* * Our c/m/atime granularity is 1 ns because we may stack on file * systems whose granularity is as good. */ sb->s_time_gran = 1; sb->s_magic = SDCARDFS_SUPER_MAGIC; if (sb_info->options.type != TYPE_NONE) sb->s_op = &sdcardfs_multimount_sops; else sb->s_op = &sdcardfs_sops; /* see comment next to the definition of sdcardfs_d_alloc_root */ sb->s_root = sdcardfs_d_alloc_root(sb); if (!sb->s_root) { err = -ENOMEM; goto out_sput; } /* link the upper and lower dentries */ sb->s_root->d_fsdata = NULL; err = new_dentry_private_data(sb->s_root); if (err) goto out_freeroot; /* set the lower dentries for s_root */ sdcardfs_set_lower_path(sb->s_root, &lower_path); /* call interpose to create the upper level inode */ err = sdcardfs_interpose(sb->s_root, sb, &lower_path); if (!err) { /* setup permission policy */ if(sb_info->options.multi_user){ setup_derived_state(sb->s_root->d_inode, PERM_PRE_ROOT, sb_info->options.userid, AID_ROOT, sb_info->options.gid, false); sb_info->obbpath_s = kzalloc(PATH_MAX, GFP_KERNEL); snprintf(sb_info->obbpath_s, PATH_MAX, "%s/obb", dev_name); err = prepare_dir(sb_info->obbpath_s, sb_info->options.fs_low_uid, sb_info->options.fs_low_gid, 00775); } else { setup_derived_state(sb->s_root->d_inode, PERM_ROOT, sb_info->options.userid, AID_ROOT, sb_info->options.gid, false); sb_info->obbpath_s = kzalloc(PATH_MAX, GFP_KERNEL); snprintf(sb_info->obbpath_s, PATH_MAX, "%s/Android/obb", dev_name); } fix_derived_permission(sb->s_root->d_inode); sb_info->devpath = kzalloc(PATH_MAX, GFP_KERNEL); if(sb_info->devpath && dev_name) strncpy(sb_info->devpath, dev_name, strlen(dev_name)); if (!silent && !err) printk(KERN_INFO "sdcardfs: mounted on top of %s type %s\n", dev_name, lower_sb->s_type->name); goto out; } /* else error: fall through */ free_dentry_private_data(sb->s_root); out_freeroot: dput(sb->s_root); out_sput: /* drop refs we took earlier */ atomic_dec(&lower_sb->s_active); packagelist_destroy(sb_info->pkgl_id); out_freesbi: kfree(SDCARDFS_SB(sb)); sb->s_fs_info = NULL; out_free: path_put(&lower_path); out: return err; }
/* * Main driver function for sdcardfs's lookup. * * Returns: NULL (ok), ERR_PTR if an error occurred. * Fills in lower_parent_path with <dentry,mnt> on success. */ static struct dentry *__sdcardfs_lookup(struct dentry *dentry, struct nameidata *nd, struct path *lower_parent_path) { int err = 0; struct vfsmount *lower_dir_mnt; struct dentry *lower_dir_dentry = NULL; struct dentry *lower_dentry; const char *name; struct path lower_path; struct qstr this; struct sdcardfs_sb_info *sbi; struct nameidata lower_nd; sbi = SDCARDFS_SB(dentry->d_sb); /* must initialize dentry operations */ d_set_d_op(dentry, &sdcardfs_ci_dops); if (IS_ROOT(dentry)) goto out; name = dentry->d_name.name; /* now start the actual lookup procedure */ lower_dir_dentry = lower_parent_path->dentry; lower_dir_mnt = lower_parent_path->mnt; /* Use vfs_path_lookup to check if the dentry exists or not */ if (sbi->options.lower_fs == LOWER_FS_EXT4) { err = vfs_path_lookup(lower_dir_dentry, lower_dir_mnt, name, LOOKUP_CASE_INSENSITIVE, &lower_nd); } else if (sbi->options.lower_fs == LOWER_FS_FAT) { err = vfs_path_lookup(lower_dir_dentry, lower_dir_mnt, name, 0, &lower_nd); } lower_path = lower_nd.path; /* no error: handle positive dentries */ if (!err) { /* check if the dentry is an obb dentry * if true, the lower_inode must be replaced with * the inode of the graft path */ if(need_graft_path(dentry)) { /* setup_obb_dentry() * The lower_path will be stored to the dentry's orig_path * and the base obbpath will be copyed to the lower_path variable. * if an error returned, there's no change in the lower_path * returns: -ERRNO if error (0: no error) */ err = setup_obb_dentry(dentry, &lower_path); if(err) { /* if the sbi->obbpath is not available, we can optionally * setup the lower_path with its orig_path. * but, the current implementation just returns an error * because the sdcard daemon also regards this case as * a lookup fail. */ printk(KERN_INFO "sdcardfs: base obbpath is not available\n"); sdcardfs_put_reset_orig_path(dentry); goto out; } } sdcardfs_set_lower_path(dentry, &lower_path); err = sdcardfs_interpose(dentry, dentry->d_sb, &lower_path); if (err) /* path_put underlying path on error */ sdcardfs_put_reset_lower_path(dentry); goto out; } /* * We don't consider ENOENT an error, and we want to return a * negative dentry. */ if (err && err != -ENOENT) goto out; /* instatiate a new negative dentry */ this.name = name; this.len = strlen(name); this.hash = full_name_hash(this.name, this.len); lower_dentry = d_lookup(lower_dir_dentry, &this); if (lower_dentry) goto setup_lower; lower_dentry = d_alloc(lower_dir_dentry, &this); if (!lower_dentry) { err = -ENOMEM; goto out; } d_add(lower_dentry, NULL); /* instantiate and hash */ setup_lower: lower_path.dentry = lower_dentry; lower_path.mnt = mntget(lower_dir_mnt); sdcardfs_set_lower_path(dentry, &lower_path); /* * If the intent is to create a file, then don't return an error, so * the VFS will continue the process of making this negative dentry * into a positive one. */ if (nd) { if (nd->flags & (LOOKUP_CREATE|LOOKUP_RENAME_TARGET)) err = 0; } else err = 0; out: return ERR_PTR(err); }
/* * our custom d_alloc_root work-alike * * we can't use d_alloc_root if we want to use our own interpose function * unchanged, so we simply call our own "fake" d_alloc_root */ static struct dentry *sdcardfs_d_alloc_root(struct super_block *sb) { struct dentry *ret = NULL; if (sb) { static const struct qstr name = { .name = "/", .len = 1 }; ret = d_alloc(NULL, &name); if (ret) { d_set_d_op(ret, &sdcardfs_ci_dops); ret->d_sb = sb; ret->d_parent = ret; } } return ret; } #endif DEFINE_MUTEX(sdcardfs_super_list_lock); LIST_HEAD(sdcardfs_super_list); EXPORT_SYMBOL_GPL(sdcardfs_super_list_lock); EXPORT_SYMBOL_GPL(sdcardfs_super_list); /* * There is no need to lock the sdcardfs_super_info's rwsem as there is no * way anyone can have a reference to the superblock at this point in time. */ static int sdcardfs_read_super(struct super_block *sb, const char *dev_name, void *raw_data, int silent) { int err = 0; int debug; struct super_block *lower_sb; struct path lower_path; struct sdcardfs_sb_info *sb_info; struct inode *inode; printk(KERN_INFO "sdcardfs version 2.0\n"); if (!dev_name) { printk(KERN_ERR "sdcardfs: read_super: missing dev_name argument\n"); err = -EINVAL; goto out; } printk(KERN_INFO "sdcardfs: dev_name -> %s\n", dev_name); printk(KERN_INFO "sdcardfs: options -> %s\n", (char *)raw_data); /* parse lower path */ err = kern_path(dev_name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &lower_path); if (err) { printk(KERN_ERR "sdcardfs: error accessing lower directory '%s'\n", dev_name); goto out; } /* allocate superblock private data */ sb->s_fs_info = kzalloc(sizeof(struct sdcardfs_sb_info), GFP_KERNEL); if (!SDCARDFS_SB(sb)) { printk(KERN_CRIT "sdcardfs: read_super: out of memory\n"); err = -ENOMEM; goto out_free; } sb_info = sb->s_fs_info; /* parse options */ err = parse_options(sb, raw_data, silent, &debug, &sb_info->options); if (err) { printk(KERN_ERR "sdcardfs: invalid options\n"); goto out_freesbi; } /* set the lower superblock field of upper superblock */ lower_sb = lower_path.dentry->d_sb; atomic_inc(&lower_sb->s_active); sdcardfs_set_lower_super(sb, lower_sb); /* inherit maxbytes from lower file system */ sb->s_maxbytes = lower_sb->s_maxbytes; /* * Our c/m/atime granularity is 1 ns because we may stack on file * systems whose granularity is as good. */ sb->s_time_gran = 1; sb->s_magic = SDCARDFS_SUPER_MAGIC; sb->s_op = &sdcardfs_sops; /* get a new inode and allocate our root dentry */ inode = sdcardfs_iget(sb, lower_path.dentry->d_inode, 0); if (IS_ERR(inode)) { err = PTR_ERR(inode); goto out_sput; } sb->s_root = d_make_root(inode); if (!sb->s_root) { err = -ENOMEM; goto out_iput; } d_set_d_op(sb->s_root, &sdcardfs_ci_dops); /* link the upper and lower dentries */ sb->s_root->d_fsdata = NULL; err = new_dentry_private_data(sb->s_root); if (err) goto out_freeroot; /* set the lower dentries for s_root */ sdcardfs_set_lower_path(sb->s_root, &lower_path); /* * No need to call interpose because we already have a positive * dentry, which was instantiated by d_make_root. Just need to * d_rehash it. */ d_rehash(sb->s_root); /* setup permission policy */ sb_info->obbpath_s = kzalloc(PATH_MAX, GFP_KERNEL); mutex_lock(&sdcardfs_super_list_lock); if(sb_info->options.multiuser) { setup_derived_state(sb->s_root->d_inode, PERM_PRE_ROOT, sb_info->options.fs_user_id, AID_ROOT, false, sb->s_root->d_inode); snprintf(sb_info->obbpath_s, PATH_MAX, "%s/obb", dev_name); /*err = prepare_dir(sb_info->obbpath_s, sb_info->options.fs_low_uid, sb_info->options.fs_low_gid, 00755);*/ } else { setup_derived_state(sb->s_root->d_inode, PERM_ROOT, sb_info->options.fs_user_id, AID_ROOT, false, sb->s_root->d_inode); snprintf(sb_info->obbpath_s, PATH_MAX, "%s/Android/obb", dev_name); } fix_derived_permission(sb->s_root->d_inode); sb_info->sb = sb; list_add(&sb_info->list, &sdcardfs_super_list); mutex_unlock(&sdcardfs_super_list_lock); if (!silent) printk(KERN_INFO "sdcardfs: mounted on top of %s type %s\n", dev_name, lower_sb->s_type->name); goto out; /* all is well */ /* no longer needed: free_dentry_private_data(sb->s_root); */ out_freeroot: dput(sb->s_root); out_iput: iput(inode); out_sput: /* drop refs we took earlier */ atomic_dec(&lower_sb->s_active); out_freesbi: kfree(SDCARDFS_SB(sb)); sb->s_fs_info = NULL; out_free: path_put(&lower_path); out: return err; }
/* * our custom d_alloc_root work-alike * * we can't use d_alloc_root if we want to use our own interpose function * unchanged, so we simply call our own "fake" d_alloc_root */ static struct dentry *sdcardfs_d_alloc_root(struct super_block *sb) { struct dentry *ret = NULL; if (sb) { static const struct qstr name = { .name = "/", .len = 1 }; ret = d_alloc(NULL, &name); if (ret) { d_set_d_op(ret, &sdcardfs_dops); ret->d_sb = sb; ret->d_parent = ret; } } return ret; } /* * There is no need to lock the sdcardfs_super_info's rwsem as there is no * way anyone can have a reference to the superblock at this point in time. */ static int sdcardfs_read_super(struct super_block *sb, const char *dev_name, void *raw_data, int silent) { int err = 0; int debug; struct super_block *lower_sb; struct path lower_path; struct sdcardfs_sb_info *sb_info; if (!dev_name) { printk(KERN_ERR "sdcardfs: read_super: missing dev_name argument\n"); err = -EINVAL; goto out; } printk(KERN_INFO "sdcardfs: dev_name -> %s\n", dev_name); printk(KERN_INFO "sdcardfs: options -> %s\n", (char *)raw_data); /* parse lower path */ err = kern_path(dev_name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &lower_path); if (err) { printk(KERN_ERR "sdcardfs: error accessing " "lower directory '%s'\n", dev_name); goto out; } /* allocate superblock private data */ sb->s_fs_info = kzalloc(sizeof(struct sdcardfs_sb_info), GFP_KERNEL); if (!SDCARDFS_SB(sb)) { printk(KERN_CRIT "sdcardfs: read_super: out of memory\n"); err = -ENOMEM; goto out_free; } /* setup fs_uid and fs_gid for FAT emulation : wjlee */ sb_info = sb->s_fs_info; sb_info->fs_uid = AID_ROOT; sb_info->fs_gid = AID_SDCARD_RW; /* parse options */ err = parse_options(sb, raw_data, silent, &debug, &sb_info->options); if (err) { printk(KERN_ERR "sdcardfs: invalid options\n"); goto out_freesbi; } /* set the lower superblock field of upper superblock */ lower_sb = lower_path.dentry->d_sb; atomic_inc(&lower_sb->s_active); sdcardfs_set_lower_super(sb, lower_sb); /* inherit maxbytes from lower file system */ sb->s_maxbytes = lower_sb->s_maxbytes; /* * Our c/m/atime granularity is 1 ns because we may stack on file * systems whose granularity is as good. */ sb->s_time_gran = 1; sb->s_op = &sdcardfs_sops; /* see comment next to the definition of sdcardfs_d_alloc_root */ sb->s_root = sdcardfs_d_alloc_root(sb); if (!sb->s_root) { err = -ENOMEM; goto out_sput; } /* link the upper and lower dentries */ sb->s_root->d_fsdata = NULL; err = new_dentry_private_data(sb->s_root); if (err) goto out_freeroot; /* set the lower dentries for s_root */ sdcardfs_set_lower_path(sb->s_root, &lower_path); /* call interpose to create the upper level inode */ err = sdcardfs_interpose(sb->s_root, sb, &lower_path); if (!err) { if (!silent) printk(KERN_INFO "sdcardfs: mounted on top of %s type %s\n", dev_name, lower_sb->s_type->name); goto out; } /* else error: fall through */ free_dentry_private_data(sb->s_root); out_freeroot: dput(sb->s_root); out_sput: /* drop refs we took earlier */ atomic_dec(&lower_sb->s_active); out_freesbi: kfree(SDCARDFS_SB(sb)); sb->s_fs_info = NULL; out_free: path_put(&lower_path); out: return err; }
/* * Main driver function for sdcardfs's lookup. * * Returns: NULL (ok), ERR_PTR if an error occurred. * Fills in lower_parent_path with <dentry,mnt> on success. */ static struct dentry *__sdcardfs_lookup(struct dentry *dentry, struct nameidata *nd, struct path *lower_parent_path) { int err = 0; struct vfsmount *lower_dir_mnt; struct dentry *lower_dir_dentry = NULL; struct dentry *lower_dentry; const char *name; struct path lower_path; struct qstr this; /* must initialize dentry operations */ d_set_d_op(dentry, &sdcardfs_dops); if (IS_ROOT(dentry)) goto out; name = dentry->d_name.name; /* now start the actual lookup procedure */ lower_dir_dentry = lower_parent_path->dentry; lower_dir_mnt = lower_parent_path->mnt; /* Use vfs_path_lookup to check if the dentry exists or not */ err = vfs_path_lookup(lower_dir_dentry, lower_dir_mnt, name, 0, &lower_path); /* no error: handle positive dentries */ if (!err) { #ifdef SDCARDFS_CASE_INSENSITIVE_MATCH_SUPPORT dentry_found: #endif sdcardfs_set_lower_path(dentry, &lower_path); err = sdcardfs_interpose(dentry, dentry->d_sb, &lower_path); if (err) /* path_put underlying path on error */ sdcardfs_put_reset_lower_path(dentry); goto out; } #ifdef SDCARDFS_CASE_INSENSITIVE_MATCH_SUPPORT if (err == -ENOENT) { /* try case insensetive match */ char * match_name = NULL; match_name = find_case_insensitive(lower_parent_path, name); if (unlikely(IS_ERR(match_name))) { err = PTR_ERR(match_name); } else if (match_name) { /* found */ err = vfs_path_lookup(lower_dir_dentry, lower_dir_mnt, match_name, 0, &lower_path); kfree(match_name); if (!err) goto dentry_found; } /* no match */ } #endif /* * We don't consider ENOENT an error, and we want to return a * negative dentry. */ if (err && err != -ENOENT) goto out; /* instatiate a new negative dentry */ this.name = name; this.len = strlen(name); this.hash = full_name_hash(this.name, this.len); lower_dentry = d_lookup(lower_dir_dentry, &this); if (lower_dentry) goto setup_lower; lower_dentry = d_alloc(lower_dir_dentry, &this); if (!lower_dentry) { err = -ENOMEM; goto out; } d_add(lower_dentry, NULL); /* instantiate and hash */ setup_lower: lower_path.dentry = lower_dentry; lower_path.mnt = mntget(lower_dir_mnt); sdcardfs_set_lower_path(dentry, &lower_path); /* * If the intent is to create a file, then don't return an error, so * the VFS will continue the process of making this negative dentry * into a positive one. */ if (nd) { if (nd->flags & (LOOKUP_CREATE|LOOKUP_RENAME_TARGET)) err = 0; } else err = 0; out: return ERR_PTR(err); }