cregit-Linux how code gets into the kernel

Release 4.10 fs/ocfs2/namei.c

Directory: fs/ocfs2
/* -*- mode: c; c-basic-offset: 8; -*-
 * vim: noexpandtab sw=8 ts=8 sts=0:
 *
 * namei.c
 *
 * Create and rename file, directory, symlinks
 *
 * Copyright (C) 2002, 2004 Oracle.  All rights reserved.
 *
 *  Portions of this code from linux/fs/ext3/dir.c
 *
 *  Copyright (C) 1992, 1993, 1994, 1995
 *  Remy Card (card@masi.ibp.fr)
 *  Laboratoire MASI - Institut Blaise pascal
 *  Universite Pierre et Marie Curie (Paris VI)
 *
 *   from
 *
 *   linux/fs/minix/dir.c
 *
 *   Copyright (C) 1991, 1992 Linux Torvalds
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 021110-1307, USA.
 */

#include <linux/fs.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/highmem.h>
#include <linux/quotaops.h>

#include <cluster/masklog.h>

#include "ocfs2.h"

#include "alloc.h"
#include "dcache.h"
#include "dir.h"
#include "dlmglue.h"
#include "extent_map.h"
#include "file.h"
#include "inode.h"
#include "journal.h"
#include "namei.h"
#include "suballoc.h"
#include "super.h"
#include "symlink.h"
#include "sysfile.h"
#include "uptodate.h"
#include "xattr.h"
#include "acl.h"
#include "ocfs2_trace.h"

#include "buffer_head_io.h"

static int ocfs2_mknod_locked(struct ocfs2_super *osb,
			      struct inode *dir,
			      struct inode *inode,
			      dev_t dev,
			      struct buffer_head **new_fe_bh,
			      struct buffer_head *parent_fe_bh,
			      handle_t *handle,
			      struct ocfs2_alloc_context *inode_ac);

static int ocfs2_prepare_orphan_dir(struct ocfs2_super *osb,
				    struct inode **ret_orphan_dir,
				    u64 blkno,
				    char *name,
				    struct ocfs2_dir_lookup_result *lookup,
				    bool dio);

static int ocfs2_orphan_add(struct ocfs2_super *osb,
			    handle_t *handle,
			    struct inode *inode,
			    struct buffer_head *fe_bh,
			    char *name,
			    struct ocfs2_dir_lookup_result *lookup,
			    struct inode *orphan_dir_inode,
			    bool dio);

static int ocfs2_create_symlink_data(struct ocfs2_super *osb,
				     handle_t *handle,
				     struct inode *inode,
				     const char *symname);

static int ocfs2_double_lock(struct ocfs2_super *osb,
			     struct buffer_head **bh1,
			     struct inode *inode1,
			     struct buffer_head **bh2,
			     struct inode *inode2,
			     int rename);

static void ocfs2_double_unlock(struct inode *inode1, struct inode *inode2);
/* An orphan dir name is an 8 byte value, printed as a hex string */

#define OCFS2_ORPHAN_NAMELEN ((int)(2 * sizeof(u64)))


static struct dentry *ocfs2_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) { int status; u64 blkno; struct inode *inode = NULL; struct dentry *ret; struct ocfs2_inode_info *oi; trace_ocfs2_lookup(dir, dentry, dentry->d_name.len, dentry->d_name.name, (unsigned long long)OCFS2_I(dir)->ip_blkno, 0); if (dentry->d_name.len > OCFS2_MAX_FILENAME_LEN) { ret = ERR_PTR(-ENAMETOOLONG); goto bail; } status = ocfs2_inode_lock_nested(dir, NULL, 0, OI_LS_PARENT); if (status < 0) { if (status != -ENOENT) mlog_errno(status); ret = ERR_PTR(status); goto bail; } status = ocfs2_lookup_ino_from_name(dir, dentry->d_name.name, dentry->d_name.len, &blkno); if (status < 0) goto bail_add; inode = ocfs2_iget(OCFS2_SB(dir->i_sb), blkno, 0, 0); if (IS_ERR(inode)) { ret = ERR_PTR(-EACCES); goto bail_unlock; } oi = OCFS2_I(inode); /* Clear any orphaned state... If we were able to look up the * inode from a directory, it certainly can't be orphaned. We * might have the bad state from a node which intended to * orphan this inode but crashed before it could commit the * unlink. */ spin_lock(&oi->ip_lock); oi->ip_flags &= ~OCFS2_INODE_MAYBE_ORPHANED; spin_unlock(&oi->ip_lock); bail_add: ret = d_splice_alias(inode, dentry); if (inode) { /* * If d_splice_alias() finds a DCACHE_DISCONNECTED * dentry, it will d_move() it on top of ourse. The * return value will indicate this however, so in * those cases, we switch them around for the locking * code. * * NOTE: This dentry already has ->d_op set from * ocfs2_get_parent() and ocfs2_get_dentry() */ if (!IS_ERR_OR_NULL(ret)) dentry = ret; status = ocfs2_dentry_attach_lock(dentry, inode, OCFS2_I(dir)->ip_blkno); if (status) { mlog_errno(status); ret = ERR_PTR(status); goto bail_unlock; } } else ocfs2_dentry_attach_gen(dentry); bail_unlock: /* Don't drop the cluster lock until *after* the d_add -- * unlink on another node will message us to remove that * dentry under this lock so otherwise we can race this with * the downconvert thread and have a stale dentry. */ ocfs2_inode_unlock(dir, 0); bail: trace_ocfs2_lookup_ret(ret); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
mark fashehmark fasheh30389.91%650.00%
tao matao ma164.75%18.33%
goldwyn rodriguesgoldwyn rodrigues61.78%18.33%
jan karajan kara51.48%216.67%
richard weinbergerrichard weinberger41.19%18.33%
al viroal viro30.89%18.33%
Total337100.00%12100.00%


static struct inode *ocfs2_get_init_inode(struct inode *dir, umode_t mode) { struct inode *inode; int status; inode = new_inode(dir->i_sb); if (!inode) { mlog(ML_ERROR, "new_inode failed!\n"); return ERR_PTR(-ENOMEM); } /* populate as many fields early on as possible - many of * these are used by the support functions here and in * callers. */ if (S_ISDIR(mode)) set_nlink(inode, 2); inode_init_owner(inode, dir, mode); status = dquot_initialize(inode); if (status) return ERR_PTR(status); return inode; }

Contributors

PersonTokensPropCommitsCommitProp
tiger yangtiger yang6465.31%114.29%
jan karajan kara2424.49%228.57%
miklos szeredimiklos szeredi44.08%114.29%
dmitriy monakhovdmitriy monakhov44.08%114.29%
al viroal viro11.02%114.29%
christoph hellwigchristoph hellwig11.02%114.29%
Total98100.00%7100.00%


static void ocfs2_cleanup_add_entry_failure(struct ocfs2_super *osb, struct dentry *dentry, struct inode *inode) { struct ocfs2_dentry_lock *dl = dentry->d_fsdata; ocfs2_simple_drop_lockres(osb, &dl->dl_lockres); ocfs2_lock_res_free(&dl->dl_lockres); BUG_ON(dl->dl_count != 1); spin_lock(&dentry_attach_lock); dentry->d_fsdata = NULL; spin_unlock(&dentry_attach_lock); kfree(dl); iput(inode); }

Contributors

PersonTokensPropCommitsCommitProp
yiwen jiangyiwen jiang85100.00%1100.00%
Total85100.00%1100.00%


static int ocfs2_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev) { int status = 0; struct buffer_head *parent_fe_bh = NULL; handle_t *handle = NULL; struct ocfs2_super *osb; struct ocfs2_dinode *dirfe; struct buffer_head *new_fe_bh = NULL; struct inode *inode = NULL; struct ocfs2_alloc_context *inode_ac = NULL; struct ocfs2_alloc_context *data_ac = NULL; struct ocfs2_alloc_context *meta_ac = NULL; int want_clusters = 0; int want_meta = 0; int xattr_credits = 0; struct ocfs2_security_xattr_info si = { .enable = 1, }; int did_quota_inode = 0; struct ocfs2_dir_lookup_result lookup = { NULL, }; sigset_t oldset; int did_block_signals = 0; struct ocfs2_dentry_lock *dl = NULL; trace_ocfs2_mknod(dir, dentry, dentry->d_name.len, dentry->d_name.name, (unsigned long long)OCFS2_I(dir)->ip_blkno, (unsigned long)dev, mode); status = dquot_initialize(dir); if (status) { mlog_errno(status); return status; } /* get our super block */ osb = OCFS2_SB(dir->i_sb); status = ocfs2_inode_lock(dir, &parent_fe_bh, 1); if (status < 0) { if (status != -ENOENT) mlog_errno(status); return status; } if (S_ISDIR(mode) && (dir->i_nlink >= ocfs2_link_max(osb))) { status = -EMLINK; goto leave; } dirfe = (struct ocfs2_dinode *) parent_fe_bh->b_data; if (!ocfs2_read_links_count(dirfe)) { /* can't make a file in a deleted directory. */ status = -ENOENT; goto leave; } status = ocfs2_check_dir_for_entry(dir, dentry->d_name.name, dentry->d_name.len); if (status) goto leave; /* get a spot inside the dir. */ status = ocfs2_prepare_dir_for_insert(osb, dir, parent_fe_bh, dentry->d_name.name, dentry->d_name.len, &lookup); if (status < 0) { mlog_errno(status); goto leave; } /* reserve an inode spot */ status = ocfs2_reserve_new_inode(osb, &inode_ac); if (status < 0) { if (status != -ENOSPC) mlog_errno(status); goto leave; } inode = ocfs2_get_init_inode(dir, mode); if (IS_ERR(inode)) { status = PTR_ERR(inode); inode = NULL; mlog_errno(status); goto leave; } /* get security xattr */ status = ocfs2_init_security_get(inode, dir, &dentry->d_name, &si); if (status) { if (status == -EOPNOTSUPP) si.enable = 0; else { mlog_errno(status); goto leave; } } /* calculate meta data/clusters for setting security and acl xattr */ status = ocfs2_calc_xattr_init(dir, parent_fe_bh, mode, &si, &want_clusters, &xattr_credits, &want_meta); if (status < 0) { mlog_errno(status); goto leave; } /* Reserve a cluster if creating an extent based directory. */ if (S_ISDIR(mode) && !ocfs2_supports_inline_data(osb)) { want_clusters += 1; /* Dir indexing requires extra space as well */ if (ocfs2_supports_indexed_dirs(osb)) want_meta++; } status = ocfs2_reserve_new_metadata_blocks(osb, want_meta, &meta_ac); if (status < 0) { if (status != -ENOSPC) mlog_errno(status); goto leave; } status = ocfs2_reserve_clusters(osb, want_clusters, &data_ac); if (status < 0) { if (status != -ENOSPC) mlog_errno(status); goto leave; } handle = ocfs2_start_trans(osb, ocfs2_mknod_credits(osb->sb, S_ISDIR(mode), xattr_credits)); if (IS_ERR(handle)) { status = PTR_ERR(handle); handle = NULL; mlog_errno(status); goto leave; } /* Starting to change things, restart is no longer possible. */ ocfs2_block_signals(&oldset); did_block_signals = 1; status = dquot_alloc_inode(inode); if (status) goto leave; did_quota_inode = 1; /* do the real work now. */ status = ocfs2_mknod_locked(osb, dir, inode, dev, &new_fe_bh, parent_fe_bh, handle, inode_ac); if (status < 0) { mlog_errno(status); goto leave; } if (S_ISDIR(mode)) { status = ocfs2_fill_new_dir(osb, handle, dir, inode, new_fe_bh, data_ac, meta_ac); if (status < 0) { mlog_errno(status); goto leave; } status = ocfs2_journal_access_di(handle, INODE_CACHE(dir), parent_fe_bh, OCFS2_JOURNAL_ACCESS_WRITE); if (status < 0) { mlog_errno(status); goto leave; } ocfs2_add_links_count(dirfe, 1); ocfs2_journal_dirty(handle, parent_fe_bh); inc_nlink(dir); } status = ocfs2_init_acl(handle, inode, dir, new_fe_bh, parent_fe_bh, meta_ac, data_ac); if (status < 0) { mlog_errno(status); goto leave; } if (si.enable) { status = ocfs2_init_security_set(handle, inode, new_fe_bh, &si, meta_ac, data_ac); if (status < 0) { mlog_errno(status); goto leave; } } /* * Do this before adding the entry to the directory. We add * also set d_op after success so that ->d_iput() will cleanup * the dentry lock even if ocfs2_add_entry() fails below. */ status = ocfs2_dentry_attach_lock(dentry, inode, OCFS2_I(dir)->ip_blkno); if (status) { mlog_errno(status); goto leave; } dl = dentry->d_fsdata; status = ocfs2_add_entry(handle, dentry, inode, OCFS2_I(inode)->ip_blkno, parent_fe_bh, &lookup); if (status < 0) { mlog_errno(status); goto leave; } insert_inode_hash(inode); d_instantiate(dentry, inode); status = 0; leave: if (status < 0 && did_quota_inode) dquot_free_inode(inode); if (handle) ocfs2_commit_trans(osb, handle); ocfs2_inode_unlock(dir, 1); if (did_block_signals) ocfs2_unblock_signals(&oldset); brelse(new_fe_bh); brelse(parent_fe_bh); kfree(si.value); ocfs2_free_dir_lookup_result(&lookup); if (inode_ac) ocfs2_free_alloc_context(inode_ac); if (data_ac) ocfs2_free_alloc_context(data_ac); if (meta_ac) ocfs2_free_alloc_context(meta_ac); /* * We should call iput after the i_mutex of the bitmap been * unlocked in ocfs2_free_alloc_context, or the * ocfs2_delete_inode will mutex_lock again. */ if ((status < 0) && inode) { if (dl) ocfs2_cleanup_add_entry_failure(osb, dentry, inode); OCFS2_I(inode)->ip_flags |= OCFS2_INODE_SKIP_ORPHAN_DIR; clear_nlink(inode); iput(inode); } if (status) mlog_errno(status); return status; }

Contributors

PersonTokensPropCommitsCommitProp
mark fashehmark fasheh73463.17%828.57%
tiger yangtiger yang22819.62%310.71%
jan karajan kara615.25%27.14%
li dongyangli dongyang322.75%13.57%
joel beckerjoel becker312.67%310.71%
tao matao ma262.24%27.14%
yiwen jiangyiwen jiang252.15%13.57%
christoph hellwigchristoph hellwig141.20%414.29%
eric pariseric paris50.43%13.57%
junxiao bijunxiao bi30.26%13.57%
dave hansendave hansen20.17%13.57%
al viroal viro10.09%13.57%
Total1162100.00%28100.00%


static int __ocfs2_mknod_locked(struct inode *dir, struct inode *inode, dev_t dev, struct buffer_head **new_fe_bh, struct buffer_head *parent_fe_bh, handle_t *handle, struct ocfs2_alloc_context *inode_ac, u64 fe_blkno, u64 suballoc_loc, u16 suballoc_bit) { int status = 0; struct ocfs2_super *osb = OCFS2_SB(dir->i_sb); struct ocfs2_dinode *fe = NULL; struct ocfs2_extent_list *fel; u16 feat; struct ocfs2_inode_info *oi = OCFS2_I(inode); struct timespec64 ts; *new_fe_bh = NULL; /* populate as many fields early on as possible - many of * these are used by the support functions here and in * callers. */ inode->i_ino = ino_from_blkno(osb->sb, fe_blkno); OCFS2_I(inode)->ip_blkno = fe_blkno; spin_lock(&osb->osb_lock); inode->i_generation = osb->s_next_generation++; spin_unlock(&osb->osb_lock); *new_fe_bh = sb_getblk(osb->sb, fe_blkno); if (!*new_fe_bh) { status = -ENOMEM; mlog_errno(status); goto leave; } ocfs2_set_new_buffer_uptodate(INODE_CACHE(inode), *new_fe_bh); status = ocfs2_journal_access_di(handle, INODE_CACHE(inode), *new_fe_bh, OCFS2_JOURNAL_ACCESS_CREATE); if (status < 0) { mlog_errno(status); goto leave; } fe = (struct ocfs2_dinode *) (*new_fe_bh)->b_data; memset(fe, 0, osb->sb->s_blocksize); fe->i_generation = cpu_to_le32(inode->i_generation); fe->i_fs_generation = cpu_to_le32(osb->fs_generation); fe->i_blkno = cpu_to_le64(fe_blkno); fe->i_suballoc_loc = cpu_to_le64(suballoc_loc); fe->i_suballoc_bit = cpu_to_le16(suballoc_bit); fe->i_suballoc_slot = cpu_to_le16(inode_ac->ac_alloc_slot); fe->i_uid = cpu_to_le32(i_uid_read(inode)); fe->i_gid = cpu_to_le32(i_gid_read(inode)); fe->i_mode = cpu_to_le16(inode->i_mode); if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) fe->id1.dev1.i_rdev = cpu_to_le64(huge_encode_dev(dev)); ocfs2_set_links_count(fe, inode->i_nlink); fe->i_last_eb_blk = 0; strcpy(fe->i_signature, OCFS2_INODE_SIGNATURE); fe->i_flags |= cpu_to_le32(OCFS2_VALID_FL); ktime_get_real_ts64(&ts); fe->i_atime = fe->i_ctime = fe->i_mtime = cpu_to_le64(ts.tv_sec); fe->i_mtime_nsec = fe->i_ctime_nsec = fe->i_atime_nsec = cpu_to_le32(ts.tv_nsec); fe->i_dtime = 0; /* * If supported, directories start with inline data. If inline * isn't supported, but indexing is, we start them as indexed. */ feat = le16_to_cpu(fe->i_dyn_features); if (S_ISDIR(inode->i_mode) && ocfs2_supports_inline_data(osb)) { fe->i_dyn_features = cpu_to_le16(feat | OCFS2_INLINE_DATA_FL); fe->id2.i_data.id_count = cpu_to_le16( ocfs2_max_inline_data_with_xattr(osb->sb, fe)); } else { fel = &fe->id2.i_list; fel->l_tree_depth = 0; fel->l_next_free_rec = 0; fel->l_count = cpu_to_le16(ocfs2_extent_recs_per_inode(osb->sb)); } ocfs2_journal_dirty(handle, *new_fe_bh); ocfs2_populate_inode(inode, fe, 1); ocfs2_ci_set_new(osb, INODE_CACHE(inode)); if (!ocfs2_mount_local(osb)) { status = ocfs2_create_new_inode_locks(inode); if (status < 0) mlog_errno(status); } oi->i_sync_tid = handle->h_transaction->t_tid; oi->i_datasync_tid = handle->h_transaction->t_tid; leave: if (status < 0) { if (*new_fe_bh) { brelse(*new_fe_bh); *new_fe_bh = NULL; } } if (status) mlog_errno(status); return status; }

Contributors

PersonTokensPropCommitsCommitProp
mark fashehmark fasheh56083.46%628.57%
darrick j. wongdarrick j. wong304.47%14.76%
tiger yangtiger yang213.13%29.52%
joel beckerjoel becker202.98%419.05%
deepa dinamanideepa dinamani121.79%14.76%
sunil mushransunil mushran101.49%14.76%
tao matao ma71.04%29.52%
eric w. biedermaneric w. biederman60.89%14.76%
joseph qijoseph qi30.45%14.76%
rui xiangrui xiang10.15%14.76%
jan karajan kara10.15%14.76%
Total671100.00%21100.00%


static int ocfs2_mknod_locked(struct ocfs2_super *osb, struct inode *dir, struct inode *inode, dev_t dev, struct buffer_head **new_fe_bh, struct buffer_head *parent_fe_bh, handle_t *handle, struct ocfs2_alloc_context *inode_ac) { int status = 0; u64 suballoc_loc, fe_blkno = 0; u16 suballoc_bit; *new_fe_bh = NULL; status = ocfs2_claim_new_inode(handle, dir, parent_fe_bh, inode_ac, &suballoc_loc, &suballoc_bit, &fe_blkno); if (status < 0) { mlog_errno(status); return status; } status = __ocfs2_mknod_locked(dir, inode, dev, new_fe_bh, parent_fe_bh, handle, inode_ac, fe_blkno, suballoc_loc, suballoc_bit); if (status < 0) { u64 bg_blkno = ocfs2_which_suballoc_group(fe_blkno, suballoc_bit); int tmp = ocfs2_free_suballoc_bits(handle, inode_ac->ac_inode, inode_ac->ac_bh, suballoc_bit, bg_blkno, 1); if (tmp) mlog_errno(tmp); } return status; }

Contributors

PersonTokensPropCommitsCommitProp
mark fashehmark fasheh12569.83%150.00%
alex chenalex chen5430.17%150.00%
Total179100.00%2100.00%


static int ocfs2_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { int ret; trace_ocfs2_mkdir(dir, dentry, dentry->d_name.len, dentry->d_name.name, OCFS2_I(dir)->ip_blkno, mode); ret = ocfs2_mknod(dir, dentry, mode | S_IFDIR, 0); if (ret) mlog_errno(ret); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
mark fashehmark fasheh6179.22%125.00%
tao matao ma1519.48%250.00%
al viroal viro11.30%125.00%
Total77100.00%4100.00%


static int ocfs2_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool excl) { int ret; trace_ocfs2_create(dir, dentry