//----------------------------------------------------------------------------- // Populates directory //----------------------------------------------------------------------------- static struct dentry * janfs_create_file(struct super_block *sb, struct dentry *dir, struct FileDesc desc) { struct dentry* dentry; struct inode *i; struct qstr hname; // Hashed version of the name hname.name = desc.name; hname.len = strlen (desc.name); hname.hash = full_name_hash(desc.name, hname.len); // Create dentry and the inode to associate with it dentry = d_alloc(dir, &hname); if (!dentry) goto out_err; i = janfs_get_inode(sb, NULL, S_IFREG | 0755, 0); if (!i) goto out_err_put; // Add inode to dentry cache d_add(dentry, i); printk("janfs_create_file created name[%s], type[%c], size[%lu].\n", desc.name, desc.type, desc.size); return dentry; out_err_put: dput(dentry); out_err: return 0; }
/** * tacafs_create_dentry - Crea una entrada al sistema de fitxers * * Crea el dentry i inode corresponents i els posa a la dentry cache * Retorna el dentry generat o l'error corresponent (IS_ERR, PTR_ERR). **/ static inline struct dentry *tacafs_create_dentry (struct super_block *sb, struct dentry *dir, int inobase, const char *name, int mode, void *data, int datasize, struct inode_operations *iops, struct dentry_operations *dops, struct file_operations *fops) { struct dentry *dentry, *res; struct qstr qname; /* Versio amb hash del nom per anar a la dentry cache */ qname.name = name; qname.len = strlen (name); qname.hash = full_name_hash(name, qname.len); /* Creem el dentry */ dentry = d_alloc(dir, &qname); if (!dentry) return ERR_PTR(-ENOMEM); /* Creem i omplim l'inode que hi associem */ res = tacafs_fill_dentry (sb, dentry, inobase, mode, data, datasize, iops, dops, fops); if (!res) res = dentry; else dput(dentry); return res; }
/** * ecryptfs_new_lower_dentry * @name: The name of the new dentry. * @lower_dir_dentry: Parent directory of the new dentry. * @nd: nameidata from last lookup. * * Create a new dentry or get it from lower parent dir. */ static struct dentry * ecryptfs_new_lower_dentry(struct qstr *name, struct dentry *lower_dir_dentry, struct nameidata *nd) { struct dentry *new_dentry; struct dentry *tmp; struct inode *lower_dir_inode; lower_dir_inode = lower_dir_dentry->d_inode; tmp = d_alloc(lower_dir_dentry, name); if (!tmp) return ERR_PTR(-ENOMEM); mutex_lock(&lower_dir_inode->i_mutex); new_dentry = lower_dir_inode->i_op->lookup(lower_dir_inode, tmp, nd); mutex_unlock(&lower_dir_inode->i_mutex); if (!new_dentry) new_dentry = tmp; else dput(tmp); return new_dentry; }
/* * Lookup or create a dentry from within the filesystem. * * We need to use this instead of lookup_dentry, as the * directory semaphore lock is already held. */ struct dentry *umsdos_lookup_dentry(struct dentry *parent, char *name, int len, int real) { struct dentry *result, *dentry; struct qstr qstr; qstr.name = name; qstr.len = len; qstr.hash = full_name_hash(name, len); result = d_lookup(parent, &qstr); if (!result) { result = ERR_PTR(-ENOMEM); dentry = d_alloc(parent, &qstr); if (dentry) { result = real ? UMSDOS_rlookup(parent->d_inode, dentry) : UMSDOS_lookup(parent->d_inode, dentry); if (result) goto out_fail; return dentry; } } out: return result; out_fail: dput(dentry); goto out; }
struct dentry *umsdos_covered(struct dentry *parent, char *name, int len) { struct dentry *result, *dentry; struct qstr qstr; qstr.name = name; qstr.len = len; qstr.hash = full_name_hash(name, len); result = ERR_PTR(-ENOMEM); dentry = d_alloc(parent, &qstr); if (dentry) { /* XXXXXXXXXXXXXXXXXXX Race alert! */ result = UMSDOS_rlookup(parent->d_inode, dentry); d_drop(dentry); if (result) goto out_fail; return dentry; } out: return result; out_fail: dput(dentry); goto out; }
static struct dentry *vperfctr_d_alloc_root(struct inode *inode) { struct qstr this; char name[32]; struct dentry *dentry; sprintf(name, "[%lu]", inode->i_ino); this.name = name; this.len = strlen(name); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) this.hash = 0; #else this.hash = inode->i_ino; /* will go */ #endif dentry = d_alloc(vperfctr_mnt->mnt_sb->s_root, &this); if (dentry) { dentry->d_op = &vperfctrfs_dentry_operations; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) /* * We dont want to publish this dentry into global dentry hash table. * We pretend dentry is already hashed, by unsetting DCACHE_UNHASHED * This permits a working /proc/$pid/fd/XXX on vperfctrs */ dentry->d_flags &= ~DCACHE_UNHASHED; d_instantiate(dentry, inode); #else d_add(dentry, inode); #endif } return dentry; }
/** * anon_inode_getfd - creates a new file instance by hooking it up to an * anonymous inode, and a dentry that describe the "class" * of the file * * @name: [in] name of the "class" of the new file * @fops: [in] file operations for the new file * @priv: [in] private data for the new file (will be file's private_data) * @flags: [in] flags * * Creates a new file by hooking it on a single inode. This is useful for files * that do not need to have a full-fledged inode in order to operate correctly. * All the files created with anon_inode_getfile() will share a single inode, * hence saving memory and avoiding code duplication for the file/inode/dentry * setup. Returns the newly created file* or an error pointer. */ struct file *anon_inode_getfile(const char *name, const struct file_operations *fops, void *priv, int flags) { struct qstr this; struct dentry *dentry; struct file *file; int error; if (IS_ERR(anon_inode_inode)) return ERR_PTR(-ENODEV); if (fops->owner && !try_module_get(fops->owner)) return ERR_PTR(-ENOENT); /* * Link the inode to a directory entry by creating a unique name * using the inode sequence number. */ error = -ENOMEM; this.name = name; this.len = strlen(name); this.hash = 0; dentry = d_alloc(anon_inode_mnt->mnt_sb->s_root, &this); if (!dentry) goto err_module; /* * We know the anon_inode inode count is always greater than zero, * so we can avoid doing an igrab() and we can use an open-coded * atomic_inc(). */ atomic_inc(&anon_inode_inode->i_count); dentry->d_op = &anon_inodefs_dentry_operations; /* Do not publish this dentry inside the global dentry hash table */ dentry->d_flags &= ~DCACHE_UNHASHED; d_instantiate(dentry, anon_inode_inode); error = -ENFILE; file = alloc_file(anon_inode_mnt, dentry, FMODE_READ | FMODE_WRITE, fops); if (!file) goto err_dput; file->f_mapping = anon_inode_inode->i_mapping; file->f_pos = 0; file->f_flags = O_RDWR | (flags & O_NONBLOCK); file->f_version = 0; file->private_data = priv; return file; err_dput: dput(dentry); err_module: module_put(fops->owner); return ERR_PTR(error); }
int dcache_dir_open(struct inode *inode, struct file *file) { static struct qstr cursor_name = QSTR_INIT(".", 1); file->private_data = d_alloc(file->f_path.dentry, &cursor_name); return file->private_data ? 0 : -ENOMEM; }
/** * anon_inode_getfd - creates a new file instance by hooking it up to an * anonymous inode, and a dentry that describe the "class" * of the file * * @name: [in] name of the "class" of the new file * @fops: [in] file operations for the new file * @priv: [in] private data for the new file (will be file's private_data) * @flags: [in] flags * * Creates a new file by hooking it on a single inode. This is useful for files * that do not need to have a full-fledged inode in order to operate correctly. * All the files created with anon_inode_getfile() will share a single inode, * hence saving memory and avoiding code duplication for the file/inode/dentry * setup. Returns the newly created file* or an error pointer. */ struct file *anon_inode_getfile(const char *name, const struct file_operations *fops, void *priv, int flags) { struct qstr this; struct path path; struct file *file; int error; if (IS_ERR(anon_inode_inode)) return ERR_PTR(-ENODEV); if (fops->owner && !try_module_get(fops->owner)) return ERR_PTR(-ENOENT); /* * Link the inode to a directory entry by creating a unique name * using the inode sequence number. */ error = -ENOMEM; this.name = name; this.len = strlen(name); this.hash = 0; path.dentry = d_alloc(anon_inode_mnt->mnt_sb->s_root, &this); if (!path.dentry) goto err_module; path.mnt = mntget(anon_inode_mnt); /* * We know the anon_inode inode count is always greater than zero, * so we can avoid doing an igrab() and we can use an open-coded * atomic_inc(). */ atomic_inc(&anon_inode_inode->i_count); path.dentry->d_op = &anon_inodefs_dentry_operations; d_instantiate(path.dentry, anon_inode_inode); error = -ENFILE; file = alloc_file(&path, OPEN_FMODE(flags), fops); if (!file) goto err_dput; file->f_mapping = anon_inode_inode->i_mapping; file->f_pos = 0; file->f_flags = flags & (O_ACCMODE | O_NONBLOCK); file->f_version = 0; file->private_data = priv; return file; err_dput: path_put(&path); err_module: module_put(fops->owner); return ERR_PTR(error); }
/* * Find the dentry that matches "name". If there isn't one, create one. If it's * a negative dentry or the uniqueid changed, then drop it and recreate it. */ static struct dentry * cifs_readdir_lookup(struct dentry *parent, struct qstr *name, struct cifs_fattr *fattr) { struct dentry *dentry, *alias; struct inode *inode; struct super_block *sb = parent->d_inode->i_sb; cFYI(1, "For %s", name->name); if (parent->d_op && parent->d_op->d_hash) parent->d_op->d_hash(parent, parent->d_inode, name); else name->hash = full_name_hash(name->name, name->len); dentry = d_lookup(parent, name); if (dentry) { inode = dentry->d_inode; /* update inode in place if i_ino didn't change */ if (inode && CIFS_I(inode)->uniqueid == fattr->cf_uniqueid) { cifs_fattr_to_inode(inode, fattr); return dentry; } d_drop(dentry); dput(dentry); } /* * If we know that the inode will need to be revalidated immediately, * then don't create a new dentry for it. We'll end up doing an on * the wire call either way and this spares us an invalidation. */ if (fattr->cf_flags & CIFS_FATTR_NEED_REVAL) return NULL; dentry = d_alloc(parent, name); if (dentry == NULL) return NULL; inode = cifs_iget(sb, fattr); if (!inode) { dput(dentry); return NULL; } alias = d_materialise_unique(dentry, inode); if (alias != NULL) { dput(dentry); if (IS_ERR(alias)) return NULL; dentry = alias; } return dentry; }
/* * Attempt to preload the dcache with the results from the FIND_FIRST/NEXT * * Find the dentry that matches "name". If there isn't one, create one. If it's * a negative dentry or the uniqueid changed, then drop it and recreate it. */ static void cifs_prime_dcache(struct dentry *parent, struct qstr *name, struct cifs_fattr *fattr) { struct dentry *dentry, *alias; struct inode *inode; struct super_block *sb = parent->d_inode->i_sb; struct cifs_sb_info *cifs_sb = CIFS_SB(sb); cFYI(1, "%s: for %s", __func__, name->name); dentry = d_hash_and_lookup(parent, name); if (unlikely(IS_ERR(dentry))) return; if (dentry) { int err; inode = dentry->d_inode; if (inode) { /* * If we're generating inode numbers, then we don't * want to clobber the existing one with the one that * the readdir code created. */ if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) fattr->cf_uniqueid = CIFS_I(inode)->uniqueid; /* update inode in place if i_ino didn't change */ if (CIFS_I(inode)->uniqueid == fattr->cf_uniqueid) { cifs_fattr_to_inode(inode, fattr); goto out; } } err = d_invalidate(dentry); dput(dentry); if (err) return; } dentry = d_alloc(parent, name); if (!dentry) return; inode = cifs_iget(sb, fattr); if (!inode) goto out; alias = d_materialise_unique(dentry, inode); if (alias && !IS_ERR(alias)) dput(alias); out: dput(dentry); }
struct sysfs_dirent *sysfs_create_shadow_dir(struct kobject *kobj) { struct sysfs_dirent *parent_sd = kobj->sd->s_parent; struct dentry *dir, *parent, *shadow; struct inode *inode; struct sysfs_dirent *sd; struct sysfs_addrm_cxt acxt; dir = sysfs_get_dentry(kobj->sd); if (IS_ERR(dir)) { sd = (void *)dir; goto out; } parent = dir->d_parent; inode = dir->d_inode; sd = ERR_PTR(-EINVAL); if (!sysfs_is_shadowed_inode(inode)) goto out_dput; shadow = d_alloc(parent, &dir->d_name); if (!shadow) goto nomem; sd = sysfs_new_dirent("_SHADOW_", inode->i_mode, SYSFS_DIR); if (!sd) goto nomem; sd->s_elem.dir.kobj = kobj; sysfs_addrm_start(&acxt, parent_sd); /* add but don't link into children list */ sysfs_add_one(&acxt, sd); /* attach and instantiate dentry */ sysfs_attach_dentry(sd, shadow); d_instantiate(shadow, igrab(inode)); inc_nlink(inode); /* tj: synchronization? */ sysfs_addrm_finish(&acxt); dget(shadow); /* Extra count - pin the dentry in core */ goto out_dput; nomem: dput(shadow); sd = ERR_PTR(-ENOMEM); out_dput: dput(dir); out: return sd; }
/* * shmem_file_setup - get an unlinked file living in tmpfs * * @name: name for dentry (to be seen in /proc/<pid>/maps * @size: size to be set for the file * */ struct file *shmem_file_setup(char *name, loff_t size, unsigned long flags) { int error; struct file *file; struct inode *inode; struct dentry *dentry, *root; struct qstr this; if (IS_ERR(shm_mnt)) return (void *)shm_mnt; error = -ENOMEM; this.name = name; this.len = strlen(name); this.hash = 0; /* will go */ root = shm_mnt->mnt_root; dentry = d_alloc(root, &this); if (!dentry) goto put_memory; error = -ENFILE; file = get_empty_filp(); if (!file) goto put_dentry; error = -ENOSPC; inode = ramfs_get_inode(root->d_sb, S_IFREG | S_IRWXUGO, 0); if (!inode) goto close_file; d_instantiate(dentry, inode); inode->i_nlink = 0; /* It is unlinked */ file->f_path.mnt = mntget(shm_mnt); file->f_path.dentry = dentry; file->f_mapping = inode->i_mapping; file->f_op = &ramfs_file_operations; file->f_mode = FMODE_WRITE | FMODE_READ; /* notify everyone as to the change of file size */ error = do_truncate(dentry, size, 0, file); if (error < 0) goto close_file; return file; close_file: put_filp(file); put_dentry: dput(dentry); put_memory: return ERR_PTR(error); }
/* Might check in the future if inode number changed so we can rehash inode */ static int construct_dentry(struct qstr *qstring, struct file *file, struct inode **ptmp_inode, struct dentry **pnew_dentry) { struct dentry *tmp_dentry; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; int rc = 0; cFYI(1, ("For %s", qstring->name)); cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); pTcon = cifs_sb->tcon; qstring->hash = full_name_hash(qstring->name, qstring->len); tmp_dentry = d_lookup(file->f_path.dentry, qstring); if (tmp_dentry) { cFYI(0, ("existing dentry with inode 0x%p", tmp_dentry->d_inode)); *ptmp_inode = tmp_dentry->d_inode; /* BB overwrite old name? i.e. tmp_dentry->d_name and tmp_dentry->d_name.len??*/ if (*ptmp_inode == NULL) { *ptmp_inode = new_inode(file->f_path.dentry->d_sb); if (*ptmp_inode == NULL) return rc; rc = 1; } if (file->f_path.dentry->d_sb->s_flags & MS_NOATIME) (*ptmp_inode)->i_flags |= S_NOATIME | S_NOCMTIME; } else { tmp_dentry = d_alloc(file->f_path.dentry, qstring); if (tmp_dentry == NULL) { cERROR(1, ("Failed allocating dentry")); *ptmp_inode = NULL; return rc; } *ptmp_inode = new_inode(file->f_path.dentry->d_sb); if (pTcon->nocase) tmp_dentry->d_op = &cifs_ci_dentry_ops; else tmp_dentry->d_op = &cifs_dentry_ops; if (*ptmp_inode == NULL) return rc; if (file->f_path.dentry->d_sb->s_flags & MS_NOATIME) (*ptmp_inode)->i_flags |= S_NOATIME | S_NOCMTIME; rc = 2; } tmp_dentry->d_time = jiffies; *pnew_dentry = tmp_dentry; return rc; }
/* this routine links an IS_ROOT dentry into the dcache tree. It gains "parent" * as a parent and "name" as a name * It should possibly go in dcache.c */ int d_splice(struct dentry *target, struct dentry *parent, struct qstr *name) { struct dentry *tdentry; #ifdef NFSD_PARANOIA if (!IS_ROOT(target)) printk("nfsd: d_splice with no-root target: %s/%s\n", parent->d_name.name, name->name); if (!(target->d_flags & DCACHE_NFSD_DISCONNECTED)) printk("nfsd: d_splice with non-DISCONNECTED target: %s/%s\n", parent->d_name.name, name->name); #endif tdentry = d_alloc(parent, name); if (tdentry == NULL) return -ENOMEM; d_move(target, tdentry); /* tdentry will have been made a "child" of target (the parent of target) * make it an IS_ROOT instead */ spin_lock(&dcache_lock); list_del_init(&tdentry->d_child); tdentry->d_parent = tdentry; spin_unlock(&dcache_lock); d_rehash(target); dput(tdentry); /* if parent is properly connected, then we can assert that * the children are connected, but it must be a singluar (non-forking) * branch */ if (!(parent->d_flags & DCACHE_NFSD_DISCONNECTED)) { while (target) { target->d_flags &= ~DCACHE_NFSD_DISCONNECTED; parent = target; spin_lock(&dcache_lock); if (list_empty(&parent->d_subdirs)) target = NULL; else { target = list_entry(parent->d_subdirs.next, struct dentry, d_child); #ifdef NFSD_PARANOIA /* must be only child */ if (target->d_child.next != &parent->d_subdirs || target->d_child.prev != &parent->d_subdirs) printk("nfsd: d_splice found non-singular disconnected branch: %s/%s\n", parent->d_name.name, target->d_name.name); #endif } spin_unlock(&dcache_lock); } } return 0; }
int dcache_dir_open(struct inode *inode, struct file *file) { static struct qstr cursor_name = {.len = 1, .name = "."}; file->private_data = d_alloc(file->f_path.dentry, &cursor_name); return file->private_data ? 0 : -ENOMEM; } int dcache_dir_close(struct inode *inode, struct file *file) { dput(file->private_data); return 0; }
/* Might check in the future if inode number changed so we can rehash inode */ static int construct_dentry(struct qstr *qstring, struct file *file, struct inode **ptmp_inode, struct dentry **pnew_dentry, __u64 *inum) { struct dentry *tmp_dentry = NULL; struct super_block *sb = file->f_path.dentry->d_sb; int rc = 0; cFYI(1, ("For %s", qstring->name)); qstring->hash = full_name_hash(qstring->name, qstring->len); tmp_dentry = d_lookup(file->f_path.dentry, qstring); if (tmp_dentry) { /* BB: overwrite old name? i.e. tmp_dentry->d_name and * tmp_dentry->d_name.len?? */ cFYI(0, ("existing dentry with inode 0x%p", tmp_dentry->d_inode)); *ptmp_inode = tmp_dentry->d_inode; if (*ptmp_inode == NULL) { *ptmp_inode = cifs_new_inode(sb, inum); if (*ptmp_inode == NULL) return rc; rc = 1; } } else { tmp_dentry = d_alloc(file->f_path.dentry, qstring); if (tmp_dentry == NULL) { cERROR(1, ("Failed allocating dentry")); *ptmp_inode = NULL; return rc; } if (CIFS_SB(sb)->tcon->nocase) tmp_dentry->d_op = &cifs_ci_dentry_ops; else tmp_dentry->d_op = &cifs_dentry_ops; *ptmp_inode = cifs_new_inode(sb, inum); if (*ptmp_inode == NULL) return rc; rc = 2; } tmp_dentry->d_time = jiffies; *pnew_dentry = tmp_dentry; return rc; }
static struct dentry * cifs_readdir_lookup(struct dentry *parent, struct qstr *name, struct cifs_fattr *fattr) { struct dentry *dentry, *alias; struct inode *inode; struct super_block *sb = parent->d_inode->i_sb; cFYI(1, "For %s", name->name); if (parent->d_op && parent->d_op->d_hash) parent->d_op->d_hash(parent, parent->d_inode, name); else name->hash = full_name_hash(name->name, name->len); dentry = d_lookup(parent, name); if (dentry) { inode = dentry->d_inode; /* update inode in place if i_ino didn't change */ if (inode && CIFS_I(inode)->uniqueid == fattr->cf_uniqueid) { cifs_fattr_to_inode(inode, fattr); return dentry; } d_drop(dentry); dput(dentry); } dentry = d_alloc(parent, name); if (dentry == NULL) return NULL; inode = cifs_iget(sb, fattr); if (!inode) { dput(dentry); return NULL; } alias = d_materialise_unique(dentry, inode); if (alias != NULL) { dput(dentry); if (IS_ERR(alias)) return NULL; dentry = alias; } return dentry; }
static struct dentry *vperfctr_d_alloc_root(struct inode *inode) { struct qstr this; char name[32]; struct dentry *dentry; sprintf(name, "[%lu]", inode->i_ino); this.name = name; this.len = strlen(name); this.hash = inode->i_ino; /* will go */ dentry = d_alloc(vperfctr_mnt->mnt_sb->s_root, &this); if (dentry) { dentry->d_op = &vperfctrfs_dentry_operations; d_add(dentry, inode); } return dentry; }
static int jffs2_whiteout(struct inode *old_dir, struct dentry *old_dentry) { struct dentry *wh; int err; wh = d_alloc(old_dentry->d_parent, &old_dentry->d_name); if (!wh) return -ENOMEM; err = jffs2_mknod(old_dir, wh, S_IFCHR | WHITEOUT_MODE, WHITEOUT_DEV); if (err) return err; d_rehash(wh); return 0; }
/* Might check in the future if inode number changed so we can rehash inode */ static int construct_dentry(struct qstr *qstring, struct file *file, struct inode **ptmp_inode, struct dentry **pnew_dentry) { struct dentry *tmp_dentry; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; int rc = 0; cFYI(1, ("For %s", qstring->name)); cifs_sb = CIFS_SB(file->f_dentry->d_sb); pTcon = cifs_sb->tcon; qstring->hash = full_name_hash(qstring->name, qstring->len); tmp_dentry = d_lookup(file->f_dentry, qstring); if (tmp_dentry) { cFYI(0, ("existing dentry with inode 0x%p", tmp_dentry->d_inode)); *ptmp_inode = tmp_dentry->d_inode; /* BB overwrite old name? i.e. tmp_dentry->d_name and tmp_dentry->d_name.len??*/ if(*ptmp_inode == NULL) { *ptmp_inode = new_inode(file->f_dentry->d_sb); if(*ptmp_inode == NULL) return rc; rc = 1; d_instantiate(tmp_dentry, *ptmp_inode); } } else { tmp_dentry = d_alloc(file->f_dentry, qstring); if(tmp_dentry == NULL) { cERROR(1,("Failed allocating dentry")); *ptmp_inode = NULL; return rc; } *ptmp_inode = new_inode(file->f_dentry->d_sb); tmp_dentry->d_op = &cifs_dentry_ops; if(*ptmp_inode == NULL) return rc; rc = 1; d_instantiate(tmp_dentry, *ptmp_inode); d_rehash(tmp_dentry); } tmp_dentry->d_time = jiffies; *pnew_dentry = tmp_dentry; return rc; }
/* * Find the dentry that matches "name". If there isn't one, create one. If it's * a negative dentry or the uniqueid changed, then drop it and recreate it. */ static struct dentry * cifs_readdir_lookup(struct dentry *parent, struct qstr *name, struct cifs_fattr *fattr) { struct dentry *dentry, *alias; struct inode *inode; struct super_block *sb = parent->d_inode->i_sb; cFYI(1, "For %s", name->name); if (parent->d_op && parent->d_op->d_hash) parent->d_op->d_hash(parent, parent->d_inode, name); else name->hash = full_name_hash(name->name, name->len); dentry = d_lookup(parent, name); if (dentry) { /* FIXME: check for inode number changes? */ if (dentry->d_inode != NULL) return dentry; d_drop(dentry); dput(dentry); } dentry = d_alloc(parent, name); if (dentry == NULL) return NULL; inode = cifs_iget(sb, fattr); if (!inode) { dput(dentry); return NULL; } alias = d_materialise_unique(dentry, inode); if (alias != NULL) { dput(dentry); if (IS_ERR(alias)) return NULL; dentry = alias; } return dentry; }
/* * Find the dentry that matches "name". If there isn't one, create one. If it's * a negative dentry or the uniqueid changed, then drop it and recreate it. */ static struct dentry * cifs_readdir_lookup(struct dentry *parent, struct qstr *name, struct cifs_fattr *fattr) { struct dentry *dentry, *alias; struct inode *inode; struct super_block *sb = parent->d_inode->i_sb; cFYI(1, ("For %s", name->name)); dentry = d_lookup(parent, name); if (dentry) { /* FIXME: check for inode number changes? */ if (dentry->d_inode != NULL) return dentry; d_drop(dentry); dput(dentry); } dentry = d_alloc(parent, name); if (dentry == NULL) return NULL; inode = cifs_iget(sb, fattr); if (!inode) { dput(dentry); return NULL; } if (CIFS_SB(sb)->tcon->nocase) dentry->d_op = &cifs_ci_dentry_ops; else dentry->d_op = &cifs_dentry_ops; alias = d_materialise_unique(dentry, inode); if (alias != NULL) { dput(dentry); if (IS_ERR(alias)) return NULL; dentry = alias; } return dentry; }
static struct super_block * perfctr_get_sb_pseudo(struct file_system_type *fs_type, char *name, struct super_operations *ops, unsigned long magic) { struct super_block *s = sget(fs_type, NULL, set_anon_super, NULL); static struct super_operations default_ops = {.statfs = simple_statfs}; struct dentry *dentry; struct inode *root; struct qstr d_name = {.name = name, .len = strlen(name)}; if (IS_ERR(s)) return s; s->s_flags = MS_NOUSER; s->s_maxbytes = ~0ULL; s->s_blocksize = 1024; s->s_blocksize_bits = 10; s->s_magic = magic; s->s_op = ops ? ops : &default_ops; root = new_inode(s); if (!root) goto Enomem; root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR; root->i_uid = root->i_gid = 0; root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME; dentry = d_alloc(NULL, &d_name); if (!dentry) { iput(root); goto Enomem; } dentry->d_sb = s; dentry->d_parent = dentry; d_instantiate(dentry, root); s->s_root = dentry; s->s_flags |= MS_ACTIVE; return s; Enomem: up_write(&s->s_umount); deactivate_super(s); return ERR_PTR(-ENOMEM); }
static struct dentry *efivarfs_alloc_dentry(struct dentry *parent, char *name) { struct dentry *d; struct qstr q; int err; q.name = name; q.len = strlen(name); err = efivarfs_d_hash(NULL, NULL, &q); if (err) return ERR_PTR(err); d = d_alloc(parent, &q); if (d) return d; return ERR_PTR(-ENOMEM); }
static struct dentry * __oprofilefs_create_file(struct super_block * sb, struct dentry * root, char const * name, struct file_operations * fops) { struct dentry * dentry; struct inode * inode; struct qstr qname; qname.name = name; qname.len = strlen(name); qname.hash = full_name_hash(qname.name, qname.len); dentry = d_alloc(root, &qname); if (!dentry) return 0; inode = oprofilefs_get_inode(sb, S_IFREG | 0644); if (!inode) { dput(dentry); return 0; } inode->i_fop = fops; d_add(dentry, inode); return dentry; }
struct dentry * oprofilefs_mkdir(struct super_block * sb, struct dentry * root, char const * name) { struct dentry * dentry; struct inode * inode; struct qstr qname; qname.name = name; qname.len = strlen(name); qname.hash = full_name_hash(qname.name, qname.len); dentry = d_alloc(root, &qname); if (!dentry) return 0; inode = oprofilefs_get_inode(sb, S_IFDIR | 0755); if (!inode) { dput(dentry); return 0; } inode->i_op = &oprofilefs_dir_inode_operations; inode->i_fop = &oprofilefs_dir_operations; d_add(dentry, inode); return dentry; }
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); }
/* * RENAME * FIXME: Some nfsds, like the Linux user space nfsd, may generate a * different file handle for the same inode after a rename (e.g. when * moving to a different directory). A fail-safe method to do so would * be to look up old_dir/old_name, create a link to new_dir/new_name and * rename the old file using the sillyrename stuff. This way, the original * file in old_dir will go away when the last process iput()s the inode. * * FIXED. * * It actually works quite well. One needs to have the possibility for * at least one ".nfs..." file in each directory the file ever gets * moved or linked to which happens automagically with the new * implementation that only depends on the dcache stuff instead of * using the inode layer * * Unfortunately, things are a little more complicated than indicated * above. For a cross-directory move, we want to make sure we can get * rid of the old inode after the operation. This means there must be * no pending writes (if it's a file), and the use count must be 1. * If these conditions are met, we can drop the dentries before doing * the rename. */ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { struct inode *old_inode = old_dentry->d_inode; struct inode *new_inode = new_dentry->d_inode; struct dentry *dentry = NULL, *rehash = NULL; int error = -EBUSY; /* * To prevent any new references to the target during the rename, * we unhash the dentry and free the inode in advance. */ if (!d_unhashed(new_dentry)) { d_drop(new_dentry); rehash = new_dentry; } dfprintk(VFS, "NFS: rename(%s/%s -> %s/%s, ct=%d)\n", old_dentry->d_parent->d_name.name, old_dentry->d_name.name, new_dentry->d_parent->d_name.name, new_dentry->d_name.name, atomic_read(&new_dentry->d_count)); /* * First check whether the target is busy ... we can't * safely do _any_ rename if the target is in use. * * For files, make a copy of the dentry and then do a * silly-rename. If the silly-rename succeeds, the * copied dentry is hashed and becomes the new target. */ if (!new_inode) goto go_ahead; if (S_ISDIR(new_inode->i_mode)) goto out; else if (atomic_read(&new_dentry->d_count) > 1) { int err; /* copy the target dentry's name */ dentry = d_alloc(new_dentry->d_parent, &new_dentry->d_name); if (!dentry) goto out; /* silly-rename the existing target ... */ err = nfs_sillyrename(new_dir, new_dentry); if (!err) { new_dentry = rehash = dentry; new_inode = NULL; /* instantiate the replacement target */ d_instantiate(new_dentry, NULL); } /* dentry still busy? */ if (atomic_read(&new_dentry->d_count) > 1) { #ifdef NFS_PARANOIA printk("nfs_rename: target %s/%s busy, d_count=%d\n", new_dentry->d_parent->d_name.name, new_dentry->d_name.name, atomic_read(&new_dentry->d_count)); #endif goto out; } } go_ahead: /* * ... prune child dentries and writebacks if needed. */ if (atomic_read(&old_dentry->d_count) > 1) { nfs_wb_all(old_inode); shrink_dcache_parent(old_dentry); } if (new_inode) d_delete(new_dentry); nfs_zap_caches(new_dir); nfs_zap_caches(old_dir); error = NFS_PROTO(old_dir)->rename(old_dir, &old_dentry->d_name, new_dir, &new_dentry->d_name); out: if (rehash) d_rehash(rehash); if (!error && !S_ISDIR(old_inode->i_mode)) d_move(old_dentry, new_dentry); /* new dentry created? */ if (dentry) dput(dentry); return error; }
static int fuse_direntplus_link(struct file *file, struct fuse_direntplus *direntplus, u64 attr_version) { int err; struct fuse_entry_out *o = &direntplus->entry_out; struct fuse_dirent *dirent = &direntplus->dirent; struct dentry *parent = file->f_path.dentry; struct qstr name = QSTR_INIT(dirent->name, dirent->namelen); struct dentry *dentry; struct dentry *alias; struct inode *dir = parent->d_inode; struct fuse_conn *fc; struct inode *inode; if (!o->nodeid) { /* * Unlike in the case of fuse_lookup, zero nodeid does not mean * ENOENT. Instead, it only means the userspace filesystem did * not want to return attributes/handle for this entry. * * So do nothing. */ return 0; } if (name.name[0] == '.') { /* * We could potentially refresh the attributes of the directory * and its parent? */ if (name.len == 1) return 0; if (name.name[1] == '.' && name.len == 2) return 0; } if (invalid_nodeid(o->nodeid)) return -EIO; if (!fuse_valid_type(o->attr.mode)) return -EIO; fc = get_fuse_conn(dir); name.hash = full_name_hash(name.name, name.len); dentry = d_lookup(parent, &name); if (dentry) { inode = dentry->d_inode; if (!inode) { d_drop(dentry); } else if (get_node_id(inode) != o->nodeid || ((o->attr.mode ^ inode->i_mode) & S_IFMT)) { err = d_invalidate(dentry); if (err) goto out; } else if (is_bad_inode(inode)) { err = -EIO; goto out; } else { struct fuse_inode *fi; fi = get_fuse_inode(inode); spin_lock(&fc->lock); fi->nlookup++; spin_unlock(&fc->lock); fuse_change_attributes(inode, &o->attr, entry_attr_timeout(o), attr_version); /* * The other branch to 'found' comes via fuse_iget() * which bumps nlookup inside */ goto found; } dput(dentry); } dentry = d_alloc(parent, &name); err = -ENOMEM; if (!dentry) goto out; inode = fuse_iget(dir->i_sb, o->nodeid, o->generation, &o->attr, entry_attr_timeout(o), attr_version); if (!inode) goto out; alias = fuse_materialise_dentry(dentry, inode); err = PTR_ERR(alias); if (IS_ERR(alias)) goto out; if (alias) { dput(dentry); dentry = alias; } found: fuse_change_entry_timeout(dentry, o); err = 0; out: dput(dentry); return err; }