/* * NAME: jfs_mknod * * FUNCTION: Create a special file (device) */ static int jfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) { struct jfs_inode_info *jfs_ip; struct btstack btstack; struct component_name dname; ino_t ino; struct inode *ip; struct inode *iplist[2]; int rc; tid_t tid; struct tblock *tblk; if (!new_valid_dev(rdev)) return -EINVAL; jfs_info("jfs_mknod: %s", dentry->d_name.name); if ((rc = get_UCSname(&dname, dentry))) goto out; ip = ialloc(dir, mode); if (ip == NULL) { rc = -ENOSPC; goto out1; } jfs_ip = JFS_IP(ip); tid = txBegin(dir->i_sb, 0); down(&JFS_IP(dir)->commit_sem); down(&JFS_IP(ip)->commit_sem); rc = jfs_init_acl(tid, ip, dir); if (rc) goto out3; rc = jfs_init_security(tid, ip, dir); if (rc) { txAbort(tid, 0); goto out3; } if ((rc = dtSearch(dir, &dname, &ino, &btstack, JFS_CREATE))) { txAbort(tid, 0); goto out3; } tblk = tid_to_tblock(tid); tblk->xflag |= COMMIT_CREATE; tblk->ino = ip->i_ino; tblk->u.ixpxd = JFS_IP(ip)->ixpxd; ino = ip->i_ino; if ((rc = dtInsert(tid, dir, &dname, &ino, &btstack))) { txAbort(tid, 0); goto out3; } ip->i_op = &jfs_file_inode_operations; jfs_ip->dev = new_encode_dev(rdev); init_special_inode(ip, ip->i_mode, rdev); insert_inode_hash(ip); mark_inode_dirty(ip); dir->i_ctime = dir->i_mtime = CURRENT_TIME; mark_inode_dirty(dir); iplist[0] = dir; iplist[1] = ip; rc = txCommit(tid, 2, iplist, 0); out3: txEnd(tid); up(&JFS_IP(ip)->commit_sem); up(&JFS_IP(dir)->commit_sem); if (rc) { free_ea_wmap(ip); ip->i_nlink = 0; iput(ip); } else d_instantiate(dentry, ip); out1: free_UCSname(&dname); out: jfs_info("jfs_mknod: returning %d", rc); return rc; }
/** * 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_getfd() will share a single inode, * hence saving memory and avoiding code duplication for the file/inode/dentry * setup. Returns new descriptor or -error. */ int anon_inode_getfd(const char *name, const struct file_operations *fops, void *priv, int flags) { struct qstr this; struct dentry *dentry; struct file *file; int error, fd; if (IS_ERR(anon_inode_inode)) return -ENODEV; if (fops->owner && !try_module_get(fops->owner)) return -ENOENT; error = get_unused_fd_flags(flags); if (error < 0) goto err_module; fd = error; /* * 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_put_unused_fd; /* * 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; fd_install(fd, file); return fd; err_dput: dput(dentry); err_put_unused_fd: put_unused_fd(fd); err_module: module_put(fops->owner); return error; }
int aufs_link(struct dentry *src_dentry, struct inode *dir, struct dentry *dentry) { int err, rerr; struct au_dtime dt; struct au_link_args *a; struct dentry *wh_dentry, *h_src_dentry; struct inode *inode; struct super_block *sb; struct au_wr_dir_args wr_dir_args = { /* .force_btgt = -1, */ .flags = AuWrDir_ADD_ENTRY }; IMustLock(dir); inode = src_dentry->d_inode; IMustLock(inode); err = -ENOMEM; a = kzalloc(sizeof(*a), GFP_NOFS); if (unlikely(!a)) goto out; a->parent = dentry->d_parent; /* dir inode is locked */ err = aufs_read_and_write_lock2(dentry, src_dentry, AuLock_NOPLM | AuLock_GEN); if (unlikely(err)) goto out_kfree; err = au_d_hashed_positive(src_dentry); if (unlikely(err)) goto out_unlock; err = au_d_may_add(dentry); if (unlikely(err)) goto out_unlock; a->src_parent = dget_parent(src_dentry); wr_dir_args.force_btgt = au_ibstart(inode); di_write_lock_parent(a->parent); wr_dir_args.force_btgt = au_wbr(dentry, wr_dir_args.force_btgt); wh_dentry = lock_hdir_lkup_wh(dentry, &dt, src_dentry, &a->pin, &wr_dir_args); err = PTR_ERR(wh_dentry); if (IS_ERR(wh_dentry)) goto out_parent; err = 0; sb = dentry->d_sb; a->bdst = au_dbstart(dentry); a->h_path.dentry = au_h_dptr(dentry, a->bdst); a->h_path.mnt = au_sbr_mnt(sb, a->bdst); a->bsrc = au_ibstart(inode); h_src_dentry = au_h_d_alias(src_dentry, a->bsrc); if (!h_src_dentry) { a->bsrc = au_dbstart(src_dentry); h_src_dentry = au_h_d_alias(src_dentry, a->bsrc); AuDebugOn(!h_src_dentry); } else if (IS_ERR(h_src_dentry)) goto out_parent; if (au_opt_test(au_mntflags(sb), PLINK)) { if (a->bdst < a->bsrc /* && h_src_dentry->d_sb != a->h_path.dentry->d_sb */) err = au_cpup_or_link(src_dentry, a); else err = vfsub_link(h_src_dentry, au_pinned_h_dir(&a->pin), &a->h_path); dput(h_src_dentry); } else { /* * copyup src_dentry to the branch we process, * and then link(2) to it. */ dput(h_src_dentry); if (a->bdst < a->bsrc /* && h_src_dentry->d_sb != a->h_path.dentry->d_sb */) { au_unpin(&a->pin); di_write_unlock(a->parent); err = au_cpup_before_link(src_dentry, a); di_write_lock_parent(a->parent); if (!err) err = au_pin(&a->pin, dentry, a->bdst, au_opt_udba(sb), AuPin_DI_LOCKED | AuPin_MNT_WRITE); if (unlikely(err)) goto out_wh; } if (!err) { h_src_dentry = au_h_dptr(src_dentry, a->bdst); err = -ENOENT; if (h_src_dentry && h_src_dentry->d_inode) err = vfsub_link(h_src_dentry, au_pinned_h_dir(&a->pin), &a->h_path); } } if (unlikely(err)) goto out_unpin; if (wh_dentry) { a->h_path.dentry = wh_dentry; err = au_wh_unlink_dentry(au_pinned_h_dir(&a->pin), &a->h_path, dentry); if (unlikely(err)) goto out_revert; } dir->i_version++; if (au_ibstart(dir) == au_dbstart(dentry)) au_cpup_attr_timesizes(dir); inc_nlink(inode); inode->i_ctime = dir->i_ctime; d_instantiate(dentry, au_igrab(inode)); if (d_unhashed(a->h_path.dentry)) /* some filesystem calls d_drop() */ d_drop(dentry); goto out_unpin; /* success */ out_revert: rerr = vfsub_unlink(au_pinned_h_dir(&a->pin), &a->h_path, /*force*/0); if (unlikely(rerr)) { AuIOErr("%.*s reverting failed(%d, %d)\n", AuDLNPair(dentry), err, rerr); err = -EIO; } au_dtime_revert(&dt); out_unpin: au_unpin(&a->pin); out_wh: dput(wh_dentry); out_parent: di_write_unlock(a->parent); dput(a->src_parent); out_unlock: if (unlikely(err)) { au_update_dbstart(dentry); d_drop(dentry); } aufs_read_and_write_unlock2(dentry, src_dentry); out_kfree: kfree(a); out: return err; }
/* * Code shared between mknod, mkdir, symlink and link */ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, struct inode *dir, struct dentry *entry, umode_t mode) { struct fuse_entry_out outarg; struct inode *inode; int err; struct fuse_forget_link *forget; forget = fuse_alloc_forget(); if (!forget) { fuse_put_request(fc, req); return -ENOMEM; } memset(&outarg, 0, sizeof(outarg)); req->in.h.nodeid = get_node_id(dir); req->out.numargs = 1; if (fc->minor < 9) req->out.args[0].size = FUSE_COMPAT_ENTRY_OUT_SIZE; else req->out.args[0].size = sizeof(outarg); req->out.args[0].value = &outarg; fuse_request_send(fc, req); err = req->out.h.error; fuse_put_request(fc, req); if (err) goto out_put_forget_req; err = -EIO; if (invalid_nodeid(outarg.nodeid)) goto out_put_forget_req; if ((outarg.attr.mode ^ mode) & S_IFMT) goto out_put_forget_req; inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, &outarg.attr, entry_attr_timeout(&outarg), 0); if (!inode) { fuse_queue_forget(fc, forget, outarg.nodeid, 1); return -ENOMEM; } kfree(forget); if (S_ISDIR(inode->i_mode)) { struct dentry *alias; mutex_lock(&fc->inst_mutex); alias = d_find_alias(inode); if (alias) { /* New directory must have moved since mkdir */ mutex_unlock(&fc->inst_mutex); dput(alias); iput(inode); return -EBUSY; } d_instantiate(entry, inode); mutex_unlock(&fc->inst_mutex); } else d_instantiate(entry, inode); fuse_change_entry_timeout(entry, &outarg); fuse_invalidate_attr(dir); return 0; out_put_forget_req: kfree(forget); return err; }
static int gfs2_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) { struct gfs2_inode *dip = GFS2_I(dir); struct gfs2_sbd *sdp = GFS2_SB(dir); struct inode *inode = old_dentry->d_inode; struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_holder ghs[2]; int alloc_required; int error; if (S_ISDIR(inode->i_mode)) return -EPERM; gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs); gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1); error = gfs2_glock_nq(ghs); /* parent */ if (error) goto out_parent; error = gfs2_glock_nq(ghs + 1); /* child */ if (error) goto out_child; error = gfs2_permission(dir, MAY_WRITE | MAY_EXEC); if (error) goto out_gunlock; error = gfs2_dir_check(dir, &dentry->d_name, NULL); switch (error) { case -ENOENT: break; case 0: error = -EEXIST; default: goto out_gunlock; } error = -EINVAL; if (!dip->i_inode.i_nlink) goto out_gunlock; error = -EFBIG; if (dip->i_di.di_entries == (u32)-1) goto out_gunlock; error = -EPERM; if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) goto out_gunlock; error = -EINVAL; if (!ip->i_inode.i_nlink) goto out_gunlock; error = -EMLINK; if (ip->i_inode.i_nlink == (u32)-1) goto out_gunlock; alloc_required = error = gfs2_diradd_alloc_required(dir, &dentry->d_name); if (error < 0) goto out_gunlock; error = 0; if (alloc_required) { struct gfs2_alloc *al = gfs2_alloc_get(dip); if (!al) { error = -ENOMEM; goto out_gunlock; } error = gfs2_quota_lock_check(dip); if (error) goto out_alloc; al->al_requested = sdp->sd_max_dirres; error = gfs2_inplace_reserve(dip); if (error) goto out_gunlock_q; error = gfs2_trans_begin(sdp, sdp->sd_max_dirres + al->al_rgd->rd_length + 2 * RES_DINODE + RES_STATFS + RES_QUOTA, 0); if (error) goto out_ipres; } else { error = gfs2_trans_begin(sdp, 2 * RES_DINODE + RES_LEAF, 0); if (error) goto out_ipres; } error = gfs2_dir_add(dir, &dentry->d_name, ip, IF2DT(inode->i_mode)); if (error) goto out_end_trans; error = gfs2_change_nlink(ip, +1); out_end_trans: gfs2_trans_end(sdp); out_ipres: if (alloc_required) gfs2_inplace_release(dip); out_gunlock_q: if (alloc_required) gfs2_quota_unlock(dip); out_alloc: if (alloc_required) gfs2_alloc_put(dip); out_gunlock: gfs2_glock_dq(ghs + 1); out_child: gfs2_glock_dq(ghs); out_parent: gfs2_holder_uninit(ghs); gfs2_holder_uninit(ghs + 1); if (!error) { atomic_inc(&inode->i_count); d_instantiate(dentry, inode); mark_inode_dirty(inode); } return error; }
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; }
/***** Make a directory */ int msdos_mkdir(struct inode *dir,struct dentry *dentry,int mode) { struct super_block *sb = dir->i_sb; struct buffer_head *bh; struct msdos_dir_entry *de; struct inode *inode; int res,is_hid; char msdos_name[MSDOS_NAME]; int ino; res = msdos_format_name(dentry->d_name.name,dentry->d_name.len, msdos_name, &MSDOS_SB(sb)->options); if (res < 0) return res; is_hid = (dentry->d_name.name[0]=='.') && (msdos_name[0]!='.'); /* foo vs .foo situation */ if (fat_scan(dir,msdos_name,&bh,&de,&ino) >= 0) goto out_exist; res = msdos_add_entry(dir, msdos_name, &bh, &de, &ino, 1, is_hid); if (res) goto out_unlock; inode = fat_build_inode(dir->i_sb, de, ino, &res); if (!inode) { fat_brelse(sb, bh); goto out_unlock; } res = 0; dir->i_nlink++; inode->i_nlink = 2; /* no need to mark them dirty */ res = fat_new_dir(inode, dir, 0); if (res) goto mkdir_error; fat_brelse(sb, bh); d_instantiate(dentry, inode); res = 0; out_unlock: return res; mkdir_error: printk("msdos_mkdir: error=%d, attempting cleanup\n", res); inode->i_nlink = 0; inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; dir->i_nlink--; mark_inode_dirty(inode); mark_inode_dirty(dir); de->name[0] = DELETED_FLAG; fat_mark_buffer_dirty(sb, bh); fat_brelse(sb, bh); fat_detach(inode); iput(inode); goto out_unlock; out_exist: fat_brelse(sb, bh); res = -EINVAL; goto out_unlock; }
static int reiserfs_symlink(struct inode *parent_dir, struct dentry *dentry, const char *symname) { int retval; struct inode *inode; char *name; int item_len; struct reiserfs_transaction_handle th; struct reiserfs_security_handle security; int mode = S_IFLNK | S_IRWXUGO; /* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */ int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 2 * (REISERFS_QUOTA_INIT_BLOCKS(parent_dir->i_sb) + REISERFS_QUOTA_TRANS_BLOCKS(parent_dir->i_sb)); dquot_initialize(parent_dir); if (!(inode = new_inode(parent_dir->i_sb))) { return -ENOMEM; } new_inode_init(inode, parent_dir, mode); retval = reiserfs_security_init(parent_dir, inode, &dentry->d_name, &security); if (retval < 0) { drop_new_inode(inode); return retval; } jbegin_count += retval; reiserfs_write_lock(parent_dir->i_sb); item_len = ROUND_UP(strlen(symname)); if (item_len > MAX_DIRECT_ITEM_LEN(parent_dir->i_sb->s_blocksize)) { retval = -ENAMETOOLONG; drop_new_inode(inode); goto out_failed; } name = kmalloc(item_len, GFP_NOFS); if (!name) { drop_new_inode(inode); retval = -ENOMEM; goto out_failed; } memcpy(name, symname, strlen(symname)); padd_item(name, item_len, strlen(symname)); retval = journal_begin(&th, parent_dir->i_sb, jbegin_count); if (retval) { drop_new_inode(inode); kfree(name); goto out_failed; } retval = reiserfs_new_inode(&th, parent_dir, mode, name, strlen(symname), dentry, inode, &security); kfree(name); if (retval) { /* reiserfs_new_inode iputs for us */ goto out_failed; } reiserfs_update_inode_transaction(inode); reiserfs_update_inode_transaction(parent_dir); inode->i_op = &reiserfs_symlink_inode_operations; inode->i_mapping->a_ops = &reiserfs_address_space_operations; // must be sure this inode is written with this transaction // //reiserfs_update_sd (&th, inode, READ_BLOCKS); retval = reiserfs_add_entry(&th, parent_dir, dentry->d_name.name, dentry->d_name.len, inode, 1 /*visible */ ); if (retval) { int err; inode->i_nlink--; reiserfs_update_sd(&th, inode); err = journal_end(&th, parent_dir->i_sb, jbegin_count); if (err) retval = err; unlock_new_inode(inode); iput(inode); goto out_failed; } d_instantiate(dentry, inode); unlock_new_inode(inode); retval = journal_end(&th, parent_dir->i_sb, jbegin_count); out_failed: reiserfs_write_unlock(parent_dir->i_sb); return retval; }
static int reiserfs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd) { int retval; struct inode *inode; /* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */ int jbegin_count = JOURNAL_PER_BALANCE_CNT * 2 + 2 * (REISERFS_QUOTA_INIT_BLOCKS(dir->i_sb) + REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb)); struct reiserfs_transaction_handle th; struct reiserfs_security_handle security; dquot_initialize(dir); if (!(inode = new_inode(dir->i_sb))) { return -ENOMEM; } new_inode_init(inode, dir, mode); jbegin_count += reiserfs_cache_default_acl(dir); retval = reiserfs_security_init(dir, inode, &dentry->d_name, &security); if (retval < 0) { drop_new_inode(inode); return retval; } jbegin_count += retval; reiserfs_write_lock(dir->i_sb); retval = journal_begin(&th, dir->i_sb, jbegin_count); if (retval) { drop_new_inode(inode); goto out_failed; } retval = reiserfs_new_inode(&th, dir, mode, NULL, 0 /*i_size */ , dentry, inode, &security); if (retval) goto out_failed; inode->i_op = &reiserfs_file_inode_operations; inode->i_fop = &reiserfs_file_operations; inode->i_mapping->a_ops = &reiserfs_address_space_operations; retval = reiserfs_add_entry(&th, dir, dentry->d_name.name, dentry->d_name.len, inode, 1 /*visible */ ); if (retval) { int err; inode->i_nlink--; reiserfs_update_sd(&th, inode); err = journal_end(&th, dir->i_sb, jbegin_count); if (err) retval = err; unlock_new_inode(inode); iput(inode); goto out_failed; } reiserfs_update_inode_transaction(inode); reiserfs_update_inode_transaction(dir); d_instantiate(dentry, inode); unlock_new_inode(inode); retval = journal_end(&th, dir->i_sb, jbegin_count); out_failed: reiserfs_write_unlock(dir->i_sb); return retval; }
void *ns_get_path(struct path *path, struct task_struct *task, const struct proc_ns_operations *ns_ops) { struct vfsmount *mnt = mntget(nsfs_mnt); struct qstr qname = { .name = "", }; struct dentry *dentry; struct inode *inode; struct ns_common *ns; unsigned long d; again: ns = ns_ops->get(task); if (!ns) { mntput(mnt); return ERR_PTR(-ENOENT); } rcu_read_lock(); d = atomic_long_read(&ns->stashed); if (!d) goto slow; dentry = (struct dentry *)d; if (!lockref_get_not_dead(&dentry->d_lockref)) goto slow; rcu_read_unlock(); ns_ops->put(ns); got_it: path->mnt = mnt; path->dentry = dentry; return NULL; slow: rcu_read_unlock(); inode = new_inode_pseudo(mnt->mnt_sb); if (!inode) { ns_ops->put(ns); mntput(mnt); return ERR_PTR(-ENOMEM); } inode->i_ino = ns->inum; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; inode->i_flags |= S_IMMUTABLE; inode->i_mode = S_IFREG | S_IRUGO; inode->i_fop = &ns_file_operations; inode->i_private = ns; dentry = d_alloc_pseudo(mnt->mnt_sb, &qname); if (!dentry) { iput(inode); mntput(mnt); return ERR_PTR(-ENOMEM); } d_instantiate(dentry, inode); dentry->d_fsdata = (void *)ns_ops; d = atomic_long_cmpxchg(&ns->stashed, 0, (unsigned long)dentry); if (d) { d_delete(dentry); /* make sure ->d_prune() does nothing */ dput(dentry); cpu_relax(); goto again; } goto got_it; } int ns_get_name(char *buf, size_t size, struct task_struct *task, const struct proc_ns_operations *ns_ops) { struct ns_common *ns; int res = -ENOENT; ns = ns_ops->get(task); if (ns) { res = snprintf(buf, size, "%s:[%u]", ns_ops->name, ns->inum); ns_ops->put(ns); } return res; } struct file *proc_ns_fget(int fd) { struct file *file; file = fget(fd); if (!file) return ERR_PTR(-EBADF); if (file->f_op != &ns_file_operations) goto out_invalid; return file; out_invalid: fput(file); return ERR_PTR(-EINVAL); } static const struct super_operations nsfs_ops = { .statfs = simple_statfs, .evict_inode = nsfs_evict, }; static struct dentry *nsfs_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { return mount_pseudo(fs_type, "nsfs:", &nsfs_ops, &ns_dentry_operations, NSFS_MAGIC); } static struct file_system_type nsfs = { .name = "nsfs", .mount = nsfs_mount, .kill_sb = kill_anon_super, }; void __init nsfs_init(void) { nsfs_mnt = kern_mount(&nsfs); if (IS_ERR(nsfs_mnt)) panic("can't set nsfs up\n"); nsfs_mnt->mnt_sb->s_flags &= ~MS_NOUSER; }
int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) { int rc = 0; int xid; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; char *full_path = NULL; struct inode *newinode = NULL; cFYI(1, ("In cifs_mkdir, mode = 0x%x inode = 0x%p ", mode, inode)); xid = GetXid(); cifs_sb = CIFS_SB(inode->i_sb); pTcon = cifs_sb->tcon; down(&inode->i_sb->s_vfs_rename_sem); full_path = build_path_from_dentry(direntry); up(&inode->i_sb->s_vfs_rename_sem); if (full_path == NULL) { FreeXid(xid); return -ENOMEM; } /* BB add setting the equivalent of mode via CreateX w/ACLs */ rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc) { cFYI(1, ("cifs_mkdir returned 0x%x ", rc)); d_drop(direntry); } else { inode->i_nlink++; if (pTcon->ses->capabilities & CAP_UNIX) rc = cifs_get_inode_info_unix(&newinode, full_path, inode->i_sb,xid); else rc = cifs_get_inode_info(&newinode, full_path, NULL, inode->i_sb,xid); direntry->d_op = &cifs_dentry_ops; d_instantiate(direntry, newinode); if (direntry->d_inode) direntry->d_inode->i_nlink = 2; if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, (__u64)current->euid, (__u64)current->egid, 0 /* dev_t */, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); } else { CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, (__u64)-1, (__u64)-1, 0 /* dev_t */, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); } else { /* BB to be implemented via Windows secrty descriptors eg CIFSSMBWinSetPerms(xid, pTcon, full_path, mode, -1, -1, local_nls); */ } } kfree(full_path); FreeXid(xid); return rc; }
static int jfs_symlink(struct inode *dip, struct dentry *dentry, const char *name) { int rc; tid_t tid; ino_t ino = 0; struct component_name dname; int ssize; /* source pathname size */ struct btstack btstack; struct inode *ip = dentry->d_inode; unchar *i_fastsymlink; s64 xlen = 0; int bmask = 0, xsize; s64 extent = 0, xaddr; struct metapage *mp; struct super_block *sb; struct tblock *tblk; struct inode *iplist[2]; jfs_info("jfs_symlink: dip:0x%p name:%s", dip, name); ssize = strlen(name) + 1; /* * search parent directory for entry/freespace * (dtSearch() returns parent directory page pinned) */ if ((rc = get_UCSname(&dname, dentry))) goto out1; /* * allocate on-disk/in-memory inode for symbolic link: * (iAlloc() returns new, locked inode) */ ip = ialloc(dip, S_IFLNK | 0777); if (ip == NULL) { rc = -ENOSPC; goto out2; } tid = txBegin(dip->i_sb, 0); down(&JFS_IP(dip)->commit_sem); down(&JFS_IP(ip)->commit_sem); rc = jfs_init_security(tid, ip, dip); if (rc) goto out3; tblk = tid_to_tblock(tid); tblk->xflag |= COMMIT_CREATE; tblk->ino = ip->i_ino; tblk->u.ixpxd = JFS_IP(ip)->ixpxd; /* fix symlink access permission * (dir_create() ANDs in the u.u_cmask, * but symlinks really need to be 777 access) */ ip->i_mode |= 0777; /* * write symbolic link target path name */ xtInitRoot(tid, ip); /* * write source path name inline in on-disk inode (fast symbolic link) */ if (ssize <= IDATASIZE) { ip->i_op = &jfs_symlink_inode_operations; i_fastsymlink = JFS_IP(ip)->i_inline; memcpy(i_fastsymlink, name, ssize); ip->i_size = ssize - 1; /* * if symlink is > 128 bytes, we don't have the space to * store inline extended attributes */ if (ssize > sizeof (JFS_IP(ip)->i_inline)) JFS_IP(ip)->mode2 &= ~INLINEEA; jfs_info("jfs_symlink: fast symlink added ssize:%d name:%s ", ssize, name); } /* * write source path name in a single extent */ else { jfs_info("jfs_symlink: allocate extent ip:0x%p", ip); ip->i_op = &page_symlink_inode_operations; ip->i_mapping->a_ops = &jfs_aops; /* * even though the data of symlink object (source * path name) is treated as non-journaled user data, * it is read/written thru buffer cache for performance. */ sb = ip->i_sb; bmask = JFS_SBI(sb)->bsize - 1; xsize = (ssize + bmask) & ~bmask; xaddr = 0; xlen = xsize >> JFS_SBI(sb)->l2bsize; if ((rc = xtInsert(tid, ip, 0, 0, xlen, &xaddr, 0))) { txAbort(tid, 0); rc = -ENOSPC; goto out3; } extent = xaddr; ip->i_size = ssize - 1; while (ssize) { /* This is kind of silly since PATH_MAX == 4K */ int copy_size = min(ssize, PSIZE); mp = get_metapage(ip, xaddr, PSIZE, 1); if (mp == NULL) { xtTruncate(tid, ip, 0, COMMIT_PWMAP); rc = -EIO; txAbort(tid, 0); goto out3; } memcpy(mp->data, name, copy_size); flush_metapage(mp); ssize -= copy_size; name += copy_size; xaddr += JFS_SBI(sb)->nbperpage; } } /* * create entry for symbolic link in parent directory */ rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE); if (rc == 0) { ino = ip->i_ino; rc = dtInsert(tid, dip, &dname, &ino, &btstack); } if (rc) { if (xlen) xtTruncate(tid, ip, 0, COMMIT_PWMAP); txAbort(tid, 0); /* discard new inode */ goto out3; } insert_inode_hash(ip); mark_inode_dirty(ip); /* * commit update of parent directory and link object */ iplist[0] = dip; iplist[1] = ip; rc = txCommit(tid, 2, &iplist[0], 0); out3: txEnd(tid); up(&JFS_IP(dip)->commit_sem); up(&JFS_IP(ip)->commit_sem); if (rc) { free_ea_wmap(ip); ip->i_nlink = 0; iput(ip); } else d_instantiate(dentry, ip); out2: free_UCSname(&dname); out1: jfs_info("jfs_symlink: rc:%d", rc); return rc; }
/* * NAME: jfs_link(vp, dvp, name, crp) * * FUNCTION: create a link to <vp> by the name = <name> * in the parent directory <dvp> * * PARAMETER: vp - target object * dvp - parent directory of new link * name - name of new link to target object * crp - credential * * RETURN: Errors from subroutines * * note: * JFS does NOT support link() on directories (to prevent circular * path in the directory hierarchy); * EPERM: the target object is a directory, and either the caller * does not have appropriate privileges or the implementation prohibits * using link() on directories [XPG4.2]. * * JFS does NOT support links between file systems: * EXDEV: target object and new link are on different file systems and * implementation does not support links between file systems [XPG4.2]. */ static int jfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) { int rc; tid_t tid; struct inode *ip = old_dentry->d_inode; ino_t ino; struct component_name dname; struct btstack btstack; struct inode *iplist[2]; jfs_info("jfs_link: %s %s", old_dentry->d_name.name, dentry->d_name.name); if (ip->i_nlink == JFS_LINK_MAX) return -EMLINK; if (ip->i_nlink == 0) return -ENOENT; tid = txBegin(ip->i_sb, 0); down(&JFS_IP(dir)->commit_sem); down(&JFS_IP(ip)->commit_sem); /* * scan parent directory for entry/freespace */ if ((rc = get_UCSname(&dname, dentry))) goto out; if ((rc = dtSearch(dir, &dname, &ino, &btstack, JFS_CREATE))) goto free_dname; /* * create entry for new link in parent directory */ ino = ip->i_ino; if ((rc = dtInsert(tid, dir, &dname, &ino, &btstack))) goto free_dname; /* update object inode */ ip->i_nlink++; /* for new link */ ip->i_ctime = CURRENT_TIME; mark_inode_dirty(dir); atomic_inc(&ip->i_count); iplist[0] = ip; iplist[1] = dir; rc = txCommit(tid, 2, &iplist[0], 0); if (rc) { ip->i_nlink--; iput(ip); } else d_instantiate(dentry, ip); free_dname: free_UCSname(&dname); out: txEnd(tid); up(&JFS_IP(dir)->commit_sem); up(&JFS_IP(ip)->commit_sem); jfs_info("jfs_link: rc:%d", rc); return rc; }
/* * NAME: jfs_create(dip, dentry, mode) * * FUNCTION: create a regular file in the parent directory <dip> * with name = <from dentry> and mode = <mode> * * PARAMETER: dip - parent directory vnode * dentry - dentry of new file * mode - create mode (rwxrwxrwx). * nd- nd struct * * RETURN: Errors from subroutines * */ static int jfs_create(struct inode *dip, struct dentry *dentry, int mode, struct nameidata *nd) { int rc = 0; tid_t tid; /* transaction id */ struct inode *ip = NULL; /* child directory inode */ ino_t ino; struct component_name dname; /* child directory name */ struct btstack btstack; struct inode *iplist[2]; struct tblock *tblk; jfs_info("jfs_create: dip:0x%p name:%s", dip, dentry->d_name.name); /* * search parent directory for entry/freespace * (dtSearch() returns parent directory page pinned) */ if ((rc = get_UCSname(&dname, dentry))) goto out1; /* * Either iAlloc() or txBegin() may block. Deadlock can occur if we * block there while holding dtree page, so we allocate the inode & * begin the transaction before we search the directory. */ ip = ialloc(dip, mode); if (ip == NULL) { rc = -ENOSPC; goto out2; } tid = txBegin(dip->i_sb, 0); down(&JFS_IP(dip)->commit_sem); down(&JFS_IP(ip)->commit_sem); rc = jfs_init_acl(tid, ip, dip); if (rc) goto out3; rc = jfs_init_security(tid, ip, dip); if (rc) { txAbort(tid, 0); goto out3; } if ((rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE))) { jfs_err("jfs_create: dtSearch returned %d", rc); txAbort(tid, 0); goto out3; } tblk = tid_to_tblock(tid); tblk->xflag |= COMMIT_CREATE; tblk->ino = ip->i_ino; tblk->u.ixpxd = JFS_IP(ip)->ixpxd; iplist[0] = dip; iplist[1] = ip; /* * initialize the child XAD tree root in-line in inode */ xtInitRoot(tid, ip); /* * create entry in parent directory for child directory * (dtInsert() releases parent directory page) */ ino = ip->i_ino; if ((rc = dtInsert(tid, dip, &dname, &ino, &btstack))) { if (rc == -EIO) { jfs_err("jfs_create: dtInsert returned -EIO"); txAbort(tid, 1); /* Marks Filesystem dirty */ } else txAbort(tid, 0); /* Filesystem full */ goto out3; } ip->i_op = &jfs_file_inode_operations; ip->i_fop = &jfs_file_operations; ip->i_mapping->a_ops = &jfs_aops; insert_inode_hash(ip); mark_inode_dirty(ip); dip->i_ctime = dip->i_mtime = CURRENT_TIME; mark_inode_dirty(dip); rc = txCommit(tid, 2, &iplist[0], 0); out3: txEnd(tid); up(&JFS_IP(dip)->commit_sem); up(&JFS_IP(ip)->commit_sem); if (rc) { free_ea_wmap(ip); ip->i_nlink = 0; iput(ip); } else d_instantiate(dentry, ip); out2: free_UCSname(&dname); out1: jfs_info("jfs_create: rc:%d", rc); return rc; }
struct dentry *f2fs_get_parent(struct dentry *child) { struct qstr dotdot = {.len = 2, .name = ".."}; unsigned long ino = f2fs_inode_by_name(child->d_inode, &dotdot); if (!ino) return ERR_PTR(-ENOENT); return d_obtain_alias(f2fs_iget(child->d_inode->i_sb, ino)); } static int __recover_dot_dentries(struct inode *dir, nid_t pino) { struct f2fs_sb_info *sbi = F2FS_I_SB(dir); struct qstr dot = {.len = 1, .name = "."}; struct qstr dotdot = {.len = 2, .name = ".."}; struct f2fs_dir_entry *de; struct page *page; int err = 0; f2fs_lock_op(sbi); de = f2fs_find_entry(dir, &dot, &page, 0); if (de) { f2fs_dentry_kunmap(dir, page); f2fs_put_page(page, 0); } else { err = __f2fs_add_link(dir, &dot, NULL, dir->i_ino, S_IFDIR); if (err) goto out; } de = f2fs_find_entry(dir, &dotdot, &page, 0); if (de) { f2fs_dentry_kunmap(dir, page); f2fs_put_page(page, 0); } else { err = __f2fs_add_link(dir, &dotdot, NULL, pino, S_IFDIR); } out: if (!err) { clear_inode_flag(F2FS_I(dir), FI_INLINE_DOTS); mark_inode_dirty(dir); } f2fs_unlock_op(sbi); return err; } static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { struct inode *inode = NULL; struct f2fs_dir_entry *de; struct page *page; nid_t ino; int err = 0; if (dentry->d_name.len > F2FS_NAME_LEN) return ERR_PTR(-ENAMETOOLONG); de = f2fs_find_entry(dir, &dentry->d_name, &page, nd ? nd->flags : 0); if (!de) return d_splice_alias(inode, dentry); ino = le32_to_cpu(de->ino); f2fs_dentry_kunmap(dir, page); f2fs_put_page(page, 0); inode = f2fs_iget(dir->i_sb, ino); if (IS_ERR(inode)) return ERR_CAST(inode); if (f2fs_has_inline_dots(inode)) { err = __recover_dot_dentries(inode, dir->i_ino); if (err) goto err_out; } return d_splice_alias(inode, dentry); err_out: iget_failed(inode); return ERR_PTR(err); } static int f2fs_unlink(struct inode *dir, struct dentry *dentry) { struct f2fs_sb_info *sbi = F2FS_I_SB(dir); struct inode *inode = dentry->d_inode; struct f2fs_dir_entry *de; struct page *page; int err = -ENOENT; trace_f2fs_unlink_enter(dir, dentry); f2fs_balance_fs(sbi); de = f2fs_find_entry(dir, &dentry->d_name, &page, 0); if (!de) goto fail; f2fs_lock_op(sbi); err = acquire_orphan_inode(sbi); if (err) { f2fs_unlock_op(sbi); f2fs_dentry_kunmap(dir, page); f2fs_put_page(page, 0); goto fail; } f2fs_delete_entry(de, page, dir, inode); f2fs_unlock_op(sbi); /* In order to evict this inode, we set it dirty */ mark_inode_dirty(inode); if (IS_DIRSYNC(dir)) f2fs_sync_fs(sbi->sb, 1); fail: trace_f2fs_unlink_exit(inode, err); return err; } static void *f2fs_follow_link(struct dentry *dentry, struct nameidata *nd) { struct page *page; page = page_follow_link_light(dentry, nd); if (IS_ERR(page)) return page; /* this is broken symlink case */ if (*nd_get_link(nd) == 0) { kunmap(page); page_cache_release(page); return ERR_PTR(-ENOENT); } return page; } static int f2fs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) { struct f2fs_sb_info *sbi = F2FS_I_SB(dir); struct inode *inode; size_t len = strlen(symname); size_t p_len; char *p_str; struct f2fs_str disk_link = FSTR_INIT(NULL, 0); struct f2fs_encrypted_symlink_data *sd = NULL; int err; if (len > dir->i_sb->s_blocksize) return -ENAMETOOLONG; f2fs_balance_fs(sbi); inode = f2fs_new_inode(dir, S_IFLNK | S_IRWXUGO); if (IS_ERR(inode)) return PTR_ERR(inode); if (f2fs_encrypted_inode(inode)) inode->i_op = &f2fs_encrypted_symlink_inode_operations; else inode->i_op = &f2fs_symlink_inode_operations; inode->i_mapping->a_ops = &f2fs_dblock_aops; f2fs_lock_op(sbi); err = f2fs_add_link(dentry, inode); if (err) goto out; f2fs_unlock_op(sbi); alloc_nid_done(sbi, inode->i_ino); if (f2fs_encrypted_inode(dir)) { struct qstr istr = QSTR_INIT(symname, len); err = f2fs_get_encryption_info(inode); if (err) goto err_out; err = f2fs_fname_crypto_alloc_buffer(inode, len, &disk_link); if (err) goto err_out; err = f2fs_fname_usr_to_disk(inode, &istr, &disk_link); if (err < 0) goto err_out; p_len = encrypted_symlink_data_len(disk_link.len) + 1; if (p_len > dir->i_sb->s_blocksize) { err = -ENAMETOOLONG; goto err_out; } sd = kzalloc(p_len, GFP_NOFS); if (!sd) { err = -ENOMEM; goto err_out; } memcpy(sd->encrypted_path, disk_link.name, disk_link.len); sd->len = cpu_to_le16(disk_link.len); p_str = (char *)sd; } else { p_len = len + 1; p_str = (char *)symname; } err = page_symlink(inode, p_str, p_len); err_out: d_instantiate(dentry, inode); unlock_new_inode(inode); /* * Let's flush symlink data in order to avoid broken symlink as much as * possible. Nevertheless, fsyncing is the best way, but there is no * way to get a file descriptor in order to flush that. * * Note that, it needs to do dir->fsync to make this recoverable. * If the symlink path is stored into inline_data, there is no * performance regression. */ if (!err) filemap_write_and_wait_range(inode->i_mapping, 0, p_len - 1); if (IS_DIRSYNC(dir)) f2fs_sync_fs(sbi->sb, 1); kfree(sd); f2fs_fname_crypto_free_buffer(&disk_link); return err; out: handle_failed_inode(inode); return err; } static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { struct f2fs_sb_info *sbi = F2FS_I_SB(dir); struct inode *inode; int err; f2fs_balance_fs(sbi); inode = f2fs_new_inode(dir, S_IFDIR | mode); if (IS_ERR(inode)) return PTR_ERR(inode); inode->i_op = &f2fs_dir_inode_operations; inode->i_fop = &f2fs_dir_operations; inode->i_mapping->a_ops = &f2fs_dblock_aops; mapping_set_gfp_mask(inode->i_mapping, GFP_F2FS_HIGH_ZERO); set_inode_flag(F2FS_I(inode), FI_INC_LINK); f2fs_lock_op(sbi); err = f2fs_add_link(dentry, inode); if (err) goto out_fail; f2fs_unlock_op(sbi); alloc_nid_done(sbi, inode->i_ino); d_instantiate(dentry, inode); unlock_new_inode(inode); if (IS_DIRSYNC(dir)) f2fs_sync_fs(sbi->sb, 1); return 0; out_fail: clear_inode_flag(F2FS_I(inode), FI_INC_LINK); handle_failed_inode(inode); return err; } static int f2fs_rmdir(struct inode *dir, struct dentry *dentry) { struct inode *inode = dentry->d_inode; if (f2fs_empty_dir(inode)) return f2fs_unlink(dir, dentry); return -ENOTEMPTY; } static int f2fs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rdev) { struct f2fs_sb_info *sbi = F2FS_I_SB(dir); struct inode *inode; int err = 0; if (!new_valid_dev(rdev)) return -EINVAL; f2fs_balance_fs(sbi); inode = f2fs_new_inode(dir, mode); if (IS_ERR(inode)) return PTR_ERR(inode); init_special_inode(inode, inode->i_mode, rdev); inode->i_op = &f2fs_special_inode_operations; f2fs_lock_op(sbi); err = f2fs_add_link(dentry, inode); if (err) goto out; f2fs_unlock_op(sbi); alloc_nid_done(sbi, inode->i_ino); d_instantiate(dentry, inode); unlock_new_inode(inode); if (IS_DIRSYNC(dir)) f2fs_sync_fs(sbi->sb, 1); return 0; out: handle_failed_inode(inode); return err; } static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { struct f2fs_sb_info *sbi = F2FS_I_SB(old_dir); struct inode *old_inode = old_dentry->d_inode; struct inode *new_inode = new_dentry->d_inode; struct page *old_dir_page; struct page *old_page, *new_page; struct f2fs_dir_entry *old_dir_entry = NULL; struct f2fs_dir_entry *old_entry; struct f2fs_dir_entry *new_entry; int err = -ENOENT; if ((old_dir != new_dir) && f2fs_encrypted_inode(new_dir) && !f2fs_is_child_context_consistent_with_parent(new_dir, old_inode)) { err = -EPERM; goto out; } f2fs_balance_fs(sbi); old_entry = f2fs_find_entry(old_dir, &old_dentry->d_name, &old_page, 0); if (!old_entry) goto out; if (S_ISDIR(old_inode->i_mode)) { err = -EIO; old_dir_entry = f2fs_parent_dir(old_inode, &old_dir_page); if (!old_dir_entry) goto out_old; } if (new_inode) { err = -ENOTEMPTY; if (old_dir_entry && !f2fs_empty_dir(new_inode)) goto out_dir; err = -ENOENT; new_entry = f2fs_find_entry(new_dir, &new_dentry->d_name, &new_page, 0); if (!new_entry) goto out_dir; f2fs_lock_op(sbi); err = acquire_orphan_inode(sbi); if (err) goto put_out_dir; if (update_dent_inode(old_inode, new_inode, &new_dentry->d_name)) { release_orphan_inode(sbi); goto put_out_dir; } f2fs_set_link(new_dir, new_entry, new_page, old_inode); new_inode->i_ctime = CURRENT_TIME; down_write(&F2FS_I(new_inode)->i_sem); if (old_dir_entry) drop_nlink(new_inode); drop_nlink(new_inode); up_write(&F2FS_I(new_inode)->i_sem); mark_inode_dirty(new_inode); if (!new_inode->i_nlink) add_orphan_inode(sbi, new_inode->i_ino); else release_orphan_inode(sbi); update_inode_page(old_inode); update_inode_page(new_inode); } else { f2fs_lock_op(sbi); err = f2fs_add_link(new_dentry, old_inode); if (err) { f2fs_unlock_op(sbi); goto out_dir; } if (old_dir_entry) { inc_nlink(new_dir); update_inode_page(new_dir); } } down_write(&F2FS_I(old_inode)->i_sem); file_lost_pino(old_inode); if (new_inode && file_enc_name(new_inode)) file_set_enc_name(old_inode); up_write(&F2FS_I(old_inode)->i_sem); old_inode->i_ctime = CURRENT_TIME; mark_inode_dirty(old_inode); f2fs_delete_entry(old_entry, old_page, old_dir, NULL); if (old_dir_entry) { if (old_dir != new_dir) { f2fs_set_link(old_inode, old_dir_entry, old_dir_page, new_dir); update_inode_page(old_inode); } else { f2fs_dentry_kunmap(old_inode, old_dir_page); f2fs_put_page(old_dir_page, 0); } drop_nlink(old_dir); mark_inode_dirty(old_dir); update_inode_page(old_dir); } f2fs_unlock_op(sbi); if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir)) f2fs_sync_fs(sbi->sb, 1); return 0; put_out_dir: f2fs_unlock_op(sbi); f2fs_dentry_kunmap(new_dir, new_page); f2fs_put_page(new_page, 0); out_dir: if (old_dir_entry) { f2fs_dentry_kunmap(old_inode, old_dir_page); f2fs_put_page(old_dir_page, 0); } out_old: f2fs_dentry_kunmap(old_dir, old_page); f2fs_put_page(old_page, 0); out: return err; } #ifdef CONFIG_F2FS_FS_ENCRYPTION static void *f2fs_encrypted_follow_link(struct dentry *dentry, struct nameidata *nd) { struct page *cpage = NULL; char *caddr, *paddr = NULL; struct f2fs_str cstr; struct f2fs_str pstr = FSTR_INIT(NULL, 0); struct inode *inode = dentry->d_inode; struct f2fs_encrypted_symlink_data *sd; loff_t size = min_t(loff_t, i_size_read(inode), PAGE_SIZE - 1); u32 max_size = inode->i_sb->s_blocksize; int res; res = f2fs_get_encryption_info(inode); if (res) return ERR_PTR(res); cpage = read_mapping_page(inode->i_mapping, 0, NULL); if (IS_ERR(cpage)) return cpage; caddr = kmap(cpage); caddr[size] = 0; /* Symlink is encrypted */ sd = (struct f2fs_encrypted_symlink_data *)caddr; cstr.name = sd->encrypted_path; cstr.len = le16_to_cpu(sd->len); /* this is broken symlink case */ if (cstr.name[0] == 0 && cstr.len == 0) { res = -ENOENT; goto errout; } if ((cstr.len + sizeof(struct f2fs_encrypted_symlink_data) - 1) > max_size) { /* Symlink data on the disk is corrupted */ res = -EIO; goto errout; } res = f2fs_fname_crypto_alloc_buffer(inode, cstr.len, &pstr); if (res) goto errout; res = f2fs_fname_disk_to_usr(inode, NULL, &cstr, &pstr); if (res < 0) goto errout; paddr = pstr.name; /* Null-terminate the name */ paddr[res] = '\0'; nd_set_link(nd, paddr); kunmap(cpage); page_cache_release(cpage); return NULL; errout: f2fs_fname_crypto_free_buffer(&pstr); kunmap(cpage); page_cache_release(cpage); return ERR_PTR(res); } void kfree_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie) { char *s = nd_get_link(nd); if (!IS_ERR(s)) kfree(s); } const struct inode_operations f2fs_encrypted_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = f2fs_encrypted_follow_link, .put_link = kfree_put_link, .getattr = f2fs_getattr, .setattr = f2fs_setattr, .setxattr = generic_setxattr, .getxattr = generic_getxattr, .listxattr = f2fs_listxattr, .removexattr = generic_removexattr, }; #endif const struct inode_operations f2fs_dir_inode_operations = { .create = f2fs_create, .lookup = f2fs_lookup, .link = f2fs_link, .unlink = f2fs_unlink, .symlink = f2fs_symlink, .mkdir = f2fs_mkdir, .rmdir = f2fs_rmdir, .mknod = f2fs_mknod, .rename = f2fs_rename, .getattr = f2fs_getattr, .setattr = f2fs_setattr, .get_acl = f2fs_get_acl, #ifdef CONFIG_F2FS_FS_XATTR .setxattr = generic_setxattr, .getxattr = generic_getxattr, .listxattr = f2fs_listxattr, .removexattr = generic_removexattr, #endif }; const struct inode_operations f2fs_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = f2fs_follow_link, .put_link = page_put_link, .getattr = f2fs_getattr, .setattr = f2fs_setattr, #ifdef CONFIG_F2FS_FS_XATTR .setxattr = generic_setxattr, .getxattr = generic_getxattr, .listxattr = f2fs_listxattr, .removexattr = generic_removexattr, #endif }; const struct inode_operations f2fs_special_inode_operations = { .getattr = f2fs_getattr, .setattr = f2fs_setattr, .get_acl = f2fs_get_acl, #ifdef CONFIG_F2FS_FS_XATTR .setxattr = generic_setxattr, .getxattr = generic_getxattr, .listxattr = f2fs_listxattr, .removexattr = generic_removexattr, #endif };
static int reiserfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) { int retval; struct inode *inode; struct reiserfs_transaction_handle th; struct reiserfs_security_handle security; /* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */ int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 2 * (REISERFS_QUOTA_INIT_BLOCKS(dir->i_sb) + REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb)); if (!new_valid_dev(rdev)) return -EINVAL; dquot_initialize(dir); if (!(inode = new_inode(dir->i_sb))) { return -ENOMEM; } new_inode_init(inode, dir, mode); jbegin_count += reiserfs_cache_default_acl(dir); retval = reiserfs_security_init(dir, inode, &dentry->d_name, &security); if (retval < 0) { drop_new_inode(inode); return retval; } jbegin_count += retval; reiserfs_write_lock(dir->i_sb); retval = journal_begin(&th, dir->i_sb, jbegin_count); if (retval) { drop_new_inode(inode); goto out_failed; } retval = reiserfs_new_inode(&th, dir, mode, NULL, 0 /*i_size */ , dentry, inode, &security); if (retval) { goto out_failed; } inode->i_op = &reiserfs_special_inode_operations; init_special_inode(inode, inode->i_mode, rdev); //FIXME: needed for block and char devices only reiserfs_update_sd(&th, inode); reiserfs_update_inode_transaction(inode); reiserfs_update_inode_transaction(dir); retval = reiserfs_add_entry(&th, dir, dentry->d_name.name, dentry->d_name.len, inode, 1 /*visible */ ); if (retval) { int err; inode->i_nlink--; reiserfs_update_sd(&th, inode); err = journal_end(&th, dir->i_sb, jbegin_count); if (err) retval = err; unlock_new_inode(inode); iput(inode); goto out_failed; } d_instantiate(dentry, inode); unlock_new_inode(inode); retval = journal_end(&th, dir->i_sb, jbegin_count); out_failed: reiserfs_write_unlock(dir->i_sb); return retval; }
static noinline int create_subvol(struct btrfs_root *root, struct dentry *dentry, char *name, int namelen) { struct btrfs_trans_handle *trans; struct btrfs_key key; struct btrfs_root_item root_item; struct btrfs_inode_item *inode_item; struct extent_buffer *leaf; struct btrfs_root *new_root; struct inode *dir = dentry->d_parent->d_inode; int ret; int err; u64 objectid; u64 new_dirid = BTRFS_FIRST_FREE_OBJECTID; u64 index = 0; ret = btrfs_find_free_objectid(NULL, root->fs_info->tree_root, 0, &objectid); if (ret) return ret; /* * 1 - inode item * 2 - refs * 1 - root item * 2 - dir items */ trans = btrfs_start_transaction(root, 6); if (IS_ERR(trans)) return PTR_ERR(trans); leaf = btrfs_alloc_free_block(trans, root, root->leafsize, 0, objectid, NULL, 0, 0, 0); if (IS_ERR(leaf)) { ret = PTR_ERR(leaf); goto fail; } memset_extent_buffer(leaf, 0, 0, sizeof(struct btrfs_header)); btrfs_set_header_bytenr(leaf, leaf->start); btrfs_set_header_generation(leaf, trans->transid); btrfs_set_header_backref_rev(leaf, BTRFS_MIXED_BACKREF_REV); btrfs_set_header_owner(leaf, objectid); write_extent_buffer(leaf, root->fs_info->fsid, (unsigned long)btrfs_header_fsid(leaf), BTRFS_FSID_SIZE); write_extent_buffer(leaf, root->fs_info->chunk_tree_uuid, (unsigned long)btrfs_header_chunk_tree_uuid(leaf), BTRFS_UUID_SIZE); btrfs_mark_buffer_dirty(leaf); inode_item = &root_item.inode; memset(inode_item, 0, sizeof(*inode_item)); inode_item->generation = cpu_to_le64(1); inode_item->size = cpu_to_le64(3); inode_item->nlink = cpu_to_le32(1); inode_item->nbytes = cpu_to_le64(root->leafsize); inode_item->mode = cpu_to_le32(S_IFDIR | 0755); btrfs_set_root_bytenr(&root_item, leaf->start); btrfs_set_root_generation(&root_item, trans->transid); btrfs_set_root_level(&root_item, 0); btrfs_set_root_refs(&root_item, 1); btrfs_set_root_used(&root_item, leaf->len); btrfs_set_root_last_snapshot(&root_item, 0); memset(&root_item.drop_progress, 0, sizeof(root_item.drop_progress)); root_item.drop_level = 0; btrfs_tree_unlock(leaf); free_extent_buffer(leaf); leaf = NULL; btrfs_set_root_dirid(&root_item, new_dirid); key.objectid = objectid; key.offset = 0; btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY); ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key, &root_item); if (ret) goto fail; key.offset = (u64)-1; new_root = btrfs_read_fs_root_no_name(root->fs_info, &key); BUG_ON(IS_ERR(new_root)); btrfs_record_root_in_trans(trans, new_root); ret = btrfs_create_subvol_root(trans, new_root, new_dirid, BTRFS_I(dir)->block_group); /* * insert the directory item */ ret = btrfs_set_inode_index(dir, &index); BUG_ON(ret); ret = btrfs_insert_dir_item(trans, root, name, namelen, dir->i_ino, &key, BTRFS_FT_DIR, index); if (ret) goto fail; btrfs_i_size_write(dir, dir->i_size + namelen * 2); ret = btrfs_update_inode(trans, root, dir); BUG_ON(ret); ret = btrfs_add_root_ref(trans, root->fs_info->tree_root, objectid, root->root_key.objectid, dir->i_ino, index, name, namelen); BUG_ON(ret); d_instantiate(dentry, btrfs_lookup_dentry(dir, dentry)); fail: err = btrfs_commit_transaction(trans, root); if (err && !ret) ret = err; return ret; }
static int reiserfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) { int retval; struct inode *inode; struct reiserfs_transaction_handle th; struct reiserfs_security_handle security; int lock_depth; /* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */ int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 2 * (REISERFS_QUOTA_INIT_BLOCKS(dir->i_sb) + REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb)); dquot_initialize(dir); #ifdef DISPLACE_NEW_PACKING_LOCALITIES /* set flag that new packing locality created and new blocks for the content * of that directory are not displaced yet */ REISERFS_I(dir)->new_packing_locality = 1; #endif mode = S_IFDIR | mode; if (!(inode = new_inode(dir->i_sb))) { return -ENOMEM; } new_inode_init(inode, dir, mode); jbegin_count += reiserfs_cache_default_acl(dir); retval = reiserfs_security_init(dir, inode, &dentry->d_name, &security); if (retval < 0) { drop_new_inode(inode); return retval; } jbegin_count += retval; lock_depth = reiserfs_write_lock_once(dir->i_sb); retval = journal_begin(&th, dir->i_sb, jbegin_count); if (retval) { drop_new_inode(inode); goto out_failed; } /* inc the link count now, so another writer doesn't overflow it while ** we sleep later on. */ INC_DIR_INODE_NLINK(dir) retval = reiserfs_new_inode(&th, dir, mode, NULL /*symlink */ , old_format_only(dir->i_sb) ? EMPTY_DIR_SIZE_V1 : EMPTY_DIR_SIZE, dentry, inode, &security); if (retval) { DEC_DIR_INODE_NLINK(dir) goto out_failed; } reiserfs_update_inode_transaction(inode); reiserfs_update_inode_transaction(dir); inode->i_op = &reiserfs_dir_inode_operations; inode->i_fop = &reiserfs_dir_operations; // note, _this_ add_entry will not update dir's stat data retval = reiserfs_add_entry(&th, dir, dentry->d_name.name, dentry->d_name.len, inode, 1 /*visible */ ); if (retval) { int err; inode->i_nlink = 0; DEC_DIR_INODE_NLINK(dir); reiserfs_update_sd(&th, inode); err = journal_end(&th, dir->i_sb, jbegin_count); if (err) retval = err; unlock_new_inode(inode); iput(inode); goto out_failed; } // the above add_entry did not update dir's stat data reiserfs_update_sd(&th, dir); d_instantiate(dentry, inode); unlock_new_inode(inode); retval = journal_end(&th, dir->i_sb, jbegin_count); out_failed: reiserfs_write_unlock_once(dir->i_sb, lock_depth); return retval; }
int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode, dev_t device_number) { int rc = -EPERM; unsigned int xid; int create_options = CREATE_NOT_DIR | CREATE_OPTION_SPECIAL; struct cifs_sb_info *cifs_sb; struct tcon_link *tlink; struct cifs_tcon *tcon; struct cifs_io_parms io_parms; char *full_path = NULL; struct inode *newinode = NULL; __u32 oplock = 0; struct cifs_fid fid; struct cifs_open_parms oparms; FILE_ALL_INFO *buf = NULL; unsigned int bytes_written; struct win_dev *pdev; struct kvec iov[2]; if (!old_valid_dev(device_number)) return -EINVAL; cifs_sb = CIFS_SB(inode->i_sb); tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) return PTR_ERR(tlink); tcon = tlink_tcon(tlink); xid = get_xid(); full_path = build_path_from_dentry(direntry); if (full_path == NULL) { rc = -ENOMEM; goto mknod_out; } if (tcon->unix_ext) { struct cifs_unix_set_info_args args = { .mode = mode & ~current_umask(), .ctime = NO_CHANGE_64, .atime = NO_CHANGE_64, .mtime = NO_CHANGE_64, .device = device_number, }; if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { args.uid = current_fsuid(); args.gid = current_fsgid(); } else { args.uid = INVALID_UID; /* no change */ args.gid = INVALID_GID; /* no change */ } rc = CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args, cifs_sb->local_nls, cifs_remap(cifs_sb)); if (rc) goto mknod_out; rc = cifs_get_inode_info_unix(&newinode, full_path, inode->i_sb, xid); if (rc == 0) d_instantiate(direntry, newinode); goto mknod_out; } if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) goto mknod_out; cifs_dbg(FYI, "sfu compat create special file\n"); buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); if (buf == NULL) { kfree(full_path); rc = -ENOMEM; free_xid(xid); return rc; } if (backup_cred(cifs_sb)) create_options |= CREATE_OPEN_BACKUP_INTENT; oparms.tcon = tcon; oparms.cifs_sb = cifs_sb; oparms.desired_access = GENERIC_WRITE; oparms.create_options = create_options; oparms.disposition = FILE_CREATE; oparms.path = full_path; oparms.fid = &fid; oparms.reconnect = false; if (tcon->ses->server->oplocks) oplock = REQ_OPLOCK; else oplock = 0; rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, buf); if (rc) goto mknod_out; /* * BB Do not bother to decode buf since no local inode yet to put * timestamps in, but we can reuse it safely. */ pdev = (struct win_dev *)buf; io_parms.pid = current->tgid; io_parms.tcon = tcon; io_parms.offset = 0; io_parms.length = sizeof(struct win_dev); iov[1].iov_base = buf; iov[1].iov_len = sizeof(struct win_dev); if (S_ISCHR(mode)) { memcpy(pdev->type, "IntxCHR", 8); pdev->major = cpu_to_le64(MAJOR(device_number)); pdev->minor = cpu_to_le64(MINOR(device_number)); rc = tcon->ses->server->ops->sync_write(xid, &fid, &io_parms, &bytes_written, iov, 1); } else if (S_ISBLK(mode)) { memcpy(pdev->type, "IntxBLK", 8); pdev->major = cpu_to_le64(MAJOR(device_number)); pdev->minor = cpu_to_le64(MINOR(device_number)); rc = tcon->ses->server->ops->sync_write(xid, &fid, &io_parms, &bytes_written, iov, 1); } /* else if (S_ISFIFO) */ tcon->ses->server->ops->close(xid, tcon, &fid); d_drop(direntry); /* FIXME: add code here to set EAs */ mknod_out: kfree(full_path); kfree(buf); free_xid(xid); cifs_put_tlink(tlink); return rc; }
static int ubifs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd) { struct inode *inode; struct ubifs_info *c = dir->i_sb->s_fs_info; int err, sz_change = CALC_DENT_SIZE(dentry->d_name.len); struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1, .dirtied_ino = 1 }; struct ubifs_inode *dir_ui = ubifs_inode(dir); /* * Budget request settings: new inode, new direntry, changing the * parent directory inode. */ dbg_gen("dent '%.*s', mode %#x in dir ino %lu", dentry->d_name.len, dentry->d_name.name, mode, dir->i_ino); err = ubifs_budget_space(c, &req); if (err) return err; inode = ubifs_new_inode(c, dir, mode); if (IS_ERR(inode)) { err = PTR_ERR(inode); goto out_budg; } mutex_lock(&dir_ui->ui_mutex); dir->i_size += sz_change; dir_ui->ui_size = dir->i_size; dir->i_mtime = dir->i_ctime = inode->i_ctime; err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 0, 0); if (err) goto out_cancel; mutex_unlock(&dir_ui->ui_mutex); ubifs_release_budget(c, &req); insert_inode_hash(inode); d_instantiate(dentry, inode); return 0; out_cancel: dir->i_size -= sz_change; dir_ui->ui_size = dir->i_size; mutex_unlock(&dir_ui->ui_mutex); make_bad_inode(inode); iput(inode); out_budg: ubifs_release_budget(c, &req); ubifs_err("cannot create regular file, error %d", err); return err; } /** * vfs_dent_type - get VFS directory entry type. * @type: UBIFS directory entry type * * This function converts UBIFS directory entry type into VFS directory entry * type. */ static unsigned int vfs_dent_type(uint8_t type) { switch (type) { case UBIFS_ITYPE_REG: return DT_REG; case UBIFS_ITYPE_DIR: return DT_DIR; case UBIFS_ITYPE_LNK: return DT_LNK; case UBIFS_ITYPE_BLK: return DT_BLK; case UBIFS_ITYPE_CHR: return DT_CHR; case UBIFS_ITYPE_FIFO: return DT_FIFO; case UBIFS_ITYPE_SOCK: return DT_SOCK; default: BUG(); } return 0; } /* * The classical Unix view for directory is that it is a linear array of * (name, inode number) entries. Linux/VFS assumes this model as well. * Particularly, 'readdir()' call wants us to return a directory entry offset * which later may be used to continue 'readdir()'ing the directory or to * 'seek()' to that specific direntry. Obviously UBIFS does not really fit this * model because directory entries are identified by keys, which may collide. * * UBIFS uses directory entry hash value for directory offsets, so * 'seekdir()'/'telldir()' may not always work because of possible key * collisions. But UBIFS guarantees that consecutive 'readdir()' calls work * properly by means of saving full directory entry name in the private field * of the file description object. * * This means that UBIFS cannot support NFS which requires full * 'seekdir()'/'telldir()' support. */ static int ubifs_readdir(struct file *file, void *dirent, filldir_t filldir) { int err, over = 0; struct qstr nm; union ubifs_key key; struct ubifs_dent_node *dent; struct inode *dir = file->f_path.dentry->d_inode; struct ubifs_info *c = dir->i_sb->s_fs_info; dbg_gen("dir ino %lu, f_pos %#llx", dir->i_ino, file->f_pos); if (file->f_pos > UBIFS_S_KEY_HASH_MASK || file->f_pos == 2) /* * The directory was seek'ed to a senseless position or there * are no more entries. */ return 0; /* File positions 0 and 1 correspond to "." and ".." */ if (file->f_pos == 0) { ubifs_assert(!file->private_data); over = filldir(dirent, ".", 1, 0, dir->i_ino, DT_DIR); if (over) return 0; file->f_pos = 1; } if (file->f_pos == 1) { ubifs_assert(!file->private_data); over = filldir(dirent, "..", 2, 1, parent_ino(file->f_path.dentry), DT_DIR); if (over) return 0; /* Find the first entry in TNC and save it */ lowest_dent_key(c, &key, dir->i_ino); nm.name = NULL; dent = ubifs_tnc_next_ent(c, &key, &nm); if (IS_ERR(dent)) { err = PTR_ERR(dent); goto out; } file->f_pos = key_hash_flash(c, &dent->key); file->private_data = dent; } dent = file->private_data; if (!dent) { /* * The directory was seek'ed to and is now readdir'ed. * Find the entry corresponding to @file->f_pos or the * closest one. */ dent_key_init_hash(c, &key, dir->i_ino, file->f_pos); nm.name = NULL; dent = ubifs_tnc_next_ent(c, &key, &nm); if (IS_ERR(dent)) { err = PTR_ERR(dent); goto out; } file->f_pos = key_hash_flash(c, &dent->key); file->private_data = dent; } while (1) { dbg_gen("feed '%s', ino %llu, new f_pos %#x", dent->name, (unsigned long long)le64_to_cpu(dent->inum), key_hash_flash(c, &dent->key)); ubifs_assert(le64_to_cpu(dent->ch.sqnum) > ubifs_inode(dir)->creat_sqnum); nm.len = le16_to_cpu(dent->nlen); over = filldir(dirent, dent->name, nm.len, file->f_pos, le64_to_cpu(dent->inum), vfs_dent_type(dent->type)); if (over) return 0; /* Switch to the next entry */ key_read(c, &dent->key, &key); nm.name = dent->name; dent = ubifs_tnc_next_ent(c, &key, &nm); if (IS_ERR(dent)) { err = PTR_ERR(dent); goto out; } kfree(file->private_data); file->f_pos = key_hash_flash(c, &dent->key); file->private_data = dent; cond_resched(); } out: if (err != -ENOENT) { ubifs_err("cannot find next direntry, error %d", err); return err; } kfree(file->private_data); file->private_data = NULL; file->f_pos = 2; return 0; }
/** * securityfs_create_file - create a file in the securityfs filesystem * * @name: a pointer to a string containing the name of the file to create. * @mode: the permission that the file should have * @parent: a pointer to the parent dentry for this file. This should be a * directory dentry if set. If this parameter is %NULL, then the * file will be created in the root of the securityfs filesystem. * @data: a pointer to something that the caller will want to get to later * on. The inode.i_private pointer will point to this value on * the open() call. * @fops: a pointer to a struct file_operations that should be used for * this file. * * This is the basic "create a file" function for securityfs. It allows for a * wide range of flexibility in creating a file, or a directory (if you * want to create a directory, the securityfs_create_dir() function is * recommended to be used instead). * * This function returns a pointer to a dentry if it succeeds. This * pointer must be passed to the securityfs_remove() function when the file is * to be removed (no automatic cleanup happens if your module is unloaded, * you are responsible here). If an error occurs, the function will return * the error value (via ERR_PTR). * * If securityfs is not enabled in the kernel, the value %-ENODEV is * returned. */ struct dentry *securityfs_create_file(const char *name, umode_t mode, struct dentry *parent, void *data, const struct file_operations *fops) { struct dentry *dentry; int is_dir = S_ISDIR(mode); struct inode *dir, *inode; int error; if (!is_dir) { BUG_ON(!fops); mode = (mode & S_IALLUGO) | S_IFREG; } pr_debug("securityfs: creating file '%s'\n",name); error = simple_pin_fs(&fs_type, &mount, &mount_count); if (error) return ERR_PTR(error); if (!parent) parent = mount->mnt_root; dir = d_inode(parent); inode_lock(dir); dentry = lookup_one_len(name, parent, strlen(name)); if (IS_ERR(dentry)) goto out; if (d_really_is_positive(dentry)) { error = -EEXIST; goto out1; } inode = new_inode(dir->i_sb); if (!inode) { error = -ENOMEM; goto out1; } inode->i_ino = get_next_ino(); inode->i_mode = mode; inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode); inode->i_private = data; if (is_dir) { inode->i_op = &simple_dir_inode_operations; inode->i_fop = &simple_dir_operations; inc_nlink(inode); inc_nlink(dir); } else { inode->i_fop = fops; } d_instantiate(dentry, inode); dget(dentry); inode_unlock(dir); return dentry; out1: dput(dentry); dentry = ERR_PTR(error); out: inode_unlock(dir); simple_release_fs(&mount, &mount_count); return dentry; }
static int ubifs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) { struct ubifs_info *c = dir->i_sb->s_fs_info; struct inode *inode = old_dentry->d_inode; struct ubifs_inode *ui = ubifs_inode(inode); struct ubifs_inode *dir_ui = ubifs_inode(dir); int err, sz_change = CALC_DENT_SIZE(dentry->d_name.len); struct ubifs_budget_req req = { .new_dent = 1, .dirtied_ino = 2, .dirtied_ino_d = ALIGN(ui->data_len, 8) }; /* * Budget request settings: new direntry, changing the target inode, * changing the parent inode. */ dbg_gen("dent '%.*s' to ino %lu (nlink %d) in dir ino %lu", dentry->d_name.len, dentry->d_name.name, inode->i_ino, inode->i_nlink, dir->i_ino); err = dbg_check_synced_i_size(inode); if (err) return err; err = ubifs_budget_space(c, &req); if (err) return err; lock_2_inodes(dir, inode); inc_nlink(inode); atomic_inc(&inode->i_count); inode->i_ctime = ubifs_current_time(inode); dir->i_size += sz_change; dir_ui->ui_size = dir->i_size; dir->i_mtime = dir->i_ctime = inode->i_ctime; err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 0, 0); if (err) goto out_cancel; unlock_2_inodes(dir, inode); ubifs_release_budget(c, &req); d_instantiate(dentry, inode); return 0; out_cancel: dir->i_size -= sz_change; dir_ui->ui_size = dir->i_size; drop_nlink(inode); unlock_2_inodes(dir, inode); ubifs_release_budget(c, &req); iput(inode); return err; } static int ubifs_unlink(struct inode *dir, struct dentry *dentry) { struct ubifs_info *c = dir->i_sb->s_fs_info; struct inode *inode = dentry->d_inode; struct ubifs_inode *dir_ui = ubifs_inode(dir); int sz_change = CALC_DENT_SIZE(dentry->d_name.len); int err, budgeted = 1; struct ubifs_budget_req req = { .mod_dent = 1, .dirtied_ino = 2 }; /* * Budget request settings: deletion direntry, deletion inode (+1 for * @dirtied_ino), changing the parent directory inode. If budgeting * fails, go ahead anyway because we have extra space reserved for * deletions. */ dbg_gen("dent '%.*s' from ino %lu (nlink %d) in dir ino %lu", dentry->d_name.len, dentry->d_name.name, inode->i_ino, inode->i_nlink, dir->i_ino); err = dbg_check_synced_i_size(inode); if (err) return err; err = ubifs_budget_space(c, &req); if (err) { if (err != -ENOSPC) return err; budgeted = 0; } lock_2_inodes(dir, inode); inode->i_ctime = ubifs_current_time(dir); drop_nlink(inode); dir->i_size -= sz_change; dir_ui->ui_size = dir->i_size; dir->i_mtime = dir->i_ctime = inode->i_ctime; err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 1, 0); if (err) goto out_cancel; unlock_2_inodes(dir, inode); if (budgeted) ubifs_release_budget(c, &req); else { /* We've deleted something - clean the "no space" flags */ c->nospace = c->nospace_rp = 0; smp_wmb(); } return 0; out_cancel: dir->i_size += sz_change; dir_ui->ui_size = dir->i_size; inc_nlink(inode); unlock_2_inodes(dir, inode); if (budgeted) ubifs_release_budget(c, &req); return err; } /** * check_dir_empty - check if a directory is empty or not. * @c: UBIFS file-system description object * @dir: VFS inode object of the directory to check * * This function checks if directory @dir is empty. Returns zero if the * directory is empty, %-ENOTEMPTY if it is not, and other negative error codes * in case of of errors. */ static int check_dir_empty(struct ubifs_info *c, struct inode *dir) { struct qstr nm = { .name = NULL }; struct ubifs_dent_node *dent; union ubifs_key key; int err; lowest_dent_key(c, &key, dir->i_ino); dent = ubifs_tnc_next_ent(c, &key, &nm); if (IS_ERR(dent)) { err = PTR_ERR(dent); if (err == -ENOENT) err = 0; } else { kfree(dent); err = -ENOTEMPTY; } return err; } static int ubifs_rmdir(struct inode *dir, struct dentry *dentry) { struct ubifs_info *c = dir->i_sb->s_fs_info; struct inode *inode = dentry->d_inode; int sz_change = CALC_DENT_SIZE(dentry->d_name.len); int err, budgeted = 1; struct ubifs_inode *dir_ui = ubifs_inode(dir); struct ubifs_budget_req req = { .mod_dent = 1, .dirtied_ino = 2 }; /* * Budget request settings: deletion direntry, deletion inode and * changing the parent inode. If budgeting fails, go ahead anyway * because we have extra space reserved for deletions. */ dbg_gen("directory '%.*s', ino %lu in dir ino %lu", dentry->d_name.len, dentry->d_name.name, inode->i_ino, dir->i_ino); err = check_dir_empty(c, dentry->d_inode); if (err) return err; err = ubifs_budget_space(c, &req); if (err) { if (err != -ENOSPC) return err; budgeted = 0; } lock_2_inodes(dir, inode); inode->i_ctime = ubifs_current_time(dir); clear_nlink(inode); drop_nlink(dir); dir->i_size -= sz_change; dir_ui->ui_size = dir->i_size; dir->i_mtime = dir->i_ctime = inode->i_ctime; err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 1, 0); if (err) goto out_cancel; unlock_2_inodes(dir, inode); if (budgeted) ubifs_release_budget(c, &req); else { /* We've deleted something - clean the "no space" flags */ c->nospace = c->nospace_rp = 0; smp_wmb(); } return 0; out_cancel: dir->i_size += sz_change; dir_ui->ui_size = dir->i_size; inc_nlink(dir); inc_nlink(inode); inc_nlink(inode); unlock_2_inodes(dir, inode); if (budgeted) ubifs_release_budget(c, &req); return err; } static int ubifs_mkdir(struct inode *dir, struct dentry *dentry, int mode) { struct inode *inode; struct ubifs_inode *dir_ui = ubifs_inode(dir); struct ubifs_info *c = dir->i_sb->s_fs_info; int err, sz_change = CALC_DENT_SIZE(dentry->d_name.len); struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1 }; /* * Budget request settings: new inode, new direntry and changing parent * directory inode. */ dbg_gen("dent '%.*s', mode %#x in dir ino %lu", dentry->d_name.len, dentry->d_name.name, mode, dir->i_ino); err = ubifs_budget_space(c, &req); if (err) return err; inode = ubifs_new_inode(c, dir, S_IFDIR | mode); if (IS_ERR(inode)) { err = PTR_ERR(inode); goto out_budg; } mutex_lock(&dir_ui->ui_mutex); insert_inode_hash(inode); inc_nlink(inode); inc_nlink(dir); dir->i_size += sz_change; dir_ui->ui_size = dir->i_size; dir->i_mtime = dir->i_ctime = inode->i_ctime; err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 0, 0); if (err) { ubifs_err("cannot create directory, error %d", err); goto out_cancel; } mutex_unlock(&dir_ui->ui_mutex); ubifs_release_budget(c, &req); d_instantiate(dentry, inode); return 0; out_cancel: dir->i_size -= sz_change; dir_ui->ui_size = dir->i_size; drop_nlink(dir); mutex_unlock(&dir_ui->ui_mutex); make_bad_inode(inode); iput(inode); out_budg: ubifs_release_budget(c, &req); return err; } static int ubifs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) { struct inode *inode; struct ubifs_inode *ui; struct ubifs_inode *dir_ui = ubifs_inode(dir); struct ubifs_info *c = dir->i_sb->s_fs_info; union ubifs_dev_desc *dev = NULL; int sz_change = CALC_DENT_SIZE(dentry->d_name.len); int err, devlen = 0; struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1, .new_ino_d = ALIGN(devlen, 8), .dirtied_ino = 1 }; /* * Budget request settings: new inode, new direntry and changing parent * directory inode. */ dbg_gen("dent '%.*s' in dir ino %lu", dentry->d_name.len, dentry->d_name.name, dir->i_ino); if (!new_valid_dev(rdev)) return -EINVAL; if (S_ISBLK(mode) || S_ISCHR(mode)) { dev = kmalloc(sizeof(union ubifs_dev_desc), GFP_NOFS); if (!dev) return -ENOMEM; devlen = ubifs_encode_dev(dev, rdev); } err = ubifs_budget_space(c, &req); if (err) { kfree(dev); return err; } inode = ubifs_new_inode(c, dir, mode); if (IS_ERR(inode)) { kfree(dev); err = PTR_ERR(inode); goto out_budg; } init_special_inode(inode, inode->i_mode, rdev); inode->i_size = ubifs_inode(inode)->ui_size = devlen; ui = ubifs_inode(inode); ui->data = dev; ui->data_len = devlen; mutex_lock(&dir_ui->ui_mutex); dir->i_size += sz_change; dir_ui->ui_size = dir->i_size; dir->i_mtime = dir->i_ctime = inode->i_ctime; err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 0, 0); if (err) goto out_cancel; mutex_unlock(&dir_ui->ui_mutex); ubifs_release_budget(c, &req); insert_inode_hash(inode); d_instantiate(dentry, inode); return 0; out_cancel: dir->i_size -= sz_change; dir_ui->ui_size = dir->i_size; mutex_unlock(&dir_ui->ui_mutex); make_bad_inode(inode); iput(inode); out_budg: ubifs_release_budget(c, &req); return err; } static int ubifs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) { struct inode *inode; struct ubifs_inode *ui; struct ubifs_inode *dir_ui = ubifs_inode(dir); struct ubifs_info *c = dir->i_sb->s_fs_info; int err, len = strlen(symname); int sz_change = CALC_DENT_SIZE(dentry->d_name.len); struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1, .new_ino_d = ALIGN(len, 8), .dirtied_ino = 1 }; /* * Budget request settings: new inode, new direntry and changing parent * directory inode. */ dbg_gen("dent '%.*s', target '%s' in dir ino %lu", dentry->d_name.len, dentry->d_name.name, symname, dir->i_ino); if (len > UBIFS_MAX_INO_DATA) return -ENAMETOOLONG; err = ubifs_budget_space(c, &req); if (err) return err; inode = ubifs_new_inode(c, dir, S_IFLNK | S_IRWXUGO); if (IS_ERR(inode)) { err = PTR_ERR(inode); goto out_budg; } ui = ubifs_inode(inode); ui->data = kmalloc(len + 1, GFP_NOFS); if (!ui->data) { err = -ENOMEM; goto out_inode; } memcpy(ui->data, symname, len); ((char *)ui->data)[len] = '\0'; /* * The terminating zero byte is not written to the flash media and it * is put just to make later in-memory string processing simpler. Thus, * data length is @len, not @len + %1. */ ui->data_len = len; inode->i_size = ubifs_inode(inode)->ui_size = len; mutex_lock(&dir_ui->ui_mutex); dir->i_size += sz_change; dir_ui->ui_size = dir->i_size; dir->i_mtime = dir->i_ctime = inode->i_ctime; err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 0, 0); if (err) goto out_cancel; mutex_unlock(&dir_ui->ui_mutex); ubifs_release_budget(c, &req); insert_inode_hash(inode); d_instantiate(dentry, inode); return 0; out_cancel: dir->i_size -= sz_change; dir_ui->ui_size = dir->i_size; mutex_unlock(&dir_ui->ui_mutex); out_inode: make_bad_inode(inode); iput(inode); out_budg: ubifs_release_budget(c, &req); return err; } /** * lock_3_inodes - lock three UBIFS inodes for rename. * @inode1: first inode * @inode2: second inode * @inode3: third inode * * For 'ubifs_rename()', @inode1 may be the same as @inode2 whereas @inode3 may * be null. */ static void lock_3_inodes(struct inode *inode1, struct inode *inode2, struct inode *inode3) { struct inode *i1, *i2, *i3; if (!inode3) { if (inode1 != inode2) { lock_2_inodes(inode1, inode2); return; } mutex_lock_nested(&ubifs_inode(inode1)->ui_mutex, WB_MUTEX_1); return; } if (inode1 == inode2) { lock_2_inodes(inode1, inode3); return; } /* 3 different inodes */ if (inode1 < inode2) { i3 = inode2; if (inode1 < inode3) { i1 = inode1; i2 = inode3; } else { i1 = inode3; i2 = inode1; } } else { i3 = inode1; if (inode2 < inode3) { i1 = inode2; i2 = inode3; } else { i1 = inode3; i2 = inode2; } } mutex_lock_nested(&ubifs_inode(i1)->ui_mutex, WB_MUTEX_1); lock_2_inodes(i2, i3); } /** * unlock_3_inodes - unlock three UBIFS inodes for rename. * @inode1: first inode * @inode2: second inode * @inode3: third inode */ static void unlock_3_inodes(struct inode *inode1, struct inode *inode2, struct inode *inode3) { mutex_unlock(&ubifs_inode(inode1)->ui_mutex); if (inode1 != inode2) mutex_unlock(&ubifs_inode(inode2)->ui_mutex); if (inode3) mutex_unlock(&ubifs_inode(inode3)->ui_mutex); } static int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { struct ubifs_info *c = old_dir->i_sb->s_fs_info; struct inode *old_inode = old_dentry->d_inode; struct inode *new_inode = new_dentry->d_inode; struct ubifs_inode *old_inode_ui = ubifs_inode(old_inode); int err, release, sync = 0, move = (new_dir != old_dir); int is_dir = S_ISDIR(old_inode->i_mode); int unlink = !!new_inode; int new_sz = CALC_DENT_SIZE(new_dentry->d_name.len); int old_sz = CALC_DENT_SIZE(old_dentry->d_name.len); struct ubifs_budget_req req = { .new_dent = 1, .mod_dent = 1, .dirtied_ino = 3 }; struct ubifs_budget_req ino_req = { .dirtied_ino = 1, .dirtied_ino_d = ALIGN(old_inode_ui->data_len, 8) }; struct timespec time; /* * Budget request settings: deletion direntry, new direntry, removing * the old inode, and changing old and new parent directory inodes. * * However, this operation also marks the target inode as dirty and * does not write it, so we allocate budget for the target inode * separately. */ dbg_gen("dent '%.*s' ino %lu in dir ino %lu to dent '%.*s' in " "dir ino %lu", old_dentry->d_name.len, old_dentry->d_name.name, old_inode->i_ino, old_dir->i_ino, new_dentry->d_name.len, new_dentry->d_name.name, new_dir->i_ino); if (unlink && is_dir) { err = check_dir_empty(c, new_inode); if (err) return err; } err = ubifs_budget_space(c, &req); if (err) return err; err = ubifs_budget_space(c, &ino_req); if (err) { ubifs_release_budget(c, &req); return err; } lock_3_inodes(old_dir, new_dir, new_inode); /* * Like most other Unix systems, set the @i_ctime for inodes on a * rename. */ time = ubifs_current_time(old_dir); old_inode->i_ctime = time; /* We must adjust parent link count when renaming directories */ if (is_dir) { if (move) { /* * @old_dir loses a link because we are moving * @old_inode to a different directory. */ drop_nlink(old_dir); /* * @new_dir only gains a link if we are not also * overwriting an existing directory. */ if (!unlink) inc_nlink(new_dir); } else { /* * @old_inode is not moving to a different directory, * but @old_dir still loses a link if we are * overwriting an existing directory. */ if (unlink) drop_nlink(old_dir); } } old_dir->i_size -= old_sz; ubifs_inode(old_dir)->ui_size = old_dir->i_size; old_dir->i_mtime = old_dir->i_ctime = time; new_dir->i_mtime = new_dir->i_ctime = time; /* * And finally, if we unlinked a direntry which happened to have the * same name as the moved direntry, we have to decrement @i_nlink of * the unlinked inode and change its ctime. */ if (unlink) { /* * Directories cannot have hard-links, so if this is a * directory, decrement its @i_nlink twice because an empty * directory has @i_nlink 2. */ if (is_dir) drop_nlink(new_inode); new_inode->i_ctime = time; drop_nlink(new_inode); } else { new_dir->i_size += new_sz; ubifs_inode(new_dir)->ui_size = new_dir->i_size; } /* * Do not ask 'ubifs_jnl_rename()' to flush write-buffer if @old_inode * is dirty, because this will be done later on at the end of * 'ubifs_rename()'. */ if (IS_SYNC(old_inode)) { sync = IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir); if (unlink && IS_SYNC(new_inode)) sync = 1; } err = ubifs_jnl_rename(c, old_dir, old_dentry, new_dir, new_dentry, sync); if (err) goto out_cancel; unlock_3_inodes(old_dir, new_dir, new_inode); ubifs_release_budget(c, &req); mutex_lock(&old_inode_ui->ui_mutex); release = old_inode_ui->dirty; mark_inode_dirty_sync(old_inode); mutex_unlock(&old_inode_ui->ui_mutex); if (release) ubifs_release_budget(c, &ino_req); if (IS_SYNC(old_inode)) err = old_inode->i_sb->s_op->write_inode(old_inode, 1); return err; out_cancel: if (unlink) { if (is_dir) inc_nlink(new_inode); inc_nlink(new_inode); } else { new_dir->i_size -= new_sz; ubifs_inode(new_dir)->ui_size = new_dir->i_size; } old_dir->i_size += old_sz; ubifs_inode(old_dir)->ui_size = old_dir->i_size; if (is_dir) { if (move) { inc_nlink(old_dir); if (!unlink) drop_nlink(new_dir); } else { if (unlink) inc_nlink(old_dir); } } unlock_3_inodes(old_dir, new_dir, new_inode); ubifs_release_budget(c, &ino_req); ubifs_release_budget(c, &req); return err; } int ubifs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { loff_t size; struct inode *inode = dentry->d_inode; struct ubifs_inode *ui = ubifs_inode(inode); mutex_lock(&ui->ui_mutex); stat->dev = inode->i_sb->s_dev; stat->ino = inode->i_ino; stat->mode = inode->i_mode; stat->nlink = inode->i_nlink; stat->uid = inode->i_uid; stat->gid = inode->i_gid; stat->rdev = inode->i_rdev; stat->atime = inode->i_atime; stat->mtime = inode->i_mtime; stat->ctime = inode->i_ctime; stat->blksize = UBIFS_BLOCK_SIZE; stat->size = ui->ui_size; /* * Unfortunately, the 'stat()' system call was designed for block * device based file systems, and it is not appropriate for UBIFS, * because UBIFS does not have notion of "block". For example, it is * difficult to tell how many block a directory takes - it actually * takes less than 300 bytes, but we have to round it to block size, * which introduces large mistake. This makes utilities like 'du' to * report completely senseless numbers. This is the reason why UBIFS * goes the same way as JFFS2 - it reports zero blocks for everything * but regular files, which makes more sense than reporting completely * wrong sizes. */ if (S_ISREG(inode->i_mode)) { size = ui->xattr_size; size += stat->size; size = ALIGN(size, UBIFS_BLOCK_SIZE); /* * Note, user-space expects 512-byte blocks count irrespectively * of what was reported in @stat->size. */ stat->blocks = size >> 9; } else stat->blocks = 0; mutex_unlock(&ui->ui_mutex); return 0; } struct inode_operations ubifs_dir_inode_operations = { .lookup = ubifs_lookup, .create = ubifs_create, .link = ubifs_link, .symlink = ubifs_symlink, .unlink = ubifs_unlink, .mkdir = ubifs_mkdir, .rmdir = ubifs_rmdir, .mknod = ubifs_mknod, .rename = ubifs_rename, .setattr = ubifs_setattr, .getattr = ubifs_getattr, #ifdef CONFIG_UBIFS_FS_XATTR .setxattr = ubifs_setxattr, .getxattr = ubifs_getxattr, .listxattr = ubifs_listxattr, .removexattr = ubifs_removexattr, #endif }; struct file_operations ubifs_dir_operations = { .llseek = ubifs_dir_llseek, .release = ubifs_dir_release, .read = generic_read_dir, .readdir = ubifs_readdir, .fsync = ubifs_fsync, .unlocked_ioctl = ubifs_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = ubifs_compat_ioctl, #endif };
int cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) { int rc = -EOPNOTSUPP; unsigned int xid; struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct tcon_link *tlink; struct cifs_tcon *pTcon; char *full_path = NULL; struct inode *newinode = NULL; xid = get_xid(); tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) { rc = PTR_ERR(tlink); goto symlink_exit; } pTcon = tlink_tcon(tlink); full_path = build_path_from_dentry(direntry); if (full_path == NULL) { rc = -ENOMEM; goto symlink_exit; } cifs_dbg(FYI, "Full path: %s\n", full_path); cifs_dbg(FYI, "symname is %s\n", symname); /* BB what if DFS and this volume is on different share? BB */ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) rc = create_mf_symlink(xid, pTcon, cifs_sb, full_path, symname); else if (pTcon->unix_ext) rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname, cifs_sb->local_nls, cifs_remap(cifs_sb)); /* else rc = CIFSCreateReparseSymLink(xid, pTcon, fromName, toName, cifs_sb_target->local_nls); */ if (rc == 0) { if (pTcon->unix_ext) rc = cifs_get_inode_info_unix(&newinode, full_path, inode->i_sb, xid); else rc = cifs_get_inode_info(&newinode, full_path, NULL, inode->i_sb, xid, NULL); if (rc != 0) { cifs_dbg(FYI, "Create symlink ok, getinodeinfo fail rc = %d\n", rc); } else { d_instantiate(direntry, newinode); } } symlink_exit: kfree(full_path); cifs_put_tlink(tlink); free_xid(xid); return rc; }
STATIC int xfs_vn_mknod( struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) { struct inode *inode; struct xfs_inode *ip = NULL; xfs_acl_t *default_acl = NULL; struct xfs_name name; attrexists_t test_default_acl = _ACL_DEFAULT_EXISTS; int error; /* * Irix uses Missed'em'V split, but doesn't want to see * the upper 5 bits of (14bit) major. */ if (unlikely(!sysv_valid_dev(rdev) || MAJOR(rdev) & ~0x1ff)) return -EINVAL; if (test_default_acl && test_default_acl(dir)) { if (!_ACL_ALLOC(default_acl)) { return -ENOMEM; } if (!_ACL_GET_DEFAULT(dir, default_acl)) { _ACL_FREE(default_acl); default_acl = NULL; } } xfs_dentry_to_name(&name, dentry); if (IS_POSIXACL(dir) && !default_acl) mode &= ~current->fs->umask; switch (mode & S_IFMT) { case S_IFCHR: case S_IFBLK: case S_IFIFO: case S_IFSOCK: rdev = sysv_encode_dev(rdev); case S_IFREG: error = xfs_create(XFS_I(dir), &name, mode, rdev, &ip, NULL); break; case S_IFDIR: error = xfs_mkdir(XFS_I(dir), &name, mode, &ip, NULL); break; default: error = EINVAL; break; } if (unlikely(error)) goto out_free_acl; inode = ip->i_vnode; error = xfs_init_security(inode, dir); if (unlikely(error)) goto out_cleanup_inode; if (default_acl) { error = _ACL_INHERIT(inode, mode, default_acl); if (unlikely(error)) goto out_cleanup_inode; xfs_iflags_set(ip, XFS_IMODIFIED); _ACL_FREE(default_acl); } if (S_ISDIR(mode)) xfs_validate_fields(inode); d_instantiate(dentry, inode); xfs_validate_fields(dir); return -error; out_cleanup_inode: xfs_cleanup_inode(dir, inode, dentry, mode); out_free_acl: if (default_acl) _ACL_FREE(default_acl); return -error; }
static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode) { struct gfs2_inode *dip = GFS2_I(dir), *ip; struct gfs2_sbd *sdp = GFS2_SB(dir); struct gfs2_holder ghs[2]; struct inode *inode; struct buffer_head *dibh; int error; gfs2_holder_init(dip->i_gl, 0, 0, ghs); inode = gfs2_createi(ghs, &dentry->d_name, S_IFDIR | mode, 0); if (IS_ERR(inode)) { gfs2_holder_uninit(ghs); return PTR_ERR(inode); } ip = ghs[1].gh_gl->gl_object; ip->i_inode.i_nlink = 2; ip->i_di.di_size = sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode); ip->i_di.di_flags |= GFS2_DIF_JDATA; ip->i_di.di_entries = 2; error = gfs2_meta_inode_buffer(ip, &dibh); if (!gfs2_assert_withdraw(sdp, !error)) { struct gfs2_dinode *di = (struct gfs2_dinode *)dibh->b_data; struct gfs2_dirent *dent = (struct gfs2_dirent *)(di+1); struct qstr str; gfs2_str2qstr(&str, "."); gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_qstr2dirent(&str, GFS2_DIRENT_SIZE(str.len), dent); dent->de_inum = di->di_num; /* already GFS2 endian */ dent->de_type = cpu_to_be16(DT_DIR); di->di_entries = cpu_to_be32(1); gfs2_str2qstr(&str, ".."); dent = (struct gfs2_dirent *)((char*)dent + GFS2_DIRENT_SIZE(1)); gfs2_qstr2dirent(&str, dibh->b_size - GFS2_DIRENT_SIZE(1) - sizeof(struct gfs2_dinode), dent); gfs2_inum_out(dip, dent); dent->de_type = cpu_to_be16(DT_DIR); gfs2_dinode_out(ip, di); brelse(dibh); } error = gfs2_change_nlink(dip, +1); gfs2_assert_withdraw(sdp, !error); /* dip already pinned */ gfs2_trans_end(sdp); if (dip->i_alloc->al_rgd) gfs2_inplace_release(dip); gfs2_quota_unlock(dip); gfs2_alloc_put(dip); gfs2_glock_dq_uninit_m(2, ghs); d_instantiate(dentry, inode); mark_inode_dirty(inode); return 0; }
STATIC int xfs_vn_mknod( struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) { struct inode *inode; struct xfs_inode *ip = NULL; struct posix_acl *default_acl = NULL; struct xfs_name name; int error; /* * Irix uses Missed'em'V split, but doesn't want to see * the upper 5 bits of (14bit) major. */ if (S_ISCHR(mode) || S_ISBLK(mode)) { if (unlikely(!sysv_valid_dev(rdev) || MAJOR(rdev) & ~0x1ff)) return -EINVAL; rdev = sysv_encode_dev(rdev); } else { rdev = 0; } if (IS_POSIXACL(dir)) { default_acl = xfs_get_acl(dir, ACL_TYPE_DEFAULT); if (IS_ERR(default_acl)) return PTR_ERR(default_acl); if (!default_acl) mode &= ~current_umask(); } xfs_dentry_to_name(&name, dentry); error = xfs_create(XFS_I(dir), &name, mode, rdev, &ip); if (unlikely(error)) goto out_free_acl; inode = VFS_I(ip); error = xfs_init_security(inode, dir, &dentry->d_name); if (unlikely(error)) goto out_cleanup_inode; if (default_acl) { error = -xfs_inherit_acl(inode, default_acl); if (unlikely(error)) goto out_cleanup_inode; posix_acl_release(default_acl); } d_instantiate(dentry, inode); return -error; out_cleanup_inode: xfs_cleanup_inode(dir, inode, dentry); out_free_acl: posix_acl_release(default_acl); return -error; }
int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode, dev_t device_number) { int rc = -EPERM; unsigned int xid; int create_options = CREATE_NOT_DIR | CREATE_OPTION_SPECIAL; struct cifs_sb_info *cifs_sb; struct tcon_link *tlink; struct cifs_tcon *pTcon; struct cifs_io_parms io_parms; char *full_path = NULL; struct inode *newinode = NULL; int oplock = 0; u16 fileHandle; FILE_ALL_INFO *buf = NULL; unsigned int bytes_written; struct win_dev *pdev; if (!old_valid_dev(device_number)) return -EINVAL; cifs_sb = CIFS_SB(inode->i_sb); tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) return PTR_ERR(tlink); pTcon = tlink_tcon(tlink); xid = get_xid(); full_path = build_path_from_dentry(direntry); if (full_path == NULL) { rc = -ENOMEM; goto mknod_out; } if (pTcon->unix_ext) { struct cifs_unix_set_info_args args = { .mode = mode & ~current_umask(), .ctime = NO_CHANGE_64, .atime = NO_CHANGE_64, .mtime = NO_CHANGE_64, .device = device_number, }; if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { args.uid = (__u64) current_fsuid(); args.gid = (__u64) current_fsgid(); } else { args.uid = NO_CHANGE_64; args.gid = NO_CHANGE_64; } rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, &args, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc) goto mknod_out; rc = cifs_get_inode_info_unix(&newinode, full_path, inode->i_sb, xid); if (rc == 0) d_instantiate(direntry, newinode); goto mknod_out; } if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) goto mknod_out; cFYI(1, "sfu compat create special file"); buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); if (buf == NULL) { kfree(full_path); rc = -ENOMEM; free_xid(xid); return rc; } if (backup_cred(cifs_sb)) create_options |= CREATE_OPEN_BACKUP_INTENT; rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_CREATE, GENERIC_WRITE, create_options, &fileHandle, &oplock, buf, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc) goto mknod_out; /* BB Do not bother to decode buf since no local inode yet to put * timestamps in, but we can reuse it safely */ pdev = (struct win_dev *)buf; io_parms.netfid = fileHandle; io_parms.pid = current->tgid; io_parms.tcon = pTcon; io_parms.offset = 0; io_parms.length = sizeof(struct win_dev); if (S_ISCHR(mode)) { memcpy(pdev->type, "IntxCHR", 8); pdev->major = cpu_to_le64(MAJOR(device_number)); pdev->minor = cpu_to_le64(MINOR(device_number)); rc = CIFSSMBWrite(xid, &io_parms, &bytes_written, (char *)pdev, NULL, 0); } else if (S_ISBLK(mode)) { memcpy(pdev->type, "IntxBLK", 8); pdev->major = cpu_to_le64(MAJOR(device_number)); pdev->minor = cpu_to_le64(MINOR(device_number)); rc = CIFSSMBWrite(xid, &io_parms, &bytes_written, (char *)pdev, NULL, 0); } /* else if (S_ISFIFO) */ CIFSSMBClose(xid, pTcon, fileHandle); d_drop(direntry); /* FIXME: add code here to set EAs */ mknod_out: kfree(full_path); kfree(buf); free_xid(xid); cifs_put_tlink(tlink); return rc; }
/* * 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; }
/* * Atomic create+open operation * * If the filesystem doesn't support this, then fall back to separate * 'mknod' + 'open' requests. */ static int fuse_create_open(struct inode *dir, struct dentry *entry, umode_t mode, struct nameidata *nd) { int err; struct inode *inode; struct fuse_conn *fc = get_fuse_conn(dir); struct fuse_req *req; struct fuse_forget_link *forget; struct fuse_create_in inarg; struct fuse_open_out outopen; struct fuse_entry_out outentry; struct fuse_file *ff; struct file *file; int flags = nd->intent.open.flags; if (fc->no_create) return -ENOSYS; forget = fuse_alloc_forget(); if (!forget) return -ENOMEM; req = fuse_get_req(fc); err = PTR_ERR(req); if (IS_ERR(req)) goto out_put_forget_req; err = -ENOMEM; ff = fuse_file_alloc(fc); if (!ff) goto out_put_request; if (!fc->dont_mask) mode &= ~current_umask(); flags &= ~O_NOCTTY; memset(&inarg, 0, sizeof(inarg)); memset(&outentry, 0, sizeof(outentry)); inarg.flags = flags; inarg.mode = mode; inarg.umask = current_umask(); req->in.h.opcode = FUSE_CREATE; req->in.h.nodeid = get_node_id(dir); req->in.numargs = 2; req->in.args[0].size = fc->minor < 12 ? sizeof(struct fuse_open_in) : sizeof(inarg); req->in.args[0].value = &inarg; req->in.args[1].size = entry->d_name.len + 1; req->in.args[1].value = entry->d_name.name; req->out.numargs = 2; if (fc->minor < 9) req->out.args[0].size = FUSE_COMPAT_ENTRY_OUT_SIZE; else req->out.args[0].size = sizeof(outentry); req->out.args[0].value = &outentry; req->out.args[1].size = sizeof(outopen); req->out.args[1].value = &outopen; fuse_request_send(fc, req); err = req->out.h.error; if (err) { if (err == -ENOSYS) fc->no_create = 1; goto out_free_ff; } err = -EIO; if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid)) goto out_free_ff; fuse_put_request(fc, req); ff->fh = outopen.fh; ff->nodeid = outentry.nodeid; ff->open_flags = outopen.open_flags; inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation, &outentry.attr, entry_attr_timeout(&outentry), 0); if (!inode) { flags &= ~(O_CREAT | O_EXCL | O_TRUNC); fuse_sync_release(ff, flags); fuse_queue_forget(fc, forget, outentry.nodeid, 1); return -ENOMEM; } kfree(forget); d_instantiate(entry, inode); fuse_change_entry_timeout(entry, &outentry); fuse_invalidate_attr(dir); file = lookup_instantiate_filp(nd, entry, generic_file_open); if (IS_ERR(file)) { fuse_sync_release(ff, flags); return PTR_ERR(file); } file->private_data = fuse_file_get(ff); fuse_finish_open(inode, file); return 0; out_free_ff: fuse_file_free(ff); out_put_request: fuse_put_request(fc, req); out_put_forget_req: kfree(forget); return err; }
/* * NAME: jfs_mkdir(dip, dentry, mode) * * FUNCTION: create a child directory in the parent directory <dip> * with name = <from dentry> and mode = <mode> * * PARAMETER: dip - parent directory vnode * dentry - dentry of child directory * mode - create mode (rwxrwxrwx). * * RETURN: Errors from subroutines * * note: * EACCESS: user needs search+write permission on the parent directory */ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode) { int rc = 0; tid_t tid; /* transaction id */ struct inode *ip = NULL; /* child directory inode */ ino_t ino; struct component_name dname; /* child directory name */ struct btstack btstack; struct inode *iplist[2]; struct tblock *tblk; jfs_info("jfs_mkdir: dip:0x%p name:%s", dip, dentry->d_name.name); /* link count overflow on parent directory ? */ if (dip->i_nlink == JFS_LINK_MAX) { rc = -EMLINK; goto out1; } /* * search parent directory for entry/freespace * (dtSearch() returns parent directory page pinned) */ if ((rc = get_UCSname(&dname, dentry))) goto out1; /* * Either iAlloc() or txBegin() may block. Deadlock can occur if we * block there while holding dtree page, so we allocate the inode & * begin the transaction before we search the directory. */ ip = ialloc(dip, S_IFDIR | mode); if (ip == NULL) { rc = -ENOSPC; goto out2; } tid = txBegin(dip->i_sb, 0); down(&JFS_IP(dip)->commit_sem); down(&JFS_IP(ip)->commit_sem); if ((rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE))) { jfs_err("jfs_mkdir: dtSearch returned %d", rc); goto out3; } tblk = tid_to_tblock(tid); tblk->xflag |= COMMIT_CREATE; tblk->ino = ip->i_ino; tblk->u.ixpxd = JFS_IP(ip)->ixpxd; iplist[0] = dip; iplist[1] = ip; /* * initialize the child directory in-line in inode */ dtInitRoot(tid, ip, dip->i_ino); /* * create entry in parent directory for child directory * (dtInsert() releases parent directory page) */ ino = ip->i_ino; if ((rc = dtInsert(tid, dip, &dname, &ino, &btstack))) { if (rc == -EIO) { jfs_err("jfs_mkdir: dtInsert returned -EIO"); txAbort(tid, 1); /* Marks Filesystem dirty */ } else txAbort(tid, 0); /* Filesystem full */ goto out3; } ip->i_nlink = 2; /* for '.' */ ip->i_op = &jfs_dir_inode_operations; ip->i_fop = &jfs_dir_operations; insert_inode_hash(ip); mark_inode_dirty(ip); /* update parent directory inode */ dip->i_nlink++; /* for '..' from child directory */ dip->i_ctime = dip->i_mtime = CURRENT_TIME; mark_inode_dirty(dip); rc = txCommit(tid, 2, &iplist[0], 0); out3: txEnd(tid); up(&JFS_IP(dip)->commit_sem); up(&JFS_IP(ip)->commit_sem); if (rc) { ip->i_nlink = 0; iput(ip); } else d_instantiate(dentry, ip); out2: free_UCSname(&dname); #ifdef CONFIG_JFS_POSIX_ACL if (rc == 0) jfs_init_acl(ip, dip); #endif out1: jfs_info("jfs_mkdir: rc:%d", rc); return rc; }