Release 4.10 fs/gfs2/inode.c
/*
* Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
* Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License version 2.
*/
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/completion.h>
#include <linux/buffer_head.h>
#include <linux/namei.h>
#include <linux/mm.h>
#include <linux/xattr.h>
#include <linux/posix_acl.h>
#include <linux/gfs2_ondisk.h>
#include <linux/crc32.h>
#include <linux/fiemap.h>
#include <linux/security.h>
#include <linux/uaccess.h>
#include "gfs2.h"
#include "incore.h"
#include "acl.h"
#include "bmap.h"
#include "dir.h"
#include "xattr.h"
#include "glock.h"
#include "inode.h"
#include "meta_io.h"
#include "quota.h"
#include "rgrp.h"
#include "trans.h"
#include "util.h"
#include "super.h"
#include "glops.h"
static int iget_test(struct inode *inode, void *opaque)
{
u64 no_addr = *(u64 *)opaque;
return GFS2_I(inode)->i_no_addr == no_addr;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
andreas gruenbacher | andreas gruenbacher | 32 | 91.43% | 1 | 50.00% |
steven whitehouse | steven whitehouse | 3 | 8.57% | 1 | 50.00% |
| Total | 35 | 100.00% | 2 | 100.00% |
static int iget_set(struct inode *inode, void *opaque)
{
u64 no_addr = *(u64 *)opaque;
GFS2_I(inode)->i_no_addr = no_addr;
inode->i_ino = no_addr;
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
andreas gruenbacher | andreas gruenbacher | 43 | 100.00% | 1 | 100.00% |
| Total | 43 | 100.00% | 1 | 100.00% |
static struct inode *gfs2_iget(struct super_block *sb, u64 no_addr)
{
struct inode *inode;
repeat:
inode = iget5_locked(sb, no_addr, iget_test, iget_set, &no_addr);
if (!inode)
return inode;
if (is_bad_inode(inode)) {
iput(inode);
goto repeat;
}
return inode;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
andreas gruenbacher | andreas gruenbacher | 50 | 74.63% | 2 | 66.67% |
steven whitehouse | steven whitehouse | 17 | 25.37% | 1 | 33.33% |
| Total | 67 | 100.00% | 3 | 100.00% |
/**
* gfs2_set_iop - Sets inode operations
* @inode: The inode with correct i_mode filled in
*
* GFS2 lookup code fills in vfs inode contents based on info obtained
* from directory entry inside gfs2_inode_lookup().
*/
static void gfs2_set_iop(struct inode *inode)
{
struct gfs2_sbd *sdp = GFS2_SB(inode);
umode_t mode = inode->i_mode;
if (S_ISREG(mode)) {
inode->i_op = &gfs2_file_iops;
if (gfs2_localflocks(sdp))
inode->i_fop = &gfs2_file_fops_nolock;
else
inode->i_fop = &gfs2_file_fops;
} else if (S_ISDIR(mode)) {
inode->i_op = &gfs2_dir_iops;
if (gfs2_localflocks(sdp))
inode->i_fop = &gfs2_dir_fops_nolock;
else
inode->i_fop = &gfs2_dir_fops;
} else if (S_ISLNK(mode)) {
inode->i_op = &gfs2_symlink_iops;
} else {
inode->i_op = &gfs2_file_iops;
init_special_inode(inode, inode->i_mode, inode->i_rdev);
}
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
steven whitehouse | steven whitehouse | 145 | 100.00% | 1 | 100.00% |
| Total | 145 | 100.00% | 1 | 100.00% |
/**
* gfs2_inode_lookup - Lookup an inode
* @sb: The super block
* @type: The type of the inode
* @no_addr: The inode number
* @no_formal_ino: The inode generation number
* @blktype: Requested block type (GFS2_BLKST_DINODE or GFS2_BLKST_UNLINKED;
* GFS2_BLKST_FREE do indicate not to verify)
*
* If @type is DT_UNKNOWN, the inode type is fetched from disk.
*
* If @blktype is anything other than GFS2_BLKST_FREE (which is used as a
* placeholder because it doesn't otherwise make sense), the on-disk block type
* is verified to be @blktype.
*
* Returns: A VFS inode, or an error
*/
struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type,
u64 no_addr, u64 no_formal_ino,
unsigned int blktype)
{
struct inode *inode;
struct gfs2_inode *ip;
struct gfs2_glock *io_gl = NULL;
struct gfs2_holder i_gh;
int error;
gfs2_holder_mark_uninitialized(&i_gh);
inode = gfs2_iget(sb, no_addr);
if (!inode)
return ERR_PTR(-ENOMEM);
ip = GFS2_I(inode);
if (inode->i_state & I_NEW) {
struct gfs2_sbd *sdp = GFS2_SB(inode);
ip->i_no_formal_ino = no_formal_ino;
error = gfs2_glock_get(sdp, no_addr, &gfs2_inode_glops, CREATE, &ip->i_gl);
if (unlikely(error))
goto fail;
ip->i_gl->gl_object = ip;
error = gfs2_glock_get(sdp, no_addr, &gfs2_iopen_glops, CREATE, &io_gl);
if (unlikely(error))
goto fail_put;
if (type == DT_UNKNOWN || blktype != GFS2_BLKST_FREE) {
/*
* The GL_SKIP flag indicates to skip reading the inode
* block. We read the inode with gfs2_inode_refresh
* after possibly checking the block type.
*/
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE,
GL_SKIP, &i_gh);
if (error)
goto fail_put;
if (blktype != GFS2_BLKST_FREE) {
error = gfs2_check_blk_type(sdp, no_addr,
blktype);
if (error)
goto fail_put;
}
}
set_bit(GIF_INVALID, &ip->i_flags);
error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, GL_EXACT, &ip->i_iopen_gh);
if (unlikely(error))
goto fail_put;
ip->i_iopen_gh.gh_gl->gl_object = ip;
gfs2_glock_put(io_gl);
io_gl = NULL;
if (type == DT_UNKNOWN) {
/* Inode glock must be locked already */
error = gfs2_inode_refresh(GFS2_I(inode));
if (error)
goto fail_refresh;
} else {
inode->i_mode = DT2IF(type);
}
gfs2_set_iop(inode);
inode->i_atime.tv_sec = 0;
inode->i_atime.tv_nsec = 0;
unlock_new_inode(inode);
}
if (gfs2_holder_initialized(&i_gh))
gfs2_glock_dq_uninit(&i_gh);
return inode;
fail_refresh:
ip->i_iopen_gh.gh_flags |= GL_NOCACHE;
ip->i_iopen_gh.gh_gl->gl_object = NULL;
gfs2_glock_dq_wait(&ip->i_iopen_gh);
gfs2_holder_uninit(&ip->i_iopen_gh);
fail_put:
if (io_gl)
gfs2_glock_put(io_gl);
if (gfs2_holder_initialized(&i_gh))
gfs2_glock_dq_uninit(&i_gh);
ip->i_gl->gl_object = NULL;
fail:
iget_failed(inode);
return ERR_PTR(error);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
steven whitehouse | steven whitehouse | 302 | 66.52% | 1 | 14.29% |
andreas gruenbacher | andreas gruenbacher | 123 | 27.09% | 3 | 42.86% |
robert s. peterson | robert s. peterson | 29 | 6.39% | 3 | 42.86% |
| Total | 454 | 100.00% | 7 | 100.00% |
struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr,
u64 *no_formal_ino, unsigned int blktype)
{
struct super_block *sb = sdp->sd_vfs;
struct inode *inode;
int error;
inode = gfs2_inode_lookup(sb, DT_UNKNOWN, no_addr, 0, blktype);
if (IS_ERR(inode))
return inode;
/* Two extra checks for NFS only */
if (no_formal_ino) {
error = -ESTALE;
if (GFS2_I(inode)->i_no_formal_ino != *no_formal_ino)
goto fail_iput;
error = -EIO;
if (GFS2_I(inode)->i_diskflags & GFS2_DIF_SYSTEM)
goto fail_iput;
}
return inode;
fail_iput:
iput(inode);
return ERR_PTR(error);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
steven whitehouse | steven whitehouse | 116 | 91.34% | 1 | 50.00% |
andreas gruenbacher | andreas gruenbacher | 11 | 8.66% | 1 | 50.00% |
| Total | 127 | 100.00% | 2 | 100.00% |
struct inode *gfs2_lookup_simple(struct inode *dip, const char *name)
{
struct qstr qstr;
struct inode *inode;
gfs2_str2qstr(&qstr, name);
inode = gfs2_lookupi(dip, &qstr, 1);
/* gfs2_lookupi has inconsistent callers: vfs
* related routines expect NULL for no entry found,
* gfs2_lookup_simple callers expect ENOENT
* and do not check for NULL.
*/
if (inode == NULL)
return ERR_PTR(-ENOENT);
else
return inode;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
steven whitehouse | steven whitehouse | 64 | 100.00% | 1 | 100.00% |
| Total | 64 | 100.00% | 1 | 100.00% |
/**
* gfs2_lookupi - Look up a filename in a directory and return its inode
* @d_gh: An initialized holder for the directory glock
* @name: The name of the inode to look for
* @is_root: If 1, ignore the caller's permissions
* @i_gh: An uninitialized holder for the new inode glock
*
* This can be called via the VFS filldir function when NFS is doing
* a readdirplus and the inode which its intending to stat isn't
* already in cache. In this case we must not take the directory glock
* again, since the readdir call will have already taken that lock.
*
* Returns: errno
*/
struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name,
int is_root)
{
struct super_block *sb = dir->i_sb;
struct gfs2_inode *dip = GFS2_I(dir);
struct gfs2_holder d_gh;
int error = 0;
struct inode *inode = NULL;
gfs2_holder_mark_uninitialized(&d_gh);
if (!name->len || name->len > GFS2_FNAMESIZE)
return ERR_PTR(-ENAMETOOLONG);
if ((name->len == 1 && memcmp(name->name, ".", 1) == 0) ||
(name->len == 2 && memcmp(name->name, "..", 2) == 0 &&
dir == d_inode(sb->s_root))) {
igrab(dir);
return dir;
}
if (gfs2_glock_is_locked_by_me(dip->i_gl) == NULL) {
error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh);
if (error)
return ERR_PTR(error);
}
if (!is_root) {
error = gfs2_permission(dir, MAY_EXEC);
if (error)
goto out;
}
inode = gfs2_dir_search(dir, name, false);
if (IS_ERR(inode))
error = PTR_ERR(inode);
out:
if (gfs2_holder_initialized(&d_gh))
gfs2_glock_dq_uninit(&d_gh);
if (error == -ENOENT)
return NULL;
return inode ? inode : ERR_PTR(error);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
steven whitehouse | steven whitehouse | 254 | 94.78% | 2 | 50.00% |
andreas gruenbacher | andreas gruenbacher | 11 | 4.10% | 1 | 25.00% |
david howells | david howells | 3 | 1.12% | 1 | 25.00% |
| Total | 268 | 100.00% | 4 | 100.00% |
/**
* create_ok - OK to create a new on-disk inode here?
* @dip: Directory in which dinode is to be created
* @name: Name of new dinode
* @mode:
*
* Returns: errno
*/
static int create_ok(struct gfs2_inode *dip, const struct qstr *name,
umode_t mode)
{
int error;
error = gfs2_permission(&dip->i_inode, MAY_WRITE | MAY_EXEC);
if (error)
return error;
/* Don't create entries in an unlinked directory */
if (!dip->i_inode.i_nlink)
return -ENOENT;
if (dip->i_entries == (u32)-1)
return -EFBIG;
if (S_ISDIR(mode) && dip->i_inode.i_nlink == (u32)-1)
return -EMLINK;
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
steven whitehouse | steven whitehouse | 99 | 99.00% | 1 | 50.00% |
al viro | al viro | 1 | 1.00% | 1 | 50.00% |
| Total | 100 | 100.00% | 2 | 100.00% |
static void munge_mode_uid_gid(const struct gfs2_inode *dip,
struct inode *inode)
{
if (GFS2_SB(&dip->i_inode)->sd_args.ar_suiddir &&
(dip->i_inode.i_mode & S_ISUID) &&
!uid_eq(dip->i_inode.i_uid, GLOBAL_ROOT_UID)) {
if (S_ISDIR(inode->i_mode))
inode->i_mode |= S_ISUID;
else if (!uid_eq(dip->i_inode.i_uid, current_fsuid()))
inode->i_mode &= ~07111;
inode->i_uid = dip->i_inode.i_uid;
} else
inode->i_uid = current_fsuid();
if (dip->i_inode.i_mode & S_ISGID) {
if (S_ISDIR(inode->i_mode))
inode->i_mode |= S_ISGID;
inode->i_gid = dip->i_inode.i_gid;
} else
inode->i_gid = current_fsgid();
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
steven whitehouse | steven whitehouse | 145 | 92.95% | 2 | 66.67% |
eric w. biederman | eric w. biederman | 11 | 7.05% | 1 | 33.33% |
| Total | 156 | 100.00% | 3 | 100.00% |
static int alloc_dinode(struct gfs2_inode *ip, u32 flags, unsigned *dblocks)
{
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct gfs2_alloc_parms ap = { .target = *dblocks, .aflags = flags, };
int error;
error = gfs2_quota_lock_check(ip, &ap);
if (error)
goto out;
error = gfs2_inplace_reserve(ip, &ap);
if (error)
goto out_quota;
error = gfs2_trans_begin(sdp, (*dblocks * RES_RG_BIT) + RES_STATFS + RES_QUOTA, 0);
if (error)
goto out_ipreserv;
error = gfs2_alloc_blocks(ip, &ip->i_no_addr, dblocks, 1, &ip->i_generation);
ip->i_no_formal_ino = ip->i_generation;
ip->i_inode.i_ino = ip->i_no_addr;
ip->i_goal = ip->i_no_addr;
gfs2_trans_end(sdp);
out_ipreserv:
gfs2_inplace_release(ip);
out_quota:
gfs2_quota_unlock(ip);
out:
return error;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
steven whitehouse | steven whitehouse | 172 | 93.99% | 6 | 60.00% |
robert s. peterson | robert s. peterson | 8 | 4.37% | 3 | 30.00% |
abhijith das | abhijith das | 3 | 1.64% | 1 | 10.00% |
| Total | 183 | 100.00% | 10 | 100.00% |
static void gfs2_init_dir(struct buffer_head *dibh,
const struct gfs2_inode *parent)
{
struct gfs2_dinode *di = (struct gfs2_dinode *)dibh->b_data;
struct gfs2_dirent *dent = (struct gfs2_dirent *)(di+1);
gfs2_qstr2dirent(&gfs2_qdot, GFS2_DIRENT_SIZE(gfs2_qdot.len), dent);
dent->de_inum = di->di_num; /* already GFS2 endian */
dent->de_type = cpu_to_be16(DT_DIR);
dent = (struct gfs2_dirent *)((char*)dent + GFS2_DIRENT_SIZE(1));
gfs2_qstr2dirent(&gfs2_qdotdot, dibh->b_size - GFS2_DIRENT_SIZE(1) - sizeof(struct gfs2_dinode), dent);
gfs2_inum_out(parent, dent);
dent->de_type = cpu_to_be16(DT_DIR);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
steven whitehouse | steven whitehouse | 139 | 100.00% | 1 | 100.00% |
| Total | 139 | 100.00% | 1 | 100.00% |
/**
* gfs2_init_xattr - Initialise an xattr block for a new inode
* @ip: The inode in question
*
* This sets up an empty xattr block for a new inode, ready to
* take any ACLs, LSM xattrs, etc.
*/
static void gfs2_init_xattr(struct gfs2_inode *ip)
{
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct buffer_head *bh;
struct gfs2_ea_header *ea;
bh = gfs2_meta_new(ip->i_gl, ip->i_eattr);
gfs2_trans_add_meta(ip->i_gl, bh);
gfs2_metatype_set(bh, GFS2_METATYPE_EA, GFS2_FORMAT_EA);
gfs2_buffer_clear_tail(bh, sizeof(struct gfs2_meta_header));
ea = GFS2_EA_BH2FIRST(bh);
ea->ea_rec_len = cpu_to_be32(sdp->sd_jbsize);
ea->ea_type = GFS2_EATYPE_UNUSED;
ea->ea_flags = GFS2_EAFLAG_LAST;
brelse(bh);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
steven whitehouse | steven whitehouse | 111 | 100.00% | 1 | 100.00% |
| Total | 111 | 100.00% | 1 | 100.00% |
/**
* init_dinode - Fill in a new dinode structure
* @dip: The directory this inode is being created in
* @ip: The inode
* @symname: The symlink destination (if a symlink)
* @bhp: The buffer head (returned to caller)
*
*/
static void init_dinode(struct gfs2_inode *dip, struct gfs2_inode *ip,
const char *symname)
{
struct gfs2_dinode *di;
struct buffer_head *dibh;
dibh = gfs2_meta_new(ip->i_gl, ip->i_no_addr);
gfs2_trans_add_meta(ip->i_gl, dibh);
di = (struct gfs2_dinode *)dibh->b_data;
gfs2_dinode_out(ip, di);
di->di_major = cpu_to_be32(MAJOR(ip->i_inode.i_rdev));
di->di_minor = cpu_to_be32(MINOR(ip->i_inode.i_rdev));
di->__pad1 = 0;
di->__pad2 = 0;
di->__pad3 = 0;
memset(&di->__pad4, 0, sizeof(di->__pad4));
memset(&di->di_reserved, 0, sizeof(di->di_reserved));
gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode));
switch(ip->i_inode.i_mode & S_IFMT) {
case S_IFDIR:
gfs2_init_dir(dibh, dip);
break;
case S_IFLNK:
memcpy(dibh->b_data + sizeof(struct gfs2_dinode), symname, ip->i_inode.i_size);
break;
}
set_buffer_uptodate(dibh);
brelse(dibh);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
steven whitehouse | steven whitehouse | 224 | 100.00% | 6 | 100.00% |
| Total | 224 | 100.00% | 6 | 100.00% |
/**
* gfs2_trans_da_blocks - Calculate number of blocks to link inode
* @dip: The directory we are linking into
* @da: The dir add information
* @nr_inodes: The number of inodes involved
*
* This calculate the number of blocks we need to reserve in a
* transaction to link @nr_inodes into a directory. In most cases
* @nr_inodes will be 2 (the directory plus the inode being linked in)
* but in case of rename, 4 may be required.
*
* Returns: Number of blocks
*/
static unsigned gfs2_trans_da_blks(const struct gfs2_inode *dip,
const struct gfs2_diradd *da,
unsigned nr_inodes)
{
return da->nr_blocks + gfs2_rg_blocks(dip, da->nr_blocks) +
(nr_inodes * RES_DINODE) + RES_QUOTA + RES_STATFS;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
steven whitehouse | steven whitehouse | 45 | 100.00% | 1 | 100.00% |
| Total | 45 | 100.00% | 1 | 100.00% |
static int link_dinode(struct gfs2_inode *dip, const struct qstr *name,
struct gfs2_inode *ip, struct gfs2_diradd *da)
{
struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
struct gfs2_alloc_parms ap = { .target = da->nr_blocks, };
int error;
if (da->nr_blocks) {
error = gfs2_quota_lock_check(dip, &ap);
if (error)
goto fail_quota_locks;
error = gfs2_inplace_reserve(dip, &ap);
if (error)
goto fail_quota_locks;
error = gfs2_trans_begin(sdp, gfs2_trans_da_blks(dip, da, 2), 0);
if (error)
goto fail_ipreserv;
} else {
error = gfs2_trans_begin(sdp, RES_LEAF + 2 * RES_DINODE, 0);
if (error)
goto fail_quota_locks;
}
error = gfs2_dir_add(&dip->i_inode, name, ip, da);
gfs2_trans_end(sdp);
fail_ipreserv:
gfs2_inplace_release(dip);
fail_quota_locks:
gfs2_quota_unlock(dip);
return error;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
steven whitehouse | steven whitehouse | 182 | 97.85% | 8 | 80.00% |
abhijith das | abhijith das | 3 | 1.61% | 1 | 10.00% |
robert s. peterson | robert s. peterson | 1 | 0.54% | 1 | 10.00% |
| Total | 186 | 100.00% | 10 | 100.00% |
static int gfs2_initxattrs(struct inode *inode, const struct xattr *xattr_array,
void *fs_info)
{
const struct xattr *xattr;
int err = 0;
for (xattr = xattr_array; xattr->name != NULL; xattr++) {
err = __gfs2_xattr_set(inode, xattr->name, xattr->value,
xattr->value_len, 0,
GFS2_EATYPE_SECURITY);
if (err < 0)
break;
}
return err;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
mimi zohar | mimi zohar | 47 | 57.32% | 1 | 33.33% |
steven whitehouse | steven whitehouse | 34 | 41.46% | 1 | 33.33% |
h hartley sweeten | h hartley sweeten | 1 | 1.22% | 1 | 33.33% |
| Total | 82 | 100.00% | 3 | 100.00% |
/**
* gfs2_create_inode - Create a new inode
* @dir: The parent directory
* @dentry: The new dentry
* @file: If non-NULL, the file which is being opened
* @mode: The permissions on the new inode
* @dev: For device nodes, this is the device number
* @symname: For symlinks, this is the link destination
* @size: The initial size of the inode (ignored for directories)
*
* Returns: 0 on success, or error code
*/
static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
struct file *file,
umode_t mode, dev_t dev, const char *symname,
unsigned int size, int excl, int *opened)
{
const struct qstr *name = &dentry->d_name;
struct posix_acl *default_acl, *acl;
struct gfs2_holder ghs[2];
struct inode *inode = NULL;
struct gfs2_inode *dip = GFS2_I(dir), *ip;
struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
struct gfs2_glock *io_gl = NULL;
int error, free_vfs_inode = 1;
u32 aflags = 0;
unsigned blocks = 1;
struct gfs2_diradd da = { .bh = NULL, .save_loc = 1, };
if (!name->len || name->len > GFS2_FNAMESIZE)
return -ENAMETOOLONG;
error = gfs2_rsqa_alloc(dip);
if (error)
return error;
error = gfs2_rindex_update(sdp);
if (error)
return error;
error = gfs2_glock_nq_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
if (error)
goto fail;
error = create_ok(dip, name, mode);
if (error)
goto fail_gunlock;
inode = gfs2_dir_search(dir, &dentry->d_name, !S_ISREG(mode) || excl);
error = PTR_ERR(inode);
if (!IS_ERR(inode)) {
if (S_ISDIR(inode->i_mode)) {
iput(inode);
inode = ERR_PTR(-EISDIR);
goto fail_gunlock;
}
d_instantiate(dentry, inode);
error = 0;
if (file) {
if (S_ISREG(inode->i_mode))
error = finish_open(file, dentry, gfs2_open_common, opened);
else
error = finish_no_open(file, NULL);
}
gfs2_glock_dq_uninit(ghs);
return error;
} else if (error != -ENOENT)