static struct dentry * proc_fdinfo_instantiate(struct inode *dir, struct dentry *dentry, struct task_struct *task, const void *ptr) { struct dentry *error = ERR_PTR(-ENOENT); unsigned fd = (unsigned long)ptr; struct proc_inode *ei; struct inode *inode; inode = proc_pid_make_inode(dir->i_sb, task); if (!inode) goto out; ei = PROC_I(inode); ei->fd = fd; inode->i_mode = S_IFREG | S_IRUSR; inode->i_fop = &proc_fdinfo_file_operations; d_set_d_op(dentry, &tid_fd_dentry_operations); d_add(dentry, inode); /* Close the race of the process dying before we return the dentry */ if (tid_fd_revalidate(dentry, 0)) error = NULL; out: return error; }
static int dumpfs_read_sb(struct super_block *sb, void *data, int silent) { int err = 0; struct inode *inode; struct buffer_head *bh; struct dumpfs_sb_info *sbi; dumpfs_super_block_t *ds; char *dev_name = (char *)data; if (!dev_name) { err = -EINVAL; goto out; } /* * dev_name is device_name or file that needs to be mounted * mount -t dumpfs /mnt/filename /mnt/dumpfs, dev_name points * to /mnt/filename. */ /* connect dumpfs superblock later */ sbi = kzalloc(sizeof(struct dumpfs_sb_info), GFP_KERNEL); if (!sbi) { err = -ENOMEM; goto out; } sb->s_fs_info = sbi; /* read the superblock from the disk */ if (!(bh = sb_bread(sb, 0))) { goto free; } ds = (dumpfs_super_block_t *)bh->b_data; sb->s_magic = ds->s_magic; sb->s_time_gran = 1; sb->s_op = &dumpfs_sops; sbi->s_buf = ds; printk(KERN_INFO "sbi->s_buf %p\n", sb->s_fs_info); inode = dumpfs_iget(sb, DUMPFS_ROOT_INUM); if (IS_ERR(inode)) { printk(KERN_INFO "%d \n", __LINE__); err = PTR_ERR(inode); goto out; } printk(KERN_INFO "inode %p magic %x\n", inode, ds->s_magic); sb->s_root = d_make_root(inode); if (!sb->s_root) { err = -ENOMEM; goto free; } d_rehash(sb->s_root); d_set_d_op(sb->s_root, &dumpfs_dops); goto out; free: printk(KERN_INFO "Failed free superblock"); kfree(sb->s_fs_info); out: return (err); }
static struct dentry *prlfs_lookup(struct inode *dir, struct dentry *dentry #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0) , unsigned int flags #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) , struct nameidata *nd #endif ) { int ret; struct prlfs_attr attr; struct inode *inode; DPRINTK("ENTER\n"); DPRINTK("dir ino %lld entry name \"%s\"\n", (u64)dir->i_ino, dentry->d_name.name); ret = do_prlfs_getattr(dentry, &attr); if (ret < 0 ) { if (ret == -ENOENT) { inode = NULL; ret = 0; } else goto out; } else { inode = prlfs_get_inode(dentry->d_sb, attr.mode); if (inode) prlfs_change_attributes(inode, &attr); } dentry->d_time = jiffies; d_add(dentry, inode); d_set_d_op(dentry, &prlfs_dentry_ops); out: DPRINTK("EXIT returning %d\n", ret); return ERR_PTR(ret); }
static int zpl_snapdir_mkdir(struct inode *dip, struct dentry *dentry, zpl_umode_t mode) { cred_t *cr = CRED(); vattr_t *vap; struct inode *ip; int error; crhold(cr); vap = kmem_zalloc(sizeof (vattr_t), KM_SLEEP); zpl_vap_init(vap, dip, mode | S_IFDIR, cr); error = -zfsctl_snapdir_mkdir(dip, dname(dentry), vap, &ip, cr, 0); if (error == 0) { d_clear_d_op(dentry); d_set_d_op(dentry, &zpl_dops_snapdirs); d_instantiate(dentry, ip); } kmem_free(vap, sizeof (vattr_t)); ASSERT3S(error, <=, 0); crfree(cr); return (error); }
zpl_snapdir_lookup(struct inode *dip, struct dentry *dentry, unsigned int flags) #endif { fstrans_cookie_t cookie; cred_t *cr = CRED(); struct inode *ip = NULL; int error; crhold(cr); cookie = spl_fstrans_mark(); error = -zfsctl_snapdir_lookup(dip, dname(dentry), &ip, 0, cr, NULL, NULL); ASSERT3S(error, <=, 0); spl_fstrans_unmark(cookie); crfree(cr); if (error && error != -ENOENT) return (ERR_PTR(error)); ASSERT(error == 0 || ip == NULL); d_clear_d_op(dentry); d_set_d_op(dentry, &zpl_dops_snapdirs); #ifdef HAVE_AUTOMOUNT dentry->d_flags |= DCACHE_NEED_AUTOMOUNT; #endif return (d_splice_alias(ip, dentry)); }
static struct dentry *proc_ns_instantiate(struct inode *dir, struct dentry *dentry, struct task_struct *task, const void *ptr) { const struct proc_ns_operations *ns_ops = ptr; struct inode *inode; struct proc_inode *ei; struct dentry *error = ERR_PTR(-ENOENT); void *ns; inode = proc_pid_make_inode(dir->i_sb, task); if (!inode) goto out; ns = ns_ops->get(task); if (!ns) goto out_iput; ei = PROC_I(inode); inode->i_mode = S_IFREG|S_IRUSR; inode->i_fop = &ns_file_operations; ei->ns_ops = ns_ops; ei->ns = ns; d_set_d_op(dentry, &pid_dentry_operations); d_add(dentry, inode); /* Close the race of the process dying before we return the dentry */ if (pid_revalidate(dentry, 0)) error = NULL; out: return error; out_iput: iput(inode); goto out; }
static int proc_fd_instantiate(struct inode *dir, struct dentry *dentry, struct task_struct *task, const void *ptr) { unsigned fd = (unsigned long)ptr; struct proc_inode *ei; struct inode *inode; inode = proc_pid_make_inode(dir->i_sb, task); if (!inode) goto out; ei = PROC_I(inode); ei->fd = fd; inode->i_mode = S_IFLNK; inode->i_op = &proc_pid_link_inode_operations; inode->i_size = 64; ei->op.proc_get_link = proc_fd_link; d_set_d_op(dentry, &tid_fd_dentry_operations); d_add(dentry, inode); /* Close the race of the process dying before we return the dentry */ if (tid_fd_revalidate(dentry, 0)) return 0; out: return -ENOENT; }
zpl_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) #endif { cred_t *cr = CRED(); struct inode *ip; int error; fstrans_cookie_t cookie; if (dlen(dentry) > ZFS_MAXNAMELEN) return (ERR_PTR(-ENAMETOOLONG)); crhold(cr); cookie = spl_fstrans_mark(); error = -zfs_lookup(dir, dname(dentry), &ip, 0, cr, NULL, NULL); spl_fstrans_unmark(cookie); ASSERT3S(error, <=, 0); crfree(cr); spin_lock(&dentry->d_lock); dentry->d_time = jiffies; #ifndef HAVE_S_D_OP d_set_d_op(dentry, &zpl_dentry_operations); #endif /* HAVE_S_D_OP */ spin_unlock(&dentry->d_lock); if (error) { if (error == -ENOENT) return (d_splice_alias(NULL, dentry)); else return (ERR_PTR(error)); } return (d_splice_alias(ip, dentry)); }
/* * Lookup the data. This is trivial - if the dentry didn't already * exist, we know it is negative. Set d_op to delete negative dentries. */ struct dentry *simple_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) { if (dentry->d_name.len > NAME_MAX) return ERR_PTR(-ENAMETOOLONG); if (!dentry->d_sb->s_d_op) d_set_d_op(dentry, &simple_dentry_operations); d_add(dentry, NULL); return NULL; }
static struct dentry *proc_sys_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { struct ctl_table_header *head = grab_header(dir); struct ctl_table *table = PROC_I(dir)->sysctl_entry; struct ctl_table_header *h = NULL; struct qstr *name = &dentry->d_name; struct ctl_table *p; struct inode *inode; struct dentry *err = ERR_PTR(-ENOENT); if (IS_ERR(head)) return ERR_CAST(head); if (table && !table->child) { WARN_ON(1); goto out; } table = table ? table->child : head->ctl_table; p = find_in_table(table, name); if (!p) { for (h = sysctl_head_next(NULL); h; h = sysctl_head_next(h)) { if (h->attached_to != table) continue; p = find_in_table(h->attached_by, name); if (p) break; } } if (!p) goto out; if (gr_handle_sysctl(p, MAY_EXEC)) goto out; err = ERR_PTR(-ENOMEM); inode = proc_sys_make_inode(dir->i_sb, h ? h : head, p); if (h) sysctl_head_finish(h); if (!inode) goto out; err = NULL; d_set_d_op(dentry, &proc_sys_dentry_operations); d_add(dentry, inode); out: sysctl_head_finish(head); return err; }
/* * Lookup the data. This is trivial - if the dentry didn't already * exist, we know it is negative. Set d_op to delete negative dentries. */ struct dentry *simple_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { static const struct dentry_operations simple_dentry_operations = { .d_delete = simple_delete_dentry, }; if (dentry->d_name.len > NAME_MAX) return ERR_PTR(-ENAMETOOLONG); d_set_d_op(dentry, &simple_dentry_operations); d_add(dentry, NULL); return NULL; }
/** * \<\<public\>\> This method is used when initializing a new entry. * It follows these steps: * * - converts the nameformat string and the args into a regular string * This will be the name assigned to the dentry * - checks whether we have a valid parent directory * - check whether an entry with the same name already exists * in the parent directory entry(if so, an error is returned) * - creates a new inode with the specified super block and operations * - creates a new dentry associated with the inode. * - sets a entry_operations specific to this particular entry type * This supports polymorphism. * * @param *self - pointer to this instance * @param *parent - pointer to the parent entry - has to be a directory * @param *mode - file type and access rights for the inode * @param *entry_ops - custom operations of the child class * @param *i_ops - inode operations * @param *f_ops - file operations(also stored in the new inode) * @param namefmt - nameformat string (printf style) * @param args - arguments to the format string * @return 0 upon success */ int tcmi_ctlfs_entry_init(struct tcmi_ctlfs_entry *self, struct tcmi_ctlfs_entry *parent, mode_t mode, struct tcmi_ctlfs_ops *entry_ops, const struct inode_operations *i_ops, const struct file_operations *f_ops, const char namefmt[], va_list args) { struct inode *dir; struct inode *inode; vsnprintf(self->name, sizeof(self->name), namefmt, args); mdbg(INFO4, "Initializing a new tcmi_ctlfs_entry, '%s'(%p)", self->name, self); if (!parent) { mdbg(ERR4, "Can't initialized new entry '%s', no parent specified! ", self->name); goto exit0; } mdbg(INFO4, "Parent entry='%s'", tcmi_ctlfs_entry_name(parent)); /* */ dir = parent->dentry->d_inode; if (!S_ISDIR(dir->i_mode)) { mdbg(ERR3, "Can't initialize new entry '%s', parent entry is not a directory!", self->name); goto exit0; } /* check parent for an entry with 'name' */ if (tcmi_ctlfs_entry_exists(parent, self->name)) { mdbg(ERR3,"Can't initialize new entry '%s', parent entry contains an entry of the same name!", self->name); goto exit0; } /* allocate a new inode */ if (!(inode = tcmi_ctlfs_get_inode(dir, dir->i_sb, mode, i_ops, f_ops))) { mdbg(ERR3, "Failed to allocate an inode for '%s'", self->name); goto exit0; } /* allocate a new dentry, associated with the inode */ if (tcmi_ctlfs_entry_alloc_dentry(self, parent, inode)) { mdbg(ERR3, "Failed to allocate a new dentry for %s", self->name); goto exit1; } /* Custom operations of the child class */ self->entry_ops = entry_ops; d_set_d_op(self->dentry, self->dentry->d_op); //Fix for new kernel, this function set dentry->flags according to dentry->op | by Jiri Rakosnik return 0; /* error handling */ exit1: iput(inode); exit0: return -ENOSPC; }
/* * Initialize ceph dentry state. */ int ceph_init_dentry(struct dentry *dentry) { struct ceph_dentry_info *di; if (dentry->d_fsdata) return 0; di = kmem_cache_zalloc(ceph_dentry_cachep, GFP_KERNEL); if (!di) return -ENOMEM; /* oh well */ spin_lock(&dentry->d_lock); if (dentry->d_fsdata) { /* lost a race */ kmem_cache_free(ceph_dentry_cachep, di); goto out_unlock; } if (ceph_snap(d_inode(dentry->d_parent)) == CEPH_NOSNAP) d_set_d_op(dentry, &ceph_dentry_ops); else if (ceph_snap(d_inode(dentry->d_parent)) == CEPH_SNAPDIR) d_set_d_op(dentry, &ceph_snapdir_dentry_ops); else d_set_d_op(dentry, &ceph_snap_dentry_ops); di->dentry = dentry; di->lease_session = NULL; di->time = jiffies; /* avoid reordering d_fsdata setup so that the check above is safe */ smp_mb(); dentry->d_fsdata = di; ceph_dentry_lru_add(dentry); out_unlock: spin_unlock(&dentry->d_lock); return 0; }
int __fscrypt_prepare_lookup(struct inode *dir, struct dentry *dentry) { int err = fscrypt_get_encryption_info(dir); if (err) return err; if (fscrypt_has_encryption_key(dir)) { spin_lock(&dentry->d_lock); dentry->d_flags |= DCACHE_ENCRYPTED_WITH_KEY; spin_unlock(&dentry->d_lock); } d_set_d_op(dentry, &fscrypt_d_ops); return 0; }
int reiserfs_lookup_privroot(struct super_block *s) { struct dentry *dentry; int err = 0; /* If we don't have the privroot located yet - go find it */ reiserfs_mutex_lock_safe(&s->s_root->d_inode->i_mutex, s); dentry = lookup_one_len(PRIVROOT_NAME, s->s_root, strlen(PRIVROOT_NAME)); if (!IS_ERR(dentry)) { REISERFS_SB(s)->priv_root = dentry; d_set_d_op(dentry, &xattr_lookup_poison_ops); if (dentry->d_inode) dentry->d_inode->i_flags |= S_PRIVATE; } else err = PTR_ERR(dentry); mutex_unlock(&s->s_root->d_inode->i_mutex); return err; }
static int proc_ns_instantiate(struct inode *dir, struct dentry *dentry, struct task_struct *task, const void *ptr) { const struct proc_ns_operations *ns_ops = ptr; struct inode *inode; struct proc_inode *ei; inode = proc_pid_make_inode(dir->i_sb, task, S_IFLNK | S_IRWXUGO); if (!inode) goto out; ei = PROC_I(inode); inode->i_op = &proc_ns_link_inode_operations; ei->ns_ops = ns_ops; d_set_d_op(dentry, &pid_dentry_operations); d_add(dentry, inode); /* Close the race of the process dying before we return the dentry */ if (pid_revalidate(dentry, 0)) return 0; out: return -ENOENT; }
static int proc_sys_fill_cache(struct file *filp, void *dirent, filldir_t filldir, struct ctl_table_header *head, struct ctl_table *table) { struct dentry *child, *dir = filp->f_path.dentry; struct inode *inode; struct qstr qname; ino_t ino = 0; unsigned type = DT_UNKNOWN; qname.name = table->procname; qname.len = strlen(table->procname); qname.hash = full_name_hash(qname.name, qname.len); child = d_lookup(dir, &qname); if (!child) { child = d_alloc(dir, &qname); if (child) { inode = proc_sys_make_inode(dir->d_sb, head, table); if (!inode) { dput(child); return -ENOMEM; } else { d_set_d_op(child, &proc_sys_dentry_operations); d_add(child, inode); } } else { return -ENOMEM; } } inode = child->d_inode; ino = inode->i_ino; type = inode->i_mode >> 12; dput(child); return !!filldir(dirent, qname.name, qname.len, filp->f_pos, ino, type); }
/* * 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; }
/* * There is no need to lock the wrapfs_super_info's rwsem as there is no * way anyone can have a reference to the superblock at this point in time. */ static int wrapfs_read_super(struct super_block *sb, void *raw_data, int silent) { int err = 0, i = 0; struct wrapfs_dentry_info *lower_root_info = NULL; struct inode *inode = NULL; if (!raw_data) { printk(KERN_ERR "u2fs: read_super: missing data argument\n"); err = -EINVAL; goto out; } /* allocate superblock private data */ sb->s_fs_info = kzalloc(sizeof(struct wrapfs_sb_info), GFP_KERNEL); if (!WRAPFS_SB(sb)) { printk(KERN_CRIT "u2fs: read_super: out of memory\n"); err = -ENOMEM; goto out_free; } atomic_set(&WRAPFS_SB(sb)->generation, 1); WRAPFS_SB(sb)->high_branch_id = -1; /* Parsing the Inputs */ lower_root_info = wrapfs_parse_options(sb, raw_data); if (IS_ERR(lower_root_info)) { printk(KERN_ERR "u2fs: read_super: error while parsing options" "(err = %ld)\n", PTR_ERR(lower_root_info)); err = PTR_ERR(lower_root_info); lower_root_info = NULL; goto out_free; } /* set the lower superblock field of upper superblock */ for (i = 0; i <= 1; i++) { struct dentry *d = lower_root_info->lower_paths[i].dentry; atomic_inc(&d->d_sb->s_active); wrapfs_set_lower_super_idx(sb, i, d->d_sb); } /* inherit maxbytes from highest priority branch */ sb->s_maxbytes = wrapfs_lower_super_idx(sb, 0)->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 = &wrapfs_sops; /* get a new inode and allocate our root dentry */ inode = wrapfs_new_iget(sb, iunique(sb, 1)); if (IS_ERR(inode)) { err = PTR_ERR(inode); goto out_sput; } sb->s_root = d_alloc_root(inode); if (unlikely(!sb->s_root)) { err = -ENOMEM; goto out_iput; } d_set_d_op(sb->s_root, &wrapfs_dops); /* link the upper and lower dentries */ sb->s_root->d_fsdata = NULL; err = new_dentry_private_data(sb->s_root); if (unlikely(err)) goto out_freeroot; /* if get here: cannot have error */ /* set the lower dentries for s_root */ for (i = 0; i <= 1 ; i++) { struct dentry *d; struct vfsmount *m; d = lower_root_info->lower_paths[i].dentry; m = lower_root_info->lower_paths[i].mnt; wrapfs_set_lower_dentry_idx(sb->s_root, i, d); wrapfs_set_lower_mnt_idx(sb->s_root, i, m); } atomic_set(&WRAPFS_D(sb->s_root)->generation, 1); if (atomic_read(&inode->i_count) <= 1) wrapfs_fill_inode(sb->s_root, inode); /* * No need to call interpose because we already have a positive * dentry, which was instantiated by d_alloc_root. Just need to * d_rehash it. */ d_rehash(sb->s_root); if (!silent) printk(KERN_INFO "u2fs: mounted on top of type\n"); goto out; /* all is well */ /* no longer needed: free_dentry_private_data(sb->s_root); */ out_freeroot: if (WRAPFS_D(sb->s_root)) { kfree(WRAPFS_D(sb->s_root)->lower_paths); free_dentry_private_data(sb->s_root); } dput(sb->s_root); out_iput: iput(inode); out_sput: /* drop refs we took earlier */ if (lower_root_info && !IS_ERR(lower_root_info)) { for (i = 0; i <= 1; i++) { struct dentry *d; d = lower_root_info->lower_paths[i].dentry; atomic_dec(&d->d_sb->s_active); path_put(&lower_root_info->lower_paths[i]); } kfree(lower_root_info->lower_paths); kfree(lower_root_info); lower_root_info = NULL; } out_free: kfree(WRAPFS_SB(sb)->data); kfree(WRAPFS_SB(sb)); sb->s_fs_info = NULL; out: if (lower_root_info && !IS_ERR(lower_root_info)) { kfree(lower_root_info->lower_paths); kfree(lower_root_info); } return err; }
zpl_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) #endif { cred_t *cr = CRED(); struct inode *ip; int error; fstrans_cookie_t cookie; pathname_t *ppn = NULL; pathname_t pn; zfs_sb_t *zsb = dentry->d_sb->s_fs_info; if (dlen(dentry) > ZFS_MAXNAMELEN) return (ERR_PTR(-ENAMETOOLONG)); crhold(cr); cookie = spl_fstrans_mark(); /* If we are a case insensitive fs, we need the real name */ if (zsb->z_case == ZFS_CASE_INSENSITIVE) { pn.pn_bufsize = ZFS_MAXNAMELEN; pn.pn_buf = kmem_zalloc(ZFS_MAXNAMELEN, KM_SLEEP); ppn = &pn; } error = -zfs_lookup(dir, dname(dentry), &ip, 0, cr, NULL, ppn); spl_fstrans_unmark(cookie); ASSERT3S(error, <=, 0); crfree(cr); spin_lock(&dentry->d_lock); dentry->d_time = jiffies; #ifndef HAVE_S_D_OP d_set_d_op(dentry, &zpl_dentry_operations); #endif /* HAVE_S_D_OP */ spin_unlock(&dentry->d_lock); if (error) { if (ppn) kmem_free(pn.pn_buf, ZFS_MAXNAMELEN); if (error == -ENOENT) return (d_splice_alias(NULL, dentry)); else return (ERR_PTR(error)); } /* * If we are case insensitive, call the correct function * to install the name. */ if (ppn) { struct dentry *new_dentry; struct qstr ci_name; ci_name.name = pn.pn_buf; ci_name.len = strlen(pn.pn_buf); new_dentry = d_add_ci(dentry, ip, &ci_name); kmem_free(pn.pn_buf, ZFS_MAXNAMELEN); return (new_dentry); } else { return (d_splice_alias(ip, dentry)); } }
zpl_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) #endif { cred_t *cr = CRED(); struct inode *ip; int error; fstrans_cookie_t cookie; pathname_t *ppn = NULL; pathname_t pn; int zfs_flags = 0; zfs_sb_t *zsb = dentry->d_sb->s_fs_info; if (dlen(dentry) > ZFS_MAX_DATASET_NAME_LEN) return (ERR_PTR(-ENAMETOOLONG)); crhold(cr); cookie = spl_fstrans_mark(); /* If we are a case insensitive fs, we need the real name */ if (zsb->z_case == ZFS_CASE_INSENSITIVE) { zfs_flags = FIGNORECASE; pn_alloc(&pn); ppn = &pn; } error = -zfs_lookup(dir, dname(dentry), &ip, zfs_flags, cr, NULL, ppn); spl_fstrans_unmark(cookie); ASSERT3S(error, <=, 0); crfree(cr); spin_lock(&dentry->d_lock); dentry->d_time = jiffies; #ifndef HAVE_S_D_OP d_set_d_op(dentry, &zpl_dentry_operations); #endif /* HAVE_S_D_OP */ spin_unlock(&dentry->d_lock); if (error) { /* * If we have a case sensitive fs, we do not want to * insert negative entries, so return NULL for ENOENT. * Fall through if the error is not ENOENT. Also free memory. */ if (ppn) { pn_free(ppn); if (error == -ENOENT) return (NULL); } if (error == -ENOENT) return (d_splice_alias(NULL, dentry)); else return (ERR_PTR(error)); } /* * If we are case insensitive, call the correct function * to install the name. */ if (ppn) { struct dentry *new_dentry; struct qstr ci_name; ci_name.name = pn.pn_buf; ci_name.len = strlen(pn.pn_buf); new_dentry = d_add_ci(dentry, ip, &ci_name); pn_free(ppn); return (new_dentry); } else { return (d_splice_alias(ip, dentry)); } }
/** * This should allocate memory for sf_inode_info, compute a unique inode * number, get an inode from vfs, initialize inode info, instantiate * dentry. * * @param parent inode entry of the directory * @param dentry directory cache entry * @param path path name * @param info file information * @param handle handle * @returns 0 on success, Linux error code otherwise */ static int sf_instantiate(struct inode *parent, struct dentry *dentry, SHFLSTRING *path, PSHFLFSOBJINFO info, SHFLHANDLE handle) { int err; ino_t ino; struct inode *inode; struct sf_inode_info *sf_new_i; struct sf_glob_info *sf_g = GET_GLOB_INFO(parent->i_sb); TRACE(); BUG_ON(!sf_g); sf_new_i = kmalloc(sizeof(*sf_new_i), GFP_KERNEL); if (!sf_new_i) { LogRelFunc(("could not allocate inode info.\n")); err = -ENOMEM; goto fail0; } ino = iunique(parent->i_sb, 1); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25) inode = iget_locked(parent->i_sb, ino); #else inode = iget(parent->i_sb, ino); #endif if (!inode) { LogFunc(("iget failed\n")); err = -ENOMEM; goto fail1; } sf_init_inode(sf_g, inode, info); sf_new_i->path = path; SET_INODE_INFO(inode, sf_new_i); dentry->d_time = jiffies; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38) d_set_d_op(dentry, &sf_dentry_ops); #else dentry->d_op = &sf_dentry_ops; #endif sf_new_i->force_restat = 1; sf_new_i->force_reread = 0; d_instantiate(dentry, inode); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25) unlock_new_inode(inode); #endif /* Store this handle if we leave the handle open. */ sf_new_i->handle = handle; return 0; fail1: kfree(sf_new_i); fail0: 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; //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; }
/** * This is called when vfs failed to locate dentry in the cache. The * job of this function is to allocate inode and link it to dentry. * [dentry] contains the name to be looked in the [parent] directory. * Failure to locate the name is not a "hard" error, in this case NULL * inode is added to [dentry] and vfs should proceed trying to create * the entry via other means. NULL(or "positive" pointer) ought to be * returned in case of success and "negative" pointer on error */ static struct dentry *sf_lookup(struct inode *parent, struct dentry *dentry #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) , unsigned int flags #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) , struct nameidata *nd #endif ) { int err; struct sf_inode_info *sf_i, *sf_new_i; struct sf_glob_info *sf_g; SHFLSTRING *path; struct inode *inode; ino_t ino; SHFLFSOBJINFO fsinfo; TRACE(); sf_g = GET_GLOB_INFO(parent->i_sb); sf_i = GET_INODE_INFO(parent); BUG_ON(!sf_g); BUG_ON(!sf_i); err = sf_path_from_dentry(__func__, sf_g, sf_i, dentry, &path); if (err) goto fail0; err = sf_stat(__func__, sf_g, path, &fsinfo, 1); if (err) { if (err == -ENOENT) { /* -ENOENT: add NULL inode to dentry so it later can be created via call to create/mkdir/open */ kfree(path); inode = NULL; } else goto fail1; } else { sf_new_i = kmalloc(sizeof(*sf_new_i), GFP_KERNEL); if (!sf_new_i) { LogRelFunc(("could not allocate memory for new inode info\n")); err = -ENOMEM; goto fail1; } sf_new_i->handle = SHFL_HANDLE_NIL; sf_new_i->force_reread = 0; ino = iunique(parent->i_sb, 1); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25) inode = iget_locked(parent->i_sb, ino); #else inode = iget(parent->i_sb, ino); #endif if (!inode) { LogFunc(("iget failed\n")); err = -ENOMEM; /* XXX: ??? */ goto fail2; } SET_INODE_INFO(inode, sf_new_i); sf_init_inode(sf_g, inode, &fsinfo); sf_new_i->path = path; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25) unlock_new_inode(inode); #endif } sf_i->force_restat = 0; dentry->d_time = jiffies; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38) d_set_d_op(dentry, &sf_dentry_ops); #else dentry->d_op = &sf_dentry_ops; #endif d_add(dentry, inode); return NULL; fail2: kfree(sf_new_i); fail1: kfree(path); fail0: 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(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 sdcardfskk's lookup. * * Returns: NULL (ok), ERR_PTR if an error occurred. * Fills in lower_parent_path with <dentry,mnt> on success. */ static struct dentry *__sdcardfskk_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 nameidata lower_nd; struct path lower_path; struct qstr this; struct sdcardfskk_sb_info *sbi; sbi = SDCARDFSKK_SB(dentry->d_sb); /* must initialize dentry operations */ d_set_d_op(dentry, &sdcardfskk_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); } /* 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_kitkat(dentry)) { /* setup_obb_dentry_kitkat() * 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_kitkat(dentry, &lower_nd.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 "sdcardfskk: base obbpath is not available\n"); sdcardfskk_put_reset_orig_path(dentry); goto out; } } sdcardfskk_set_lower_path(dentry, &lower_nd.path); err = sdcardfskk_interpose(dentry, dentry->d_sb, &lower_nd.path); if (err) /* path_put underlying path on error */ sdcardfskk_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); sdcardfskk_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); }
/* * Main driver function for wrapfs's lookup. * * Returns: NULL (ok), ERR_PTR if an error occurred. * Fills in lower_parent_path with <dentry,mnt> on success. */ static struct dentry *__wrapfs_lookup(struct dentry *dentry, int flags, 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, &wrapfs_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) { wrapfs_set_lower_path(dentry, &lower_path); err = wrapfs_interpose(dentry, dentry->d_sb, &lower_path); if (err) /* path_put underlying path on error */ wrapfs_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); wrapfs_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 (flags & (LOOKUP_CREATE|LOOKUP_RENAME_TARGET)) err = 0; out: return ERR_PTR(err); }
/* * There is no need to lock the wrapfs_super_info's rwsem as there is no * way anyone can have a reference to the superblock at this point in time. */ static int wrapfs_read_super(struct super_block *sb, void *raw_data, int silent) { int err = 0; struct super_block *lower_sb; struct path lower_path; char *dev_name = (char *) raw_data; struct inode *inode; if (!dev_name) { printk(KERN_ERR "wrapfs: read_super: missing dev_name argument\n"); err = -EINVAL; goto out; } /* parse lower path */ err = kern_path(dev_name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &lower_path); if (err) { printk(KERN_ERR "wrapfs: error accessing " "lower directory '%s'\n", dev_name); goto out; } /* allocate superblock private data */ sb->s_fs_info = kzalloc(sizeof(struct wrapfs_sb_info), GFP_KERNEL); if (!WRAPFS_SB(sb)) { printk(KERN_CRIT "wrapfs: read_super: out of memory\n"); err = -ENOMEM; goto out_free; } /* set the lower superblock field of upper superblock */ lower_sb = lower_path.dentry->d_sb; atomic_inc(&lower_sb->s_active); wrapfs_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 = &wrapfs_sops; /* get a new inode and allocate our root dentry */ inode = wrapfs_iget(sb, lower_path.dentry->d_inode); if (IS_ERR(inode)) { err = PTR_ERR(inode); goto out_sput; } sb->s_root = d_alloc_root(inode); if (!sb->s_root) { err = -ENOMEM; goto out_iput; } d_set_d_op(sb->s_root, &wrapfs_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; /* if get here: cannot have error */ /* set the lower dentries for s_root */ wrapfs_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_alloc_root. Just need to * d_rehash it. */ d_rehash(sb->s_root); if (!silent) printk(KERN_INFO "wrapfs: 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); kfree(WRAPFS_SB(sb)); sb->s_fs_info = NULL; out_free: path_put(&lower_path); out: return err; }
/* * Connect a unionfs inode dentry/inode with several lower ones. This is * the classic stackable file system "vnode interposition" action. * * @sb: unionfs's super_block */ struct dentry *unionfs_interpose(struct dentry *dentry, struct super_block *sb, int flag) { int err = 0; struct inode *inode; int need_fill_inode = 1; struct dentry *spliced = NULL; verify_locked(dentry); /* * We allocate our new inode below by calling unionfs_iget, * which will initialize some of the new inode's fields */ /* * On revalidate we've already got our own inode and just need * to fix it up. */ if (flag == INTERPOSE_REVAL) { inode = dentry->d_inode; UNIONFS_I(inode)->bstart = -1; UNIONFS_I(inode)->bend = -1; atomic_set(&UNIONFS_I(inode)->generation, atomic_read(&UNIONFS_SB(sb)->generation)); UNIONFS_I(inode)->lower_inodes = kcalloc(sbmax(sb), sizeof(struct inode *), GFP_KERNEL); if (unlikely(!UNIONFS_I(inode)->lower_inodes)) { err = -ENOMEM; goto out; } } else { /* get unique inode number for unionfs */ inode = unionfs_iget(sb, iunique(sb, UNIONFS_ROOT_INO)); if (IS_ERR(inode)) { err = PTR_ERR(inode); goto out; } if (atomic_read(&inode->i_count) > 1) goto skip; } need_fill_inode = 0; unionfs_fill_inode(dentry, inode); skip: /* only (our) lookup wants to do a d_add */ switch (flag) { case INTERPOSE_DEFAULT: /* for operations which create new inodes */ d_add(dentry, inode); break; case INTERPOSE_REVAL_NEG: d_instantiate(dentry, inode); break; case INTERPOSE_LOOKUP: spliced = d_splice_alias(inode, dentry); if (spliced && spliced != dentry) { /* * d_splice can return a dentry if it was * disconnected and had to be moved. We must ensure * that the private data of the new dentry is * correct and that the inode info was filled * properly. Finally we must return this new * dentry. */ d_set_d_op(spliced, &unionfs_dops); spliced->d_fsdata = dentry->d_fsdata; dentry->d_fsdata = NULL; dentry = spliced; if (need_fill_inode) { need_fill_inode = 0; unionfs_fill_inode(dentry, inode); } goto out_spliced; } else if (!spliced) { if (need_fill_inode) { need_fill_inode = 0; unionfs_fill_inode(dentry, inode); goto out_spliced; } } break; case INTERPOSE_REVAL: /* Do nothing. */ break; default: printk(KERN_CRIT "unionfs: invalid interpose flag passed!\n"); BUG(); } goto out; out_spliced: if (!err) return spliced; out: return ERR_PTR(err); }