/* We do silly rename. In case sillyrename() returns -EBUSY, the inode * belongs to an active ".nfs..." file and we return -EBUSY. * * If sillyrename() returns 0, we do nothing, otherwise we unlink. */ static int nfs_unlink(struct inode *dir, struct dentry *dentry) { int error; int need_rehash = 0; dfprintk(VFS, "NFS: unlink(%s/%ld, %s)\n", dir->i_sb->s_id, dir->i_ino, dentry->d_name.name); lock_kernel(); spin_lock(&dcache_lock); spin_lock(&dentry->d_lock); if (atomic_read(&dentry->d_count) > 1) { spin_unlock(&dentry->d_lock); spin_unlock(&dcache_lock); error = nfs_sillyrename(dir, dentry); unlock_kernel(); return error; } if (!d_unhashed(dentry)) { __d_drop(dentry); need_rehash = 1; } spin_unlock(&dentry->d_lock); spin_unlock(&dcache_lock); error = nfs_safe_remove(dentry); if (!error) { nfs_renew_times(dentry); nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); } else if (need_rehash) d_rehash(dentry); unlock_kernel(); 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); }
/** * ecryptfs_create * @dir: The inode of the directory in which to create the file. * @dentry: The eCryptfs dentry * @mode: The mode of the new file. * * Creates a new file. * * Returns zero on success; non-zero on error condition */ static int ecryptfs_create(struct inode *directory_inode, struct dentry *ecryptfs_dentry, umode_t mode, bool excl) { struct inode *ecryptfs_inode; int rc; ecryptfs_inode = ecryptfs_do_create(directory_inode, ecryptfs_dentry, mode); if (unlikely(IS_ERR(ecryptfs_inode))) { ecryptfs_printk(KERN_WARNING, "Failed to create file in" "lower filesystem\n"); rc = PTR_ERR(ecryptfs_inode); goto out; } /* At this point, a file exists on "disk"; we need to make sure * that this on disk file is prepared to be an ecryptfs file */ rc = ecryptfs_initialize_file(ecryptfs_dentry, ecryptfs_inode); if (rc) { ecryptfs_do_unlink(directory_inode, ecryptfs_dentry, ecryptfs_inode); make_bad_inode(ecryptfs_inode); unlock_new_inode(ecryptfs_inode); iput(ecryptfs_inode); goto out; } unlock_new_inode(ecryptfs_inode); d_instantiate(ecryptfs_dentry, ecryptfs_inode); if(d_unhashed(ecryptfs_dentry)) d_rehash(ecryptfs_dentry); out: return rc; }
/* Re-target existing file to the new endpoint. * Caller is responsible for refcounts of the old and the new thr. */ void oo_move_file(ci_private_t* priv, tcp_helper_resource_t *new_thr, oo_sp new_sockid) { priv->thr = new_thr; priv->sock_id = new_sockid; #ifndef EFX_HAVE_D_DNAME { /* tell everybody that we've changed the name. * Assume the name is short (DNAME_INLINE_LEN_MIN=36). */ struct dentry *dentry = priv->_filp->f_dentry; if( dname_external(dentry) ) { /* We do not want to handle memory free/allocation, * so just go out. * Unlucky user gets incorrect name in /proc - it is much better * than memory corruption. */ return; } d_drop(dentry); dentry->d_name.len = onloadfs_name(priv, dentry->d_iname, sizeof(dentry->d_iname)); d_rehash(dentry); } #endif }
/** * sysfs_attach_dentry - associate sysfs_dirent with dentry * @sd: target sysfs_dirent * @dentry: dentry to associate * * Associate @sd with @dentry. This is protected by * sysfs_assoc_lock to avoid race with sysfs_d_iput(). * * LOCKING: * mutex_lock(sysfs_mutex) */ static void sysfs_attach_dentry(struct sysfs_dirent *sd, struct dentry *dentry) { dentry->d_op = &sysfs_dentry_ops; dentry->d_fsdata = sysfs_get(sd); /* protect sd->s_dentry against sysfs_d_iput */ spin_lock(&sysfs_assoc_lock); sd->s_dentry = dentry; spin_unlock(&sysfs_assoc_lock); d_rehash(dentry); }
/* * Remove a file after making sure there are no pending writes, * and after checking that the file has only one user. * * We invalidate the attribute cache and free the inode prior to the operation * to avoid possible races if the server reuses the inode. */ static int nfs_safe_remove(struct dentry *dentry) { struct inode *dir = dentry->d_parent->d_inode; struct inode *inode = dentry->d_inode; int error = -EBUSY, rehash = 0; dfprintk(VFS, "NFS: safe_remove(%s/%s)\n", dentry->d_parent->d_name.name, dentry->d_name.name); /* * Unhash the dentry while we remove the file ... */ if (!d_unhashed(dentry)) { d_drop(dentry); rehash = 1; } if (atomic_read(&dentry->d_count) > 1) { #ifdef NFS_PARANOIA printk("nfs_safe_remove: %s/%s busy, d_count=%d\n", dentry->d_parent->d_name.name, dentry->d_name.name, atomic_read(&dentry->d_count)); #endif goto out; } /* If the dentry was sillyrenamed, we simply call d_delete() */ if (dentry->d_flags & DCACHE_NFSFS_RENAMED) { error = 0; goto out_delete; } nfs_zap_caches(dir); if (inode) NFS_CACHEINV(inode); error = NFS_PROTO(dir)->remove(dir, &dentry->d_name); if (error < 0) goto out; if (inode) inode->i_nlink--; out_delete: /* * Free the inode */ d_delete(dentry); out: if (rehash) d_rehash(dentry); return error; }
/* 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; }
/* 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; }
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; }
/** * ecryptfs_interpose * @lower_dentry: Existing dentry in the lower filesystem * @dentry: ecryptfs' dentry * @sb: ecryptfs's super_block * * Interposes upper and lower dentries. * * Returns zero on success; non-zero otherwise */ static int ecryptfs_interpose(struct dentry *lower_dentry, struct dentry *dentry, struct super_block *sb) { struct inode *inode = ecryptfs_get_inode(lower_dentry->d_inode, sb); if (IS_ERR(inode)) return PTR_ERR(inode); d_instantiate(dentry, inode); if(d_unhashed(dentry)) d_rehash(dentry); #ifdef CONFIG_SDP if(S_ISDIR(inode->i_mode) && dentry) { if(IS_UNDER_ROOT(dentry)) { struct ecryptfs_mount_crypt_stat *mount_crypt_stat = &ecryptfs_superblock_to_private(inode->i_sb)->mount_crypt_stat; int engineid; printk("Creating a directoy under root directory of current partition.\n"); if(is_chamber_directory(mount_crypt_stat, dentry->d_name.name, &engineid)) { printk("This is a chamber directory engine[%d]\n", engineid); set_chamber_flag(engineid, inode); } } else if(IS_SENSITIVE_DENTRY(dentry->d_parent)) { /* * When parent directory is sensitive */ struct ecryptfs_crypt_stat *crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat; struct ecryptfs_crypt_stat *parent_crypt_stat = &ecryptfs_inode_to_private(dentry->d_parent->d_inode)->crypt_stat; //TODO : remove this log DEK_LOGE("Parent %s[id:%d] is sensitive. so this directory is sensitive too\n", dentry->d_parent->d_name.name, parent_crypt_stat->engine_id); crypt_stat->flags |= ECRYPTFS_DEK_IS_SENSITIVE; crypt_stat->engine_id = parent_crypt_stat->engine_id; } } #endif return 0; }
/* * There is no need to lock the unionfs_super_info's rwsem as there is no * way anyone can have a reference to the superblock at this point in time. */ static int unionfs_read_super(struct super_block *sb, void *raw_data, int silent) { int err = 0; struct unionfs_dentry_info *lower_root_info = NULL; int bindex, bstart, bend; struct inode *inode = NULL; if (!raw_data) { printk(KERN_ERR "unionfs: read_super: missing data argument\n"); err = -EINVAL; goto out; } /* Allocate superblock private data */ sb->s_fs_info = kzalloc(sizeof(struct unionfs_sb_info), GFP_KERNEL); if (unlikely(!UNIONFS_SB(sb))) { printk(KERN_CRIT "unionfs: read_super: out of memory\n"); err = -ENOMEM; goto out; } UNIONFS_SB(sb)->bend = -1; atomic_set(&UNIONFS_SB(sb)->generation, 1); init_rwsem(&UNIONFS_SB(sb)->rwsem); UNIONFS_SB(sb)->high_branch_id = -1; /* -1 == invalid branch ID */ lower_root_info = unionfs_parse_options(sb, raw_data); if (IS_ERR(lower_root_info)) { printk(KERN_ERR "unionfs: 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; } if (lower_root_info->bstart == -1) { err = -ENOENT; goto out_free; } /* set the lower superblock field of upper superblock */ bstart = lower_root_info->bstart; BUG_ON(bstart != 0); sbend(sb) = bend = lower_root_info->bend; for (bindex = bstart; bindex <= bend; bindex++) { struct dentry *d = lower_root_info->lower_paths[bindex].dentry; atomic_inc(&d->d_sb->s_active); unionfs_set_lower_super_idx(sb, bindex, d->d_sb); } /* max Bytes is the maximum bytes from highest priority branch */ sb->s_maxbytes = unionfs_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. This is important for our * time-based cache coherency. */ sb->s_time_gran = 1; sb->s_op = &unionfs_sops; /* get a new inode and allocate our root dentry */ inode = unionfs_iget(sb, iunique(sb, UNIONFS_ROOT_INO)); if (IS_ERR(inode)) { err = PTR_ERR(inode); goto out_dput; } sb->s_root = d_make_root(inode); if (unlikely(!sb->s_root)) { err = -ENOMEM; goto out_iput; } d_set_d_op(sb->s_root, &unionfs_dops); /* link the upper and lower dentries */ sb->s_root->d_fsdata = NULL; err = new_dentry_private_data(sb->s_root, UNIONFS_DMUTEX_ROOT); if (unlikely(err)) goto out_freedpd; /* if get here: cannot have error */ /* Set the lower dentries for s_root */ for (bindex = bstart; bindex <= bend; bindex++) { struct dentry *d; struct vfsmount *m; d = lower_root_info->lower_paths[bindex].dentry; m = lower_root_info->lower_paths[bindex].mnt; unionfs_set_lower_dentry_idx(sb->s_root, bindex, d); unionfs_set_lower_mnt_idx(sb->s_root, bindex, m); } dbstart(sb->s_root) = bstart; dbend(sb->s_root) = bend; /* Set the generation number to one, since this is for the mount. */ atomic_set(&UNIONFS_D(sb->s_root)->generation, 1); if (atomic_read(&inode->i_count) <= 1) unionfs_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); unionfs_unlock_dentry(sb->s_root); goto out; /* all is well */ out_freedpd: if (UNIONFS_D(sb->s_root)) { kfree(UNIONFS_D(sb->s_root)->lower_paths); free_dentry_private_data(sb->s_root); } dput(sb->s_root); out_iput: iput(inode); out_dput: if (lower_root_info && !IS_ERR(lower_root_info)) { for (bindex = lower_root_info->bstart; bindex <= lower_root_info->bend; bindex++) { struct dentry *d; d = lower_root_info->lower_paths[bindex].dentry; /* drop refs we took earlier */ atomic_dec(&d->d_sb->s_active); path_put(&lower_root_info->lower_paths[bindex]); } kfree(lower_root_info->lower_paths); kfree(lower_root_info); lower_root_info = NULL; } out_free: kfree(UNIONFS_SB(sb)->data); kfree(UNIONFS_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; }
/* * create a regular file on an AFS filesystem */ static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool excl) { struct afs_file_status status; struct afs_callback cb; struct afs_server *server; struct afs_vnode *dvnode, *vnode; struct afs_fid fid; struct inode *inode; struct key *key; int ret; dvnode = AFS_FS_I(dir); _enter("{%x:%u},{%pd},%ho,", dvnode->fid.vid, dvnode->fid.vnode, dentry, mode); key = afs_request_key(dvnode->volume->cell); if (IS_ERR(key)) { ret = PTR_ERR(key); goto error; } mode |= S_IFREG; ret = afs_vnode_create(dvnode, key, dentry->d_name.name, mode, &fid, &status, &cb, &server); if (ret < 0) goto create_error; inode = afs_iget(dir->i_sb, key, &fid, &status, &cb); if (IS_ERR(inode)) { /* ENOMEM at a really inconvenient time - just abandon the new * directory on the server */ ret = PTR_ERR(inode); goto iget_error; } /* apply the status report we've got for the new vnode */ vnode = AFS_FS_I(inode); spin_lock(&vnode->lock); vnode->update_cnt++; spin_unlock(&vnode->lock); afs_vnode_finalise_status_update(vnode, server); afs_put_server(server); d_instantiate(dentry, inode); if (d_unhashed(dentry)) { _debug("not hashed"); d_rehash(dentry); } key_put(key); _leave(" = 0"); return 0; iget_error: afs_put_server(server); create_error: key_put(key); error: d_drop(dentry); _leave(" = %d", ret); return ret; }
/* * Create dentry/inode for this file and add it to the dircache. */ int smb_fill_cache(struct file *filp, void *dirent, filldir_t filldir, struct smb_cache_control *ctrl, struct qstr *qname, struct smb_fattr *entry) { struct dentry *newdent, *dentry = filp->f_path.dentry; struct inode *newino, *inode = dentry->d_inode; struct smb_cache_control ctl = *ctrl; int valid = 0; int hashed = 0; ino_t ino = 0; qname->hash = full_name_hash(qname->name, qname->len); if (dentry->d_op && dentry->d_op->d_hash) if (dentry->d_op->d_hash(dentry, qname) != 0) goto end_advance; newdent = d_lookup(dentry, qname); if (!newdent) { newdent = d_alloc(dentry, qname); if (!newdent) goto end_advance; } else { hashed = 1; memcpy((char *) newdent->d_name.name, qname->name, newdent->d_name.len); } if (!newdent->d_inode) { smb_renew_times(newdent); entry->f_ino = iunique(inode->i_sb, 2); newino = smb_iget(inode->i_sb, entry); if (newino) { smb_new_dentry(newdent); d_instantiate(newdent, newino); if (!hashed) d_rehash(newdent); } } else smb_set_inode_attr(newdent->d_inode, entry); if (newdent->d_inode) { ino = newdent->d_inode->i_ino; newdent->d_fsdata = (void *) ctl.fpos; smb_new_dentry(newdent); } if (ctl.idx >= SMB_DIRCACHE_SIZE) { if (ctl.page) { kunmap(ctl.page); SetPageUptodate(ctl.page); unlock_page(ctl.page); page_cache_release(ctl.page); } ctl.cache = NULL; ctl.idx -= SMB_DIRCACHE_SIZE; ctl.ofs += 1; ctl.page = grab_cache_page(&inode->i_data, ctl.ofs); if (ctl.page) ctl.cache = kmap(ctl.page); } if (ctl.cache) { ctl.cache->dentry[ctl.idx] = newdent; valid = 1; } dput(newdent); end_advance: if (!valid) ctl.valid = 0; if (!ctl.filled && (ctl.fpos == filp->f_pos)) { if (!ino) ino = find_inode_number(dentry, qname); if (!ino) ino = iunique(inode->i_sb, 2); ctl.filled = filldir(dirent, qname->name, qname->len, filp->f_pos, ino, DT_UNKNOWN); if (!ctl.filled) filp->f_pos += 1; } ctl.fpos += 1; ctl.idx += 1; *ctrl = ctl; return (ctl.valid || !ctl.filled); }
/* * create a symlink in an AFS filesystem */ static int afs_symlink(struct inode *dir, struct dentry *dentry, const char *content) { struct afs_file_status status; struct afs_server *server; struct afs_vnode *dvnode, *vnode; struct afs_fid fid; struct inode *inode; struct key *key; int ret; dvnode = AFS_FS_I(dir); _enter("{%x:%u},{%s},%s", dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name, content); ret = -ENAMETOOLONG; if (dentry->d_name.len >= AFSNAMEMAX) goto error; ret = -EINVAL; if (strlen(content) >= AFSPATHMAX) goto error; key = afs_request_key(dvnode->volume->cell); if (IS_ERR(key)) { ret = PTR_ERR(key); goto error; } ret = afs_vnode_symlink(dvnode, key, dentry->d_name.name, content, &fid, &status, &server); if (ret < 0) goto create_error; inode = afs_iget(dir->i_sb, key, &fid, &status, NULL); if (IS_ERR(inode)) { /* ENOMEM at a really inconvenient time - just abandon the new * directory on the server */ ret = PTR_ERR(inode); goto iget_error; } /* apply the status report we've got for the new vnode */ vnode = AFS_FS_I(inode); spin_lock(&vnode->lock); vnode->update_cnt++; spin_unlock(&vnode->lock); afs_vnode_finalise_status_update(vnode, server); afs_put_server(server); d_instantiate(dentry, inode); if (d_unhashed(dentry)) { _debug("not hashed"); d_rehash(dentry); } key_put(key); _leave(" = 0"); return 0; iget_error: afs_put_server(server); create_error: key_put(key); error: d_drop(dentry); _leave(" = %d", ret); return ret; }
static int cifs_filldir(char *pfindEntry, struct file *file, filldir_t filldir, void *direntry, char *scratch_buf, int max_len) { int rc = 0; struct qstr qstring; struct cifsFileInfo *pCifsF; unsigned int obj_type; __u64 inum; struct cifs_sb_info *cifs_sb; struct inode *tmp_inode; struct dentry *tmp_dentry; /* get filename and len into qstring */ /* get dentry */ /* decide whether to create and populate ionde */ if ((direntry == NULL) || (file == NULL)) return -EINVAL; pCifsF = file->private_data; if ((scratch_buf == NULL) || (pfindEntry == NULL) || (pCifsF == NULL)) return -ENOENT; rc = cifs_entry_is_dot(pfindEntry, pCifsF); /* skip . and .. since we added them first */ if (rc != 0) return 0; cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); qstring.name = scratch_buf; rc = cifs_get_name_from_search_buf(&qstring, pfindEntry, pCifsF->srch_inf.info_level, pCifsF->srch_inf.unicode, cifs_sb, max_len, &inum /* returned */); if (rc) return rc; /* only these two infolevels return valid inode numbers */ if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX || pCifsF->srch_inf.info_level == SMB_FIND_FILE_ID_FULL_DIR_INFO) rc = construct_dentry(&qstring, file, &tmp_inode, &tmp_dentry, &inum); else rc = construct_dentry(&qstring, file, &tmp_inode, &tmp_dentry, NULL); if ((tmp_inode == NULL) || (tmp_dentry == NULL)) return -ENOMEM; /* we pass in rc below, indicating whether it is a new inode, so we can figure out whether to invalidate the inode cached data if the file has changed */ if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX) unix_fill_in_inode(tmp_inode, (FILE_UNIX_INFO *)pfindEntry, &obj_type, rc); else if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD) fill_in_inode(tmp_inode, 0 /* old level 1 buffer type */, pfindEntry, &obj_type, rc); else fill_in_inode(tmp_inode, 1 /* NT */, pfindEntry, &obj_type, rc); if (rc) /* new inode - needs to be tied to dentry */ { d_instantiate(tmp_dentry, tmp_inode); if (rc == 2) d_rehash(tmp_dentry); } rc = filldir(direntry, qstring.name, qstring.len, file->f_pos, tmp_inode->i_ino, obj_type); if (rc) { cFYI(1, ("filldir rc = %d", rc)); /* we can not return filldir errors to the caller since they are "normal" when the stat blocksize is too small - we return remapped error instead */ rc = -EOVERFLOW; } dput(tmp_dentry); return rc; }
static int hpfs_unlink(struct inode *dir, struct dentry *dentry) { const char *name = dentry->d_name.name; unsigned len = dentry->d_name.len; struct quad_buffer_head qbh; struct hpfs_dirent *de; struct inode *inode = dentry->d_inode; dnode_secno dno; fnode_secno fno; int r; int rep = 0; int err; lock_kernel(); hpfs_adjust_length((char *)name, &len); again: mutex_lock(&hpfs_i(inode)->i_parent_mutex); mutex_lock(&hpfs_i(dir)->i_mutex); err = -ENOENT; de = map_dirent(dir, hpfs_i(dir)->i_dno, (char *)name, len, &dno, &qbh); if (!de) goto out; err = -EPERM; if (de->first) goto out1; err = -EISDIR; if (de->directory) goto out1; fno = de->fnode; r = hpfs_remove_dirent(dir, dno, de, &qbh, 1); switch (r) { case 1: hpfs_error(dir->i_sb, "there was error when removing dirent"); err = -EFSERROR; break; case 2: /* no space for deleting, try to truncate file */ err = -ENOSPC; if (rep++) break; mutex_unlock(&hpfs_i(dir)->i_mutex); mutex_unlock(&hpfs_i(inode)->i_parent_mutex); d_drop(dentry); spin_lock(&dentry->d_lock); if (atomic_read(&dentry->d_count) > 1 || permission(inode, MAY_WRITE, NULL) || !S_ISREG(inode->i_mode) || get_write_access(inode)) { spin_unlock(&dentry->d_lock); d_rehash(dentry); } else { struct iattr newattrs; spin_unlock(&dentry->d_lock); /*printk("HPFS: truncating file before delete.\n");*/ newattrs.ia_size = 0; newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; err = notify_change(dentry, &newattrs); put_write_access(inode); if (!err) goto again; } unlock_kernel(); return -ENOSPC; default: inode->i_nlink--; err = 0; } goto out; out1: hpfs_brelse4(&qbh); out: mutex_unlock(&hpfs_i(dir)->i_mutex); mutex_unlock(&hpfs_i(inode)->i_parent_mutex); unlock_kernel(); return err; }
/* * There is no need to lock the esdfs_super_info's rwsem as there is no * way anyone can have a reference to the superblock at this point in time. */ static int esdfs_read_super(struct super_block *sb, const char *dev_name, void *raw_data, int silent) { int err = 0; struct super_block *lower_sb; struct path lower_path; struct esdfs_sb_info *sbi; struct inode *inode; if (!dev_name) { esdfs_msg(sb, KERN_ERR, "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) { esdfs_msg(sb, KERN_ERR, "error accessing lower directory '%s'\n", dev_name); goto out; } /* allocate superblock private data */ sb->s_fs_info = kzalloc(sizeof(struct esdfs_sb_info), GFP_KERNEL); sbi = ESDFS_SB(sb); if (!sbi) { esdfs_msg(sb, KERN_CRIT, "read_super: out of memory\n"); err = -ENOMEM; goto out_pput; } /* set defaults and then parse the mount options */ memcpy(&sbi->lower_perms, &esdfs_perms_table[ESDFS_PERMS_LOWER_DEFAULT], sizeof(struct esdfs_perms)); memcpy(&sbi->upper_perms, &esdfs_perms_table[ESDFS_PERMS_UPPER_LEGACY], sizeof(struct esdfs_perms)); err = parse_options(sb, (char *)raw_data); if (err) goto out_free; /* set the lower superblock field of upper superblock */ lower_sb = lower_path.dentry->d_sb; atomic_inc(&lower_sb->s_active); esdfs_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 = &esdfs_sops; /* get a new inode and allocate our root dentry */ inode = esdfs_iget(sb, lower_path.dentry->d_inode); 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, &esdfs_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 */ esdfs_set_lower_path(sb->s_root, &lower_path); #ifdef CONFIG_SECURITY_SELINUX security_secctx_to_secid(ESDFS_LOWER_SECCTX, strlen(ESDFS_LOWER_SECCTX), &sbi->lower_secid); #endif /* * 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); if (!silent) esdfs_msg(sb, KERN_INFO, "mounted on top of %s type %s\n", dev_name, lower_sb->s_type->name); if (!ESDFS_DERIVE_PERMS(sbi)) goto out; /* let user know that we ignore this option in derived mode */ if (memcmp(&sbi->upper_perms, &esdfs_perms_table[ESDFS_PERMS_UPPER_LEGACY], sizeof(struct esdfs_perms))) esdfs_msg(sb, KERN_WARNING, "'upper' mount option ignored in derived mode\n"); /* all derived modes start with the same, basic root */ memcpy(&sbi->upper_perms, &esdfs_perms_table[ESDFS_PERMS_UPPER_DERIVED], sizeof(struct esdfs_perms)); /* * In Android 3.0 all user conent in the emulated storage tree was * stored in /data/media. Android 4.2 introduced multi-user support, * which required that the primary user's content be migrated from * /data/media to /data/media/0. The framework then uses bind mounts * to create per-process namespaces to isolate each user's tree at * /data/media/N. This approach of having each user in a common root * is now considered "legacy" by the sdcard service. */ if (test_opt(sbi, DERIVE_LEGACY)) { ESDFS_I(inode)->tree = ESDFS_TREE_ROOT_LEGACY; sbi->obb_parent = dget(sb->s_root); /* * Android 4.4 reorganized this sturcture yet again, so that the * primary user's content was again at the root. Secondary users' * content is found in Android/user/N. Emulated internal storage still * seems to use the legacy tree, but secondary external storage uses * this method. */ } else if (test_opt(sbi, DERIVE_UNIFIED)) ESDFS_I(inode)->tree = ESDFS_TREE_ROOT; /* * Later versions of Android organize user content using quantum * entanglement, which has a low probability of being supported by * this driver. */ else esdfs_msg(sb, KERN_WARNING, "unsupported derived permissions mode\n"); /* initialize root inode */ esdfs_derive_perms(sb->s_root); goto out; out_freeroot: dput(sb->s_root); out_iput: iput(inode); out_sput: /* drop refs we took earlier */ atomic_dec(&lower_sb->s_active); out_free: kfree(ESDFS_SB(sb)); sb->s_fs_info = NULL; out_pput: path_put(&lower_path); out: return err; }
int unionfs_rmdir(struct inode *dir, struct dentry *dentry) { int err = 0; struct unionfs_dir_state *namelist = NULL; print_entry_location(); lock_dentry(dentry); fist_print_dentry("IN unionfs_rmdir: ", dentry); /* check if this unionfs directory is empty or not */ err = check_empty(dentry, &namelist); if (err) { #if 0 /* vfs_rmdir(our caller) unhashed the dentry. This will recover * the Unionfs inode number for the directory itself, but the * children are already lost. It seems that tmpfs manages its * way around this by upping the refcount on everything. * * Even if we do this, we still lose the inode numbers of the * children. The best way to fix this is to fix the VFS (or * use persistent inode maps). */ if (d_unhashed(dentry)) d_rehash(dentry); #endif goto out; } #ifdef UNIONFS_DELETE_ALL if (IS_SET(dir->i_sb, DELETE_ALL)) { /* delete all. */ err = unionfs_rmdir_all(dir, dentry, namelist); } else { /* Delete the first directory. */ #endif err = unionfs_rmdir_first(dir, dentry, namelist); /* create whiteout */ if (!err) { err = create_whiteout(dentry, dbstart(dentry)); } else { int new_err; if (dbstart(dentry) == 0) goto out; /* exit if the error returned was NOT -EROFS */ if (!IS_COPYUP_ERR(err)) goto out; new_err = create_whiteout(dentry, dbstart(dentry) - 1); if (new_err != -EEXIST) err = new_err; } #ifdef UNIONFS_DELETE_ALL } #endif out: /* call d_drop so the system "forgets" about us */ if (!err) d_drop(dentry); if (namelist) free_rdstate(namelist); unlock_dentry(dentry); print_exit_status(err); 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_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; }
/* * 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; }
/* * 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 onload_alloc_file(tcp_helper_resource_t *thr, oo_sp ep_id, int flags, int fd_type) { struct qstr name = { .name = "" }; #ifdef EFX_HAVE_STRUCT_PATH struct path path; #define my_dentry path.dentry #else struct dentry *dentry; #define my_dentry dentry #endif struct file *file; int fd; struct inode *inode; ci_private_t *priv; struct file_operations *fops; fops = oo_fops_by_type(fd_type); if( fops == NULL ) return -EINVAL; ci_assert_equal(fops->owner, THIS_MODULE); inode = new_inode(onload_mnt->mnt_sb); if( inode == NULL ) return -ENOMEM; #ifdef EFX_FSTYPE_HAS_MOUNT inode->i_ino = get_next_ino(); #endif if( fd_type == CI_PRIV_TYPE_NETIF ) inode->i_mode = S_IRWXUGO; if( fd_type == CI_PRIV_TYPE_TCP_EP || fd_type == CI_PRIV_TYPE_UDP_EP ) inode->i_mode = #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21) /* in 2.6.18 this flag makes us "socket" and sendmsg crashes; * see sock_from_file() */ S_IFSOCK | #endif S_IRWXUGO; else inode->i_mode = S_IFIFO | S_IRUSR | S_IWUSR; inode->i_uid = current_fsuid(); inode->i_gid = current_fsgid(); priv = &container_of(inode, struct onload_inode, vfs_inode)->priv; priv->thr = thr; priv->sock_id = ep_id; priv->fd_type = fd_type; fd = get_unused_fd(); if( fd < 0 ) { iput(inode); return fd; } /*ci_log("[%d]%s(%d:%d) return %d priv=%p", current->pid, __func__, thr->id, ep_id, fd, priv);*/ #ifdef EFX_FSTYPE_HAS_MOUNT #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,37) path.dentry = d_alloc(onload_mnt->mnt_sb->s_root, &name); if( path.dentry != NULL ) path.dentry->d_op = &onloadfs_dentry_operations; #else path.dentry = d_alloc_pseudo(onload_mnt->mnt_sb, &name); #endif #else /* EFX_FSTYPE_HAS_MOUNT */ #ifdef EFX_HAVE_D_DNAME my_dentry = d_alloc(onload_mnt->mnt_sb->s_root, &name); #else { char str[32]; name.len = onloadfs_name(&container_of(inode, struct onload_inode, vfs_inode)->priv, str, sizeof(str)); name.name = str; name.hash = inode->i_ino; my_dentry = d_alloc(onload_mnt->mnt_sb->s_root, &name); } #endif #endif /* EFX_FSTYPE_HAS_MOUNT */ if( my_dentry == NULL ) { put_unused_fd(fd); iput(inode); return -ENOMEM; } #if !defined(EFX_FSTYPE_HAS_MOUNT) || defined(EFX_OLD_MOUNT_PSEUDO) my_dentry->d_op = &onloadfs_dentry_operations; #if !defined(EFX_HAVE_STRUCT_PATH) && defined(EFX_HAVE_D_DNAME) my_dentry->d_flags &= ~DCACHE_UNHASHED; #endif #endif d_instantiate(my_dentry, inode); #ifndef EFX_HAVE_D_DNAME d_rehash(my_dentry); #endif inode->i_fop = fops; #ifdef EFX_HAVE_STRUCT_PATH path.mnt = mntget(onload_mnt); file = alloc_file(&path, FMODE_READ | FMODE_WRITE, fops); #else file = alloc_file(onload_mnt, dentry, FMODE_READ | FMODE_WRITE, fops); #endif if( file == NULL) { #ifdef EFX_HAVE_STRUCT_PATH path_put(&path); #else dput(dentry); iput(inode); #endif put_unused_fd(fd); return -ENFILE; } priv->_filp = file; file->f_flags = O_RDWR | (flags & O_NONBLOCK); file->f_pos = 0; file->private_data = priv; if( flags & O_CLOEXEC ) { struct files_struct *files = current->files; struct fdtable *fdt; spin_lock(&files->file_lock); fdt = files_fdtable(files); rcu_assign_pointer(fdt->fd[fd], file); efx_set_close_on_exec(fd, fdt); spin_unlock(&files->file_lock); } else fd_install(fd, file); try_module_get(THIS_MODULE); ci_assert_equal(file->f_op, fops); return fd; } void onload_priv_free(ci_private_t *priv) { if( priv->_filp->f_vfsmnt != onload_mnt) ci_free(priv); /* inode will free the priv automatically */ } int oo_create_fd(tcp_helper_endpoint_t* ep, int flags, int fd_type) { int fd; tcp_helper_resource_t *trs = ep->thr; citp_waitable_obj *wo = SP_TO_WAITABLE_OBJ(&trs->netif, ep->id); efab_thr_ref(trs); fd = onload_alloc_file(trs, ep->id, flags, fd_type); if( fd < 0 ) { efab_thr_release(trs); OO_DEBUG_ERR(ci_log("%s: onload_alloc_file failed (%d)", __FUNCTION__, fd)); return fd; } ci_atomic32_and(&wo-> waitable.sb_aflags, ~(CI_SB_AFLAG_ORPHAN | CI_SB_AFLAG_TCP_IN_ACCEPTQ)); return fd; }
DENT_T * vnode_iop_lookup( INODE_T *dir, struct dentry *dent, struct nameidata *nd ) { char *name; mdki_boolean_t rele = FALSE; int err; VNODE_T *dvp; VNODE_T *rt_vnode; /* returned vnode */ INODE_T *rt_inode = NULL; /* returned inode ptr */ DENT_T * real_dentry; DENT_T *found_dentry = dent; VATTR_T *vap; struct lookup_ctx ctx; CALL_DATA_T cd; ASSERT_I_SEM_MINE(dir); /* We can find our parent entry via the dentry provided to us. */ ASSERT(dent->d_parent->d_inode == dir); if (dent->d_name.len > NAME_MAX) return ERR_PTR(-ENAMETOOLONG); name = /* drop the const */(char *) dent->d_name.name; mdki_linux_init_call_data(&cd); /* We pass along the dentry, as well as the parent inode so that * mvop_linux_lookup_* has everything it needs, even if it is passed in * the realvp, and it gets back a negative dentry. */ dvp = ITOV(dir); ctx.dentrypp = &found_dentry; ctx.flags = LOOKUP_CTX_VALID; err = VOP_LOOKUP(dvp, name, &rt_vnode, (struct pathname *)NULL, VNODE_LF_LOOKUP, NULL, &cd, &ctx); err = mdki_errno_unix_to_linux(err); if (!err) { ASSERT(rt_vnode != NULL); if (MDKI_INOISCLRVN(VTOI(rt_vnode))) { /* unwrap to the real object */ ASSERT(CVN_TO_DENT(rt_vnode)); rt_inode = CVN_TO_INO(rt_vnode); if (MDKI_INOISMVFS(rt_inode)) { VN_HOLD(ITOV(rt_inode)); VN_RELE(rt_vnode); rt_vnode = ITOV(rt_inode); } else { igrab(rt_inode); VN_RELE(rt_vnode); rt_vnode = NULL; } } else rt_inode = VTOI(rt_vnode); } if (!err && (found_dentry != dent)) { mdki_linux_destroy_call_data(&cd); /* The hold was granted in makeloopnode() in the 'nocover' case. */ if (rt_vnode != NULL) VN_RELE(rt_vnode); else iput(rt_inode); /* * found_dentry is the real socket/block/char device node's dentry. * See mvop_linux_lookup_component(). * * For sockets, we use a dentry in our tree (we fill in the * provided dentry "dent") linked to the inode of the real * object. This lets file name operations work in our * namespace, and lets socket connections all work (as they're * keyed off of the inode address) from inside to outside & * v.v. * * We also do this for VCHR, VBLK devices, and it seems to work OK * (e.g. make a node the same as /dev/tty, you can write to it) */ switch (found_dentry->d_inode->i_mode & S_IFMT) { case S_IFSOCK: case S_IFCHR: case S_IFBLK: ASSERT(dent->d_inode == NULL); MDKI_SET_DOPS(dent, &vnode_shadow_dentry_ops); igrab(found_dentry->d_inode); VNODE_D_ADD(dent, found_dentry->d_inode); VNODE_DPUT(found_dentry); found_dentry = NULL; /* tell caller to use original dentry */ break; default: /* use returned dentry */ break; } return(found_dentry); } /* We need to pass back dentry ops even for negative dentries, I think. * Shadow inodes will have been taken care of in lookup_component. */ if (dent->d_op != &vnode_shadow_dentry_ops) { if (dent->d_parent->d_op == &vnode_setview_dentry_ops) MDKI_SET_DOPS(dent, &vnode_setview_dentry_ops); else MDKI_SET_DOPS(dent, &vnode_dentry_ops); } vap = VATTR_ALLOC(); if (vap == NULL) { err = -ENOMEM; goto alloc_err; } if (!err && MDKI_INOISMVFS(rt_inode)) { /* fetch attributes & place in inode */ VATTR_SET_MASK(vap, AT_ALL); err = VOP_GETATTR(rt_vnode, vap, GETATTR_FLAG_UPDATE_ATTRS, &cd); err = mdki_errno_unix_to_linux(err); if (err == -EOPNOTSUPP) /* ignore it */ err = 0; else if (err) rele = TRUE; else if ((rt_vnode->v_flag & VLOOPROOT) != 0 && rt_inode == vnlayer_get_urdir_inode()) { /* return the real root */ VN_RELE(rt_vnode); VATTR_FREE(vap); mdki_linux_destroy_call_data(&cd); return VNODE_DGET(vnlayer_get_root_dentry()); } else if (vnlayer_looproot_vp != NULL && rt_vnode == vnlayer_looproot_vp && (real_dentry = MVOP_DENT(rt_inode, &vnode_dentry_ops)) != NULL) { /* return the real /view */ VN_RELE(rt_vnode); VATTR_FREE(vap); mdki_linux_destroy_call_data(&cd); return real_dentry; } } VATTR_FREE(vap); alloc_err: mdki_linux_destroy_call_data(&cd); /* It's an mnode-based object, set up a dentry for it */ /* We don't return ENOENT. For Linux, the negative dentry is enough */ switch (err) { case -ENOENT: err = 0; ASSERT(rt_inode == NULL); VNODE_D_ADD(dent, rt_inode); break; case 0: /* We will consume the count on rt_inode as a reference for dent */ /* * For VOB vnodes, we maintain two separate dentry trees for * the vnodes. One tree is for setview-mode names (process * sets to a view context, then looks directly at the VOB * mountpoint without any cover vnodes in the path). The * other tree is for view-extended naming into a VOB, with * dentries starting at the view tag and covering non-VOB * objects until crossing a mount point into a VOB. * * Mostly the system doesn't care, as long as it goes down the * tree from parent to child, since it will be traversing only one * of the dentry trees. But when the cache misses, the system calls * this lookup method and wants to get a dentry in return. * There are standard interfaces ( d_splice_alias() in 2.6) * which can find a good dentry referencing the inode returned * by the file system's lookup method, but these methods don't * work right when we have VOB directory vnodes with both setview * and view-extended dentries. We implement our own function * [vnlayer_inode2dentry_internal()] which knows the * distinctions and the rules for determining that an existing * attached dentry is valid for the lookup request. * * We have our own d_compare() function which forces all VOB * lookups to come to the inode lookup method (this function), * and then we get to choose the right dentry to return. We * have our own lookup cache inside MVFS so we don't care that * the dentry cache is always missing on our names. * * If we have to make a new dentry, we may need to merge it * with an NFS-created temporary dentry using d_move() * (d_splice_alias() would do this for us, but we can't use it * for reasons listed above). */ /* * We want to find the "right" dentry (if there is one), so * look for one that has a d_parent with the same dentry ops * (indicating it's in the same dentry tree). */ if (S_ISDIR(rt_inode->i_mode)) { /* * It has been empirically shown that we have to check the * parent of the dentry. If the parent has been checked out * it is possible for the cache lookup to return an inode * from the tree below the old parent directory. If this * happens on a rename, the system will panic because the * Linux rename code checks the parent of the returned * dentry to see that it matches what it has for a parent. */ found_dentry = vnlayer_inode2dentry_internal(rt_inode, dent->d_parent, NULL, dent->d_op); } else { /* * For non-directories, we also need to consider the * parent & the requested name so that * vnlayer_inode2dentry_internal() finds the right dentry. * (There may be multiple hard links; we want the one in * the same directory with the same name) */ found_dentry = vnlayer_inode2dentry_internal(rt_inode, dent->d_parent, &dent->d_name, dent->d_op); } if (found_dentry != NULL) { ASSERT(found_dentry->d_inode == rt_inode); /* * If the existing one is a disconnected dentry, we need * to move the old one to the new one (just like * d_splice_alias) to get the proper name/parent attached * in the dcache. */ if ((found_dentry->d_flags & DCACHE_DISCONNECTED) != 0) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,7) ASSERT((dent->d_flags & DCACHE_UNHASHED) != 0); #else ASSERT((dent->d_vfs_flags & DCACHE_UNHASHED) != 0); #endif d_rehash(dent); d_move(found_dentry, dent); } /* Release our count. found_dentry also references inode. */ iput(rt_inode); return found_dentry; } /* * Nothing suitable, wire it up to the proposed dentry. */ VNODE_D_ADD(dent, rt_inode); break; default: /* some other error case */ if (rele) VN_RELE(rt_vnode); break; } if (err) return ERR_PTR(err); else return NULL; }
static int hpfs_unlink(struct inode *dir, struct dentry *dentry) { const unsigned char *name = dentry->d_name.name; unsigned len = dentry->d_name.len; struct quad_buffer_head qbh; struct hpfs_dirent *de; struct inode *inode = dentry->d_inode; dnode_secno dno; int r; int rep = 0; int err; hpfs_lock(dir->i_sb); hpfs_adjust_length(name, &len); again: err = -ENOENT; de = map_dirent(dir, hpfs_i(dir)->i_dno, name, len, &dno, &qbh); if (!de) goto out; err = -EPERM; if (de->first) goto out1; err = -EISDIR; if (de->directory) goto out1; r = hpfs_remove_dirent(dir, dno, de, &qbh, 1); switch (r) { case 1: hpfs_error(dir->i_sb, "there was error when removing dirent"); err = -EFSERROR; break; case 2: /* no space for deleting, try to truncate file */ err = -ENOSPC; if (rep++) break; dentry_unhash(dentry); if (!d_unhashed(dentry)) { hpfs_unlock(dir->i_sb); return -ENOSPC; } if (generic_permission(inode, MAY_WRITE) || !S_ISREG(inode->i_mode) || get_write_access(inode)) { d_rehash(dentry); } else { struct iattr newattrs; /*printk("HPFS: truncating file before delete.\n");*/ newattrs.ia_size = 0; newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; err = notify_change(dentry, &newattrs); put_write_access(inode); if (!err) goto again; } hpfs_unlock(dir->i_sb); return -ENOSPC; default: drop_nlink(inode); err = 0; } goto out; out1: hpfs_brelse4(&qbh); out: if (!err) hpfs_update_directory_times(dir); hpfs_unlock(dir->i_sb); 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; }