X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=fs%2Fgfs2%2Finode.c;h=7cee695fa44163f378293945514b1e4a9bbfd084;hb=c1e7abbc7afc97367cd77c8f2895c2169a8f9c87;hp=cd1de61bff2f6857cce05d5fc6bc0aa835e0b0e9;hpb=c9fd43078f5007c6ca6b3a9cd04c51a8f0e44a20;p=safe%2Fjmp%2Flinux-2.6 diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index cd1de61..7cee695 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -1,10 +1,10 @@ /* * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. - * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * Copyright (C) 2004-2008 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 v.2. + * of the GNU General Public License version 2. */ #include @@ -15,10 +15,12 @@ #include #include #include -#include +#include +#include +#include +#include #include "gfs2.h" -#include "lm_interface.h" #include "incore.h" #include "acl.h" #include "bmap.h" @@ -30,416 +32,331 @@ #include "log.h" #include "meta_io.h" #include "ops_address.h" -#include "ops_file.h" #include "ops_inode.h" #include "quota.h" #include "rgrp.h" #include "trans.h" -#include "unlinked.h" #include "util.h" -/** - * inode_attr_in - Copy attributes from the dinode into the VFS inode - * @ip: The GFS2 inode (with embedded disk inode data) - * @inode: The Linux VFS inode - * - */ +struct gfs2_inum_range_host { + u64 ir_start; + u64 ir_length; +}; -static void inode_attr_in(struct gfs2_inode *ip, struct inode *inode) +static int iget_test(struct inode *inode, void *opaque) { - inode->i_ino = ip->i_num.no_formal_ino; + struct gfs2_inode *ip = GFS2_I(inode); + u64 *no_addr = opaque; - switch (ip->i_di.di_mode & S_IFMT) { - case S_IFBLK: - case S_IFCHR: - inode->i_rdev = MKDEV(ip->i_di.di_major, ip->i_di.di_minor); - break; - default: - inode->i_rdev = 0; - break; - }; - - inode->i_mode = ip->i_di.di_mode; - inode->i_nlink = ip->i_di.di_nlink; - inode->i_uid = ip->i_di.di_uid; - inode->i_gid = ip->i_di.di_gid; - i_size_write(inode, ip->i_di.di_size); - inode->i_atime.tv_sec = ip->i_di.di_atime; - inode->i_mtime.tv_sec = ip->i_di.di_mtime; - inode->i_ctime.tv_sec = ip->i_di.di_ctime; - inode->i_atime.tv_nsec = 0; - inode->i_mtime.tv_nsec = 0; - inode->i_ctime.tv_nsec = 0; - inode->i_blksize = PAGE_SIZE; - inode->i_blocks = ip->i_di.di_blocks << - (ip->i_sbd->sd_sb.sb_bsize_shift - GFS2_BASIC_BLOCK_SHIFT); - - if (ip->i_di.di_flags & GFS2_DIF_IMMUTABLE) - inode->i_flags |= S_IMMUTABLE; - else - inode->i_flags &= ~S_IMMUTABLE; + if (ip->i_no_addr == *no_addr && test_bit(GIF_USER, &ip->i_flags)) + return 1; - if (ip->i_di.di_flags & GFS2_DIF_APPENDONLY) - inode->i_flags |= S_APPEND; - else - inode->i_flags &= ~S_APPEND; + return 0; } -/** - * gfs2_inode_attr_in - Copy attributes from the dinode into the VFS inode - * @ip: The GFS2 inode (with embedded disk inode data) - * - */ - -void gfs2_inode_attr_in(struct gfs2_inode *ip) +static int iget_set(struct inode *inode, void *opaque) { - struct inode *inode; + struct gfs2_inode *ip = GFS2_I(inode); + u64 *no_addr = opaque; - inode = gfs2_ip2v_lookup(ip); - if (inode) { - inode_attr_in(ip, inode); - iput(inode); - } + inode->i_ino = (unsigned long)*no_addr; + ip->i_no_addr = *no_addr; + set_bit(GIF_USER, &ip->i_flags); + return 0; } -/** - * gfs2_inode_attr_out - Copy attributes from VFS inode into the dinode - * @ip: The GFS2 inode - * - * Only copy out the attributes that we want the VFS layer - * to be able to modify. - */ - -void gfs2_inode_attr_out(struct gfs2_inode *ip) +struct inode *gfs2_ilookup(struct super_block *sb, u64 no_addr) { - struct inode *inode = ip->i_vnode; - - gfs2_assert_withdraw(ip->i_sbd, - (ip->i_di.di_mode & S_IFMT) == (inode->i_mode & S_IFMT)); - ip->i_di.di_mode = inode->i_mode; - ip->i_di.di_uid = inode->i_uid; - ip->i_di.di_gid = inode->i_gid; - ip->i_di.di_atime = inode->i_atime.tv_sec; - ip->i_di.di_mtime = inode->i_mtime.tv_sec; - ip->i_di.di_ctime = inode->i_ctime.tv_sec; + unsigned long hash = (unsigned long)no_addr; + return ilookup5(sb, hash, iget_test, &no_addr); } -/** - * gfs2_ip2v_lookup - Get the struct inode for a struct gfs2_inode - * @ip: the struct gfs2_inode to get the struct inode for - * - * Returns: A VFS inode, or NULL if none - */ - -struct inode *gfs2_ip2v_lookup(struct gfs2_inode *ip) +static struct inode *gfs2_iget(struct super_block *sb, u64 no_addr) { - struct inode *inode = NULL; - - gfs2_assert_warn(ip->i_sbd, test_bit(GIF_MIN_INIT, &ip->i_flags)); - - spin_lock(&ip->i_spin); - if (ip->i_vnode) - inode = igrab(ip->i_vnode); - spin_unlock(&ip->i_spin); - - return inode; + unsigned long hash = (unsigned long)no_addr; + return iget5_locked(sb, hash, iget_test, iget_set, &no_addr); } -/** - * gfs2_ip2v - Get/Create a struct inode for a struct gfs2_inode - * @ip: the struct gfs2_inode to get the struct inode for - * - * Returns: A VFS inode, or NULL if no mem - */ +struct gfs2_skip_data { + u64 no_addr; + int skipped; +}; -struct inode *gfs2_ip2v(struct gfs2_inode *ip) +static int iget_skip_test(struct inode *inode, void *opaque) { - struct inode *inode, *tmp; - - inode = gfs2_ip2v_lookup(ip); - if (inode) - return inode; - - tmp = new_inode(ip->i_sbd->sd_vfs); - if (!tmp) - return NULL; - - inode_attr_in(ip, tmp); - - if (S_ISREG(ip->i_di.di_mode)) { - tmp->i_op = &gfs2_file_iops; - tmp->i_fop = &gfs2_file_fops; - tmp->i_mapping->a_ops = &gfs2_file_aops; - } else if (S_ISDIR(ip->i_di.di_mode)) { - tmp->i_op = &gfs2_dir_iops; - tmp->i_fop = &gfs2_dir_fops; - } else if (S_ISLNK(ip->i_di.di_mode)) { - tmp->i_op = &gfs2_symlink_iops; - } else { - tmp->i_op = &gfs2_dev_iops; - init_special_inode(tmp, tmp->i_mode, tmp->i_rdev); - } - - tmp->u.generic_ip = NULL; - - for (;;) { - spin_lock(&ip->i_spin); - if (!ip->i_vnode) - break; - inode = igrab(ip->i_vnode); - spin_unlock(&ip->i_spin); + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_skip_data *data = opaque; - if (inode) { - iput(tmp); - return inode; + if (ip->i_no_addr == data->no_addr && test_bit(GIF_USER, &ip->i_flags)){ + if (inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE)){ + data->skipped = 1; + return 0; } - yield(); + return 1; } - - inode = tmp; - - gfs2_inode_hold(ip); - ip->i_vnode = inode; - inode->u.generic_ip = ip; - - spin_unlock(&ip->i_spin); - - insert_inode_hash(inode); - - return inode; + return 0; } -static int iget_test(struct inode *inode, void *opaque) +static int iget_skip_set(struct inode *inode, void *opaque) { - struct gfs2_inode *ip = inode->u.generic_ip; - struct gfs2_inum *inum = (struct gfs2_inum *)opaque; + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_skip_data *data = opaque; - if (ip && ip->i_num.no_addr == inum->no_addr) + if (data->skipped) return 1; - + inode->i_ino = (unsigned long)(data->no_addr); + ip->i_no_addr = data->no_addr; + set_bit(GIF_USER, &ip->i_flags); return 0; } -struct inode *gfs2_iget(struct super_block *sb, struct gfs2_inum *inum) +static struct inode *gfs2_iget_skip(struct super_block *sb, + u64 no_addr) { - return ilookup5(sb, (unsigned long)inum->no_formal_ino, - iget_test, inum); -} + struct gfs2_skip_data data; + unsigned long hash = (unsigned long)no_addr; -void gfs2_inode_min_init(struct gfs2_inode *ip, unsigned int type) -{ - spin_lock(&ip->i_spin); - if (!test_and_set_bit(GIF_MIN_INIT, &ip->i_flags)) { - ip->i_di.di_nlink = 1; - ip->i_di.di_mode = DT2IF(type); - } - spin_unlock(&ip->i_spin); + data.no_addr = no_addr; + data.skipped = 0; + return iget5_locked(sb, hash, iget_skip_test, iget_skip_set, &data); } /** - * gfs2_inode_refresh - Refresh the incore copy of the dinode - * @ip: The GFS2 inode + * GFS2 lookup code fills in vfs inode contents based on info obtained + * from directory entry inside gfs2_inode_lookup(). This has caused issues + * with NFS code path since its get_dentry routine doesn't have the relevant + * directory entry when gfs2_inode_lookup() is invoked. Part of the code + * segment inside gfs2_inode_lookup code needs to get moved around. * - * Returns: errno - */ + * Clean up I_LOCK and I_NEW as well. + **/ -int gfs2_inode_refresh(struct gfs2_inode *ip) +void gfs2_set_iop(struct inode *inode) { - struct buffer_head *dibh; - int error; - - error = gfs2_meta_inode_buffer(ip, &dibh); - if (error) - return error; + struct gfs2_sbd *sdp = GFS2_SB(inode); + umode_t mode = inode->i_mode; - if (gfs2_metatype_check(ip->i_sbd, dibh, GFS2_METATYPE_DI)) { - brelse(dibh); - return -EIO; - } - - spin_lock(&ip->i_spin); - gfs2_dinode_in(&ip->i_di, dibh->b_data); - set_bit(GIF_MIN_INIT, &ip->i_flags); - spin_unlock(&ip->i_spin); - - brelse(dibh); - - if (ip->i_num.no_addr != ip->i_di.di_num.no_addr) { - if (gfs2_consist_inode(ip)) - gfs2_dinode_print(&ip->i_di); - return -EIO; + if (S_ISREG(mode)) { + inode->i_op = &gfs2_file_iops; + if (sdp->sd_args.ar_localflocks) + 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 (sdp->sd_args.ar_localflocks) + 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); } - if (ip->i_num.no_formal_ino != ip->i_di.di_num.no_formal_ino) - return -ESTALE; - ip->i_vn = ip->i_gl->gl_vn; - - return 0; + unlock_new_inode(inode); } /** - * inode_create - create a struct gfs2_inode - * @i_gl: The glock covering the inode - * @inum: The inode number - * @io_gl: the iopen glock to acquire/hold (using holder in new gfs2_inode) - * @io_state: the state the iopen glock should be acquired in - * @ipp: pointer to put the returned inode in + * gfs2_inode_lookup - Lookup an inode + * @sb: The super block + * @no_addr: The inode number + * @type: The type of the inode + * @skip_freeing: set this not return an inode if it is currently being freed. * - * Returns: errno + * Returns: A VFS inode, or an error */ -static int inode_create(struct gfs2_glock *i_gl, const struct gfs2_inum *inum, - struct gfs2_glock *io_gl, unsigned int io_state, - struct gfs2_inode **ipp) +struct inode *gfs2_inode_lookup(struct super_block *sb, + unsigned int type, + u64 no_addr, + u64 no_formal_ino, int skip_freeing) { - struct gfs2_sbd *sdp = i_gl->gl_sbd; + struct inode *inode; struct gfs2_inode *ip; - int error = 0; + struct gfs2_glock *io_gl; + int error; - ip = kmem_cache_alloc(gfs2_inode_cachep, GFP_KERNEL); - if (!ip) - return -ENOMEM; - memset(ip, 0, sizeof(struct gfs2_inode)); + if (skip_freeing) + inode = gfs2_iget_skip(sb, no_addr); + else + inode = gfs2_iget(sb, no_addr); + ip = GFS2_I(inode); - ip->i_num = *inum; + if (!inode) + return ERR_PTR(-ENOBUFS); - atomic_set(&ip->i_count, 1); + if (inode->i_state & I_NEW) { + struct gfs2_sbd *sdp = GFS2_SB(inode); + ip->i_no_formal_ino = no_formal_ino; - ip->i_vn = i_gl->gl_vn - 1; + 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; - ip->i_gl = i_gl; - ip->i_sbd = sdp; + error = gfs2_glock_get(sdp, no_addr, &gfs2_iopen_glops, CREATE, &io_gl); + if (unlikely(error)) + goto fail_put; - spin_lock_init(&ip->i_spin); - init_rwsem(&ip->i_rw_mutex); + 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_iopen; + ip->i_iopen_gh.gh_gl->gl_object = ip; - ip->i_greedy = gfs2_tune_get(sdp, gt_greedy_default); + gfs2_glock_put(io_gl); - error = gfs2_glock_nq_init(io_gl, - io_state, GL_LOCAL_EXCL | GL_EXACT, - &ip->i_iopen_gh); - if (error) - goto fail; - ip->i_iopen_gh.gh_owner = NULL; + if ((type == DT_UNKNOWN) && (no_formal_ino == 0)) + goto gfs2_nfsbypass; + + inode->i_mode = DT2IF(type); + + /* + * We must read the inode in order to work out its type in + * this case. Note that this doesn't happen often as we normally + * know the type beforehand. This code path only occurs during + * unlinked inode recovery (where it is safe to do this glock, + * which is not true in the general case). + */ + if (type == DT_UNKNOWN) { + struct gfs2_holder gh; + error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); + if (unlikely(error)) + goto fail_glock; + /* Inode is now uptodate */ + gfs2_glock_dq_uninit(&gh); + } - spin_lock(&io_gl->gl_spin); - gfs2_glock_hold(i_gl); - io_gl->gl_object = i_gl; - spin_unlock(&io_gl->gl_spin); + gfs2_set_iop(inode); + } - gfs2_glock_hold(i_gl); - i_gl->gl_object = ip; +gfs2_nfsbypass: + return inode; +fail_glock: + gfs2_glock_dq(&ip->i_iopen_gh); +fail_iopen: + gfs2_glock_put(io_gl); +fail_put: + ip->i_gl->gl_object = NULL; + gfs2_glock_put(ip->i_gl); +fail: + iget_failed(inode); + return ERR_PTR(error); +} - atomic_inc(&sdp->sd_inode_count); +static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf) +{ + struct gfs2_dinode_host *di = &ip->i_di; + const struct gfs2_dinode *str = buf; + struct timespec atime; + u16 height, depth; + + if (unlikely(ip->i_no_addr != be64_to_cpu(str->di_num.no_addr))) + goto corrupt; + ip->i_no_formal_ino = be64_to_cpu(str->di_num.no_formal_ino); + ip->i_inode.i_mode = be32_to_cpu(str->di_mode); + ip->i_inode.i_rdev = 0; + switch (ip->i_inode.i_mode & S_IFMT) { + case S_IFBLK: + case S_IFCHR: + ip->i_inode.i_rdev = MKDEV(be32_to_cpu(str->di_major), + be32_to_cpu(str->di_minor)); + break; + }; - *ipp = ip; + ip->i_inode.i_uid = be32_to_cpu(str->di_uid); + ip->i_inode.i_gid = be32_to_cpu(str->di_gid); + /* + * We will need to review setting the nlink count here in the + * light of the forthcoming ro bind mount work. This is a reminder + * to do that. + */ + ip->i_inode.i_nlink = be32_to_cpu(str->di_nlink); + di->di_size = be64_to_cpu(str->di_size); + i_size_write(&ip->i_inode, di->di_size); + gfs2_set_inode_blocks(&ip->i_inode, be64_to_cpu(str->di_blocks)); + atime.tv_sec = be64_to_cpu(str->di_atime); + atime.tv_nsec = be32_to_cpu(str->di_atime_nsec); + if (timespec_compare(&ip->i_inode.i_atime, &atime) < 0) + ip->i_inode.i_atime = atime; + ip->i_inode.i_mtime.tv_sec = be64_to_cpu(str->di_mtime); + ip->i_inode.i_mtime.tv_nsec = be32_to_cpu(str->di_mtime_nsec); + ip->i_inode.i_ctime.tv_sec = be64_to_cpu(str->di_ctime); + ip->i_inode.i_ctime.tv_nsec = be32_to_cpu(str->di_ctime_nsec); + + ip->i_goal = be64_to_cpu(str->di_goal_meta); + di->di_generation = be64_to_cpu(str->di_generation); + + di->di_flags = be32_to_cpu(str->di_flags); + gfs2_set_inode_flags(&ip->i_inode); + height = be16_to_cpu(str->di_height); + if (unlikely(height > GFS2_MAX_META_HEIGHT)) + goto corrupt; + ip->i_height = (u8)height; + + depth = be16_to_cpu(str->di_depth); + if (unlikely(depth > GFS2_DIR_MAX_DEPTH)) + goto corrupt; + ip->i_depth = (u8)depth; + di->di_entries = be32_to_cpu(str->di_entries); + + di->di_eattr = be64_to_cpu(str->di_eattr); + if (S_ISREG(ip->i_inode.i_mode)) + gfs2_set_aops(&ip->i_inode); return 0; - - fail: - gfs2_meta_cache_flush(ip); - kmem_cache_free(gfs2_inode_cachep, ip); - *ipp = NULL; - - return error; +corrupt: + if (gfs2_consist_inode(ip)) + gfs2_dinode_print(ip); + return -EIO; } /** - * gfs2_inode_get - Create or get a reference on an inode - * @i_gl: The glock covering the inode - * @inum: The inode number - * @create: - * @ipp: pointer to put the returned inode in + * gfs2_inode_refresh - Refresh the incore copy of the dinode + * @ip: The GFS2 inode * * Returns: errno */ -int gfs2_inode_get(struct gfs2_glock *i_gl, const struct gfs2_inum *inum, - int create, struct gfs2_inode **ipp) +int gfs2_inode_refresh(struct gfs2_inode *ip) { - struct gfs2_sbd *sdp = i_gl->gl_sbd; - struct gfs2_glock *io_gl; - int error = 0; - - gfs2_glmutex_lock(i_gl); - - *ipp = i_gl->gl_object; - if (*ipp) { - error = -ESTALE; - if ((*ipp)->i_num.no_formal_ino != inum->no_formal_ino) - goto out; - atomic_inc(&(*ipp)->i_count); - error = 0; - goto out; - } + struct buffer_head *dibh; + int error; - if (!create) - goto out; + error = gfs2_meta_inode_buffer(ip, &dibh); + if (error) + return error; - error = gfs2_glock_get(sdp, inum->no_addr, &gfs2_iopen_glops, - CREATE, &io_gl); - if (!error) { - error = inode_create(i_gl, inum, io_gl, LM_ST_SHARED, ipp); - gfs2_glock_put(io_gl); + if (gfs2_metatype_check(GFS2_SB(&ip->i_inode), dibh, GFS2_METATYPE_DI)) { + brelse(dibh); + return -EIO; } - out: - gfs2_glmutex_unlock(i_gl); + error = gfs2_dinode_in(ip, dibh->b_data); + brelse(dibh); + clear_bit(GIF_INVALID, &ip->i_flags); return error; } -void gfs2_inode_hold(struct gfs2_inode *ip) -{ - gfs2_assert(ip->i_sbd, atomic_read(&ip->i_count) > 0); - atomic_inc(&ip->i_count); -} - -void gfs2_inode_put(struct gfs2_inode *ip) -{ - gfs2_assert(ip->i_sbd, atomic_read(&ip->i_count) > 0); - atomic_dec(&ip->i_count); -} - -void gfs2_inode_destroy(struct gfs2_inode *ip) -{ - struct gfs2_sbd *sdp = ip->i_sbd; - struct gfs2_glock *io_gl = ip->i_iopen_gh.gh_gl; - struct gfs2_glock *i_gl = ip->i_gl; - - gfs2_assert_warn(sdp, !atomic_read(&ip->i_count)); - gfs2_assert(sdp, io_gl->gl_object == i_gl); - - spin_lock(&io_gl->gl_spin); - io_gl->gl_object = NULL; - gfs2_glock_put(i_gl); - spin_unlock(&io_gl->gl_spin); - - gfs2_glock_dq_uninit(&ip->i_iopen_gh); - - gfs2_meta_cache_flush(ip); - kmem_cache_free(gfs2_inode_cachep, ip); - - i_gl->gl_object = NULL; - gfs2_glock_put(i_gl); - - atomic_dec(&sdp->sd_inode_count); -} - -static int dinode_dealloc(struct gfs2_inode *ip, struct gfs2_unlinked *ul) +int gfs2_dinode_dealloc(struct gfs2_inode *ip) { - struct gfs2_sbd *sdp = ip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_alloc *al; struct gfs2_rgrpd *rgd; int error; - if (ip->i_di.di_blocks != 1) { + if (gfs2_get_inode_blocks(&ip->i_inode) != 1) { if (gfs2_consist_inode(ip)) - gfs2_dinode_print(&ip->i_di); + gfs2_dinode_print(ip); return -EIO; } al = gfs2_alloc_get(ip); + if (!al) + return -ENOMEM; error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); if (error) @@ -449,7 +366,7 @@ static int dinode_dealloc(struct gfs2_inode *ip, struct gfs2_unlinked *ul) if (error) goto out_qs; - rgd = gfs2_blk2rgrpd(sdp, ip->i_num.no_addr); + rgd = gfs2_blk2rgrpd(sdp, ip->i_no_addr); if (!rgd) { gfs2_consist_inode(ip); error = -EIO; @@ -461,209 +378,29 @@ static int dinode_dealloc(struct gfs2_inode *ip, struct gfs2_unlinked *ul) if (error) goto out_rindex_relse; - error = gfs2_trans_begin(sdp, RES_RG_BIT + RES_UNLINKED + - RES_STATFS + RES_QUOTA, 1); + error = gfs2_trans_begin(sdp, RES_RG_BIT + RES_STATFS + RES_QUOTA, 1); if (error) goto out_rg_gunlock; - gfs2_trans_add_gl(ip->i_gl); + set_bit(GLF_DIRTY, &ip->i_gl->gl_flags); + set_bit(GLF_LFLUSH, &ip->i_gl->gl_flags); gfs2_free_di(rgd, ip); - error = gfs2_unlinked_ondisk_rm(sdp, ul); - gfs2_trans_end(sdp); clear_bit(GLF_STICKY, &ip->i_gl->gl_flags); - out_rg_gunlock: +out_rg_gunlock: gfs2_glock_dq_uninit(&al->al_rgd_gh); - - out_rindex_relse: +out_rindex_relse: gfs2_glock_dq_uninit(&al->al_ri_gh); - - out_qs: +out_qs: gfs2_quota_unhold(ip); - - out: +out: gfs2_alloc_put(ip); - - return error; -} - -/** - * inode_dealloc - Deallocate all on-disk blocks for an inode (dinode) - * @sdp: the filesystem - * @inum: the inode number to deallocate - * @io_gh: a holder for the iopen glock for this inode - * - * Returns: errno - */ - -static int inode_dealloc(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul, - struct gfs2_holder *io_gh) -{ - struct gfs2_inode *ip; - struct gfs2_holder i_gh; - int error; - - error = gfs2_glock_nq_num(sdp, - ul->ul_ut.ut_inum.no_addr, &gfs2_inode_glops, - LM_ST_EXCLUSIVE, 0, &i_gh); - if (error) - return error; - - /* We reacquire the iopen lock here to avoid a race with the NFS server - calling gfs2_read_inode() with the inode number of a inode we're in - the process of deallocating. And we can't keep our hold on the lock - from inode_dealloc_init() for deadlock reasons. */ - - gfs2_holder_reinit(LM_ST_EXCLUSIVE, LM_FLAG_TRY, io_gh); - error = gfs2_glock_nq(io_gh); - switch (error) { - case 0: - break; - case GLR_TRYFAILED: - error = 1; - default: - goto out; - } - - gfs2_assert_warn(sdp, !i_gh.gh_gl->gl_object); - error = inode_create(i_gh.gh_gl, &ul->ul_ut.ut_inum, io_gh->gh_gl, - LM_ST_EXCLUSIVE, &ip); - - gfs2_glock_dq(io_gh); - - if (error) - goto out; - - error = gfs2_inode_refresh(ip); - if (error) - goto out_iput; - - if (ip->i_di.di_nlink) { - if (gfs2_consist_inode(ip)) - gfs2_dinode_print(&ip->i_di); - error = -EIO; - goto out_iput; - } - - if (S_ISDIR(ip->i_di.di_mode) && - (ip->i_di.di_flags & GFS2_DIF_EXHASH)) { - error = gfs2_dir_exhash_dealloc(ip); - if (error) - goto out_iput; - } - - if (ip->i_di.di_eattr) { - error = gfs2_ea_dealloc(ip); - if (error) - goto out_iput; - } - - if (!gfs2_is_stuffed(ip)) { - error = gfs2_file_dealloc(ip); - if (error) - goto out_iput; - } - - error = dinode_dealloc(ip, ul); - if (error) - goto out_iput; - - out_iput: - gfs2_glmutex_lock(i_gh.gh_gl); - gfs2_inode_put(ip); - gfs2_inode_destroy(ip); - gfs2_glmutex_unlock(i_gh.gh_gl); - - out: - gfs2_glock_dq_uninit(&i_gh); - - return error; -} - -/** - * try_inode_dealloc - Try to deallocate an inode and all its blocks - * @sdp: the filesystem - * - * Returns: 0 on success, -errno on error, 1 on busy (inode open) - */ - -static int try_inode_dealloc(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul) -{ - struct gfs2_holder io_gh; - int error = 0; - - gfs2_try_toss_inode(sdp, &ul->ul_ut.ut_inum); - - error = gfs2_glock_nq_num(sdp, - ul->ul_ut.ut_inum.no_addr, &gfs2_iopen_glops, - LM_ST_EXCLUSIVE, LM_FLAG_TRY_1CB, &io_gh); - switch (error) { - case 0: - break; - case GLR_TRYFAILED: - return 1; - default: - return error; - } - - gfs2_glock_dq(&io_gh); - error = inode_dealloc(sdp, ul, &io_gh); - gfs2_holder_uninit(&io_gh); - - return error; -} - -static int inode_dealloc_uninit(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul) -{ - struct gfs2_rgrpd *rgd; - struct gfs2_holder ri_gh, rgd_gh; - int error; - - error = gfs2_rindex_hold(sdp, &ri_gh); - if (error) - return error; - - rgd = gfs2_blk2rgrpd(sdp, ul->ul_ut.ut_inum.no_addr); - if (!rgd) { - gfs2_consist(sdp); - error = -EIO; - goto out; - } - - error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, &rgd_gh); - if (error) - goto out; - - error = gfs2_trans_begin(sdp, - RES_RG_BIT + RES_UNLINKED + RES_STATFS, - 0); - if (error) - goto out_gunlock; - - gfs2_free_uninit_di(rgd, ul->ul_ut.ut_inum.no_addr); - gfs2_unlinked_ondisk_rm(sdp, ul); - - gfs2_trans_end(sdp); - - out_gunlock: - gfs2_glock_dq_uninit(&rgd_gh); - out: - gfs2_glock_dq_uninit(&ri_gh); - return error; } -int gfs2_inode_dealloc(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul) -{ - if (ul->ul_ut.ut_flags & GFS2_UTF_UNINIT) - return inode_dealloc_uninit(sdp, ul); - else - return try_inode_dealloc(sdp, ul); -} - /** * gfs2_change_nlink - Change nlink count on inode * @ip: The GFS2 inode @@ -671,20 +408,20 @@ int gfs2_inode_dealloc(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul) * * Returns: errno */ - int gfs2_change_nlink(struct gfs2_inode *ip, int diff) { struct buffer_head *dibh; - uint32_t nlink; + u32 nlink; int error; - nlink = ip->i_di.di_nlink + diff; + BUG_ON(diff != 1 && diff != -1); + nlink = ip->i_inode.i_nlink + diff; /* If we are reducing the nlink count, but the new value ends up being bigger than the old one, we must have underflowed. */ - if (diff < 0 && nlink > ip->i_di.di_nlink) { + if (diff < 0 && nlink > ip->i_inode.i_nlink) { if (gfs2_consist_inode(ip)) - gfs2_dinode_print(&ip->i_di); + gfs2_dinode_print(ip); return -EIO; } @@ -692,16 +429,42 @@ int gfs2_change_nlink(struct gfs2_inode *ip, int diff) if (error) return error; - ip->i_di.di_nlink = nlink; - ip->i_di.di_ctime = get_seconds(); + if (diff > 0) + inc_nlink(&ip->i_inode); + else + drop_nlink(&ip->i_inode); + + ip->i_inode.i_ctime = CURRENT_TIME; gfs2_trans_add_bh(ip->i_gl, dibh, 1); - gfs2_dinode_out(&ip->i_di, dibh->b_data); + gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); + mark_inode_dirty(&ip->i_inode); - return 0; + if (ip->i_inode.i_nlink == 0) + gfs2_unlink_di(&ip->i_inode); /* mark inode unlinked */ + + return error; +} + +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; } + /** * gfs2_lookupi - Look up a filename in a directory and return its inode * @d_gh: An initialized holder for the directory glock @@ -709,79 +472,79 @@ int gfs2_change_nlink(struct gfs2_inode *ip, int diff) * @is_root: If 1, ignore the caller's permissions * @i_gh: An uninitialized holder for the new inode glock * - * There will always be a vnode (Linux VFS inode) for the d_gh inode unless - * @is_root is true. + * 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 */ -int gfs2_lookupi(struct inode *dir, struct qstr *name, int is_root, - struct inode **inodep) +struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name, + int is_root) { struct super_block *sb = dir->i_sb; - struct gfs2_inode *ipp; - struct gfs2_inode *dip = dir->u.generic_ip; - struct gfs2_sbd *sdp = dip->i_sbd; + struct gfs2_inode *dip = GFS2_I(dir); struct gfs2_holder d_gh; - struct gfs2_inum inum; - unsigned int type; - struct gfs2_glock *gl; int error = 0; - - *inodep = NULL; + struct inode *inode = NULL; + int unlock = 0; if (!name->len || name->len > GFS2_FNAMESIZE) - return -ENAMETOOLONG; + return ERR_PTR(-ENAMETOOLONG); - if (gfs2_filecmp(name, ".", 1) || - (gfs2_filecmp(name, "..", 2) && dir == sb->s_root->d_inode)) { - gfs2_inode_hold(dip); - ipp = dip; - goto done; + if ((name->len == 1 && memcmp(name->name, ".", 1) == 0) || + (name->len == 2 && memcmp(name->name, "..", 2) == 0 && + dir == sb->s_root->d_inode)) { + igrab(dir); + return dir; } - error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh); - if (error) - return error; + 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); + unlock = 1; + } if (!is_root) { - error = gfs2_repermission(dip->i_vnode, MAY_EXEC, NULL); + error = gfs2_permission(dir, MAY_EXEC); if (error) goto out; } - error = gfs2_dir_search(dip, name, &inum, &type); - if (error) - goto out; + inode = gfs2_dir_search(dir, name); + if (IS_ERR(inode)) + error = PTR_ERR(inode); +out: + if (unlock) + gfs2_glock_dq_uninit(&d_gh); + if (error == -ENOENT) + return NULL; + return inode ? inode : ERR_PTR(error); +} - error = gfs2_glock_get(sdp, inum.no_addr, &gfs2_inode_glops, - CREATE, &gl); - if (error) - goto out; +static void gfs2_inum_range_in(struct gfs2_inum_range_host *ir, const void *buf) +{ + const struct gfs2_inum_range *str = buf; - error = gfs2_inode_get(gl, &inum, CREATE, &ipp); - if (!error) - gfs2_inode_min_init(ipp, type); + ir->ir_start = be64_to_cpu(str->ir_start); + ir->ir_length = be64_to_cpu(str->ir_length); +} - gfs2_glock_put(gl); +static void gfs2_inum_range_out(const struct gfs2_inum_range_host *ir, void *buf) +{ + struct gfs2_inum_range *str = buf; -out: - gfs2_glock_dq_uninit(&d_gh); -done: - if (error == 0) { - *inodep = gfs2_ip2v(ipp); - if (!*inodep) - error = -ENOMEM; - gfs2_inode_put(ipp); - } - return error; + str->ir_start = cpu_to_be64(ir->ir_start); + str->ir_length = cpu_to_be64(ir->ir_length); } -static int pick_formal_ino_1(struct gfs2_sbd *sdp, uint64_t *formal_ino) +static int pick_formal_ino_1(struct gfs2_sbd *sdp, u64 *formal_ino) { - struct gfs2_inode *ip = sdp->sd_ir_inode->u.generic_ip; + struct gfs2_inode *ip = GFS2_I(sdp->sd_ir_inode); struct buffer_head *bh; - struct gfs2_inum_range ir; + struct gfs2_inum_range_host ir; int error; error = gfs2_trans_begin(sdp, RES_DINODE, 0); @@ -818,13 +581,13 @@ static int pick_formal_ino_1(struct gfs2_sbd *sdp, uint64_t *formal_ino) return 1; } -static int pick_formal_ino_2(struct gfs2_sbd *sdp, uint64_t *formal_ino) +static int pick_formal_ino_2(struct gfs2_sbd *sdp, u64 *formal_ino) { - struct gfs2_inode *ip = sdp->sd_ir_inode->u.generic_ip; - struct gfs2_inode *m_ip = sdp->sd_inum_inode->u.generic_ip; + struct gfs2_inode *ip = GFS2_I(sdp->sd_ir_inode); + struct gfs2_inode *m_ip = GFS2_I(sdp->sd_inum_inode); struct gfs2_holder gh; struct buffer_head *bh; - struct gfs2_inum_range ir; + struct gfs2_inum_range_host ir; int error; error = gfs2_glock_nq_init(m_ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); @@ -839,27 +602,28 @@ static int pick_formal_ino_2(struct gfs2_sbd *sdp, uint64_t *formal_ino) error = gfs2_meta_inode_buffer(ip, &bh); if (error) goto out_end_trans; - + gfs2_inum_range_in(&ir, bh->b_data + sizeof(struct gfs2_dinode)); if (!ir.ir_length) { struct buffer_head *m_bh; - uint64_t x, y; + u64 x, y; + __be64 z; error = gfs2_meta_inode_buffer(m_ip, &m_bh); if (error) goto out_brelse; - x = *(uint64_t *)(m_bh->b_data + sizeof(struct gfs2_dinode)); - x = y = be64_to_cpu(x); + z = *(__be64 *)(m_bh->b_data + sizeof(struct gfs2_dinode)); + x = y = be64_to_cpu(z); ir.ir_start = x; ir.ir_length = GFS2_INUM_QUANTUM; x += GFS2_INUM_QUANTUM; if (x < y) gfs2_consist_inode(m_ip); - x = cpu_to_be64(x); + z = cpu_to_be64(x); gfs2_trans_add_bh(m_ip->i_gl, m_bh, 1); - *(uint64_t *)(m_bh->b_data + sizeof(struct gfs2_dinode)) = x; + *(__be64 *)(m_bh->b_data + sizeof(struct gfs2_dinode)) = z; brelse(m_bh); } @@ -870,20 +634,17 @@ static int pick_formal_ino_2(struct gfs2_sbd *sdp, uint64_t *formal_ino) gfs2_trans_add_bh(ip->i_gl, bh, 1); gfs2_inum_range_out(&ir, bh->b_data + sizeof(struct gfs2_dinode)); - out_brelse: +out_brelse: brelse(bh); - - out_end_trans: +out_end_trans: mutex_unlock(&sdp->sd_inum_mutex); gfs2_trans_end(sdp); - - out: +out: gfs2_glock_dq_uninit(&gh); - return error; } -static int pick_formal_ino(struct gfs2_sbd *sdp, uint64_t *inum) +static int pick_formal_ino(struct gfs2_sbd *sdp, u64 *inum) { int error; @@ -905,20 +666,20 @@ static int pick_formal_ino(struct gfs2_sbd *sdp, uint64_t *inum) * Returns: errno */ -static int create_ok(struct gfs2_inode *dip, struct qstr *name, +static int create_ok(struct gfs2_inode *dip, const struct qstr *name, unsigned int mode) { int error; - error = gfs2_repermission(dip->i_vnode, MAY_WRITE | MAY_EXEC, NULL); + 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_di.di_nlink) + if (!dip->i_inode.i_nlink) return -EPERM; - error = gfs2_dir_search(dip, name, NULL, NULL); + error = gfs2_dir_check(&dip->i_inode, name, NULL); switch (error) { case -ENOENT: error = 0; @@ -929,9 +690,9 @@ static int create_ok(struct gfs2_inode *dip, struct qstr *name, return error; } - if (dip->i_di.di_entries == (uint32_t)-1) + if (dip->i_di.di_entries == (u32)-1) return -EFBIG; - if (S_ISDIR(mode) && dip->i_di.di_nlink == (uint32_t)-1) + if (S_ISDIR(mode) && dip->i_inode.i_nlink == (u32)-1) return -EMLINK; return 0; @@ -940,55 +701,49 @@ static int create_ok(struct gfs2_inode *dip, struct qstr *name, static void munge_mode_uid_gid(struct gfs2_inode *dip, unsigned int *mode, unsigned int *uid, unsigned int *gid) { - if (dip->i_sbd->sd_args.ar_suiddir && - (dip->i_di.di_mode & S_ISUID) && - dip->i_di.di_uid) { + if (GFS2_SB(&dip->i_inode)->sd_args.ar_suiddir && + (dip->i_inode.i_mode & S_ISUID) && dip->i_inode.i_uid) { if (S_ISDIR(*mode)) *mode |= S_ISUID; - else if (dip->i_di.di_uid != current->fsuid) + else if (dip->i_inode.i_uid != current->fsuid) *mode &= ~07111; - *uid = dip->i_di.di_uid; + *uid = dip->i_inode.i_uid; } else *uid = current->fsuid; - if (dip->i_di.di_mode & S_ISGID) { + if (dip->i_inode.i_mode & S_ISGID) { if (S_ISDIR(*mode)) *mode |= S_ISGID; - *gid = dip->i_di.di_gid; + *gid = dip->i_inode.i_gid; } else *gid = current->fsgid; } -static int alloc_dinode(struct gfs2_inode *dip, struct gfs2_unlinked *ul) +static int alloc_dinode(struct gfs2_inode *dip, u64 *no_addr, u64 *generation) { - struct gfs2_sbd *sdp = dip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); int error; - gfs2_alloc_get(dip); + if (gfs2_alloc_get(dip) == NULL) + return -ENOMEM; - dip->i_alloc.al_requested = RES_DINODE; + dip->i_alloc->al_requested = RES_DINODE; error = gfs2_inplace_reserve(dip); if (error) goto out; - error = gfs2_trans_begin(sdp, RES_RG_BIT + RES_UNLINKED + - RES_STATFS, 0); + error = gfs2_trans_begin(sdp, RES_RG_BIT + RES_STATFS, 0); if (error) goto out_ipreserv; - ul->ul_ut.ut_inum.no_addr = gfs2_alloc_di(dip); - - ul->ul_ut.ut_flags = GFS2_UTF_UNINIT; - error = gfs2_unlinked_ondisk_add(sdp, ul); + *no_addr = gfs2_alloc_di(dip, generation); gfs2_trans_end(sdp); - out_ipreserv: +out_ipreserv: gfs2_inplace_release(dip); - - out: +out: gfs2_alloc_put(dip); - return error; } @@ -1004,12 +759,14 @@ static int alloc_dinode(struct gfs2_inode *dip, struct gfs2_unlinked *ul) */ static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, - struct gfs2_inum *inum, unsigned int mode, - unsigned int uid, unsigned int gid) + const struct gfs2_inum_host *inum, unsigned int mode, + unsigned int uid, unsigned int gid, + const u64 *generation, dev_t dev, struct buffer_head **bhp) { - struct gfs2_sbd *sdp = dip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); struct gfs2_dinode *di; struct buffer_head *dibh; + struct timespec tv = CURRENT_TIME; dibh = gfs2_meta_new(gl, inum->no_addr); gfs2_trans_add_bh(gl, dibh, 1); @@ -1022,52 +779,55 @@ static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, di->di_mode = cpu_to_be32(mode); di->di_uid = cpu_to_be32(uid); di->di_gid = cpu_to_be32(gid); - di->di_nlink = cpu_to_be32(0); - di->di_size = cpu_to_be64(0); + di->di_nlink = 0; + di->di_size = 0; di->di_blocks = cpu_to_be64(1); - di->di_atime = di->di_mtime = di->di_ctime = cpu_to_be64(get_seconds()); - di->di_major = di->di_minor = cpu_to_be32(0); + di->di_atime = di->di_mtime = di->di_ctime = cpu_to_be64(tv.tv_sec); + di->di_major = cpu_to_be32(MAJOR(dev)); + di->di_minor = cpu_to_be32(MINOR(dev)); di->di_goal_meta = di->di_goal_data = cpu_to_be64(inum->no_addr); - di->__pad[0] = di->__pad[1] = 0; - di->di_flags = cpu_to_be32(0); + di->di_generation = cpu_to_be64(*generation); + di->di_flags = 0; if (S_ISREG(mode)) { if ((dip->i_di.di_flags & GFS2_DIF_INHERIT_JDATA) || gfs2_tune_get(sdp, gt_new_files_jdata)) di->di_flags |= cpu_to_be32(GFS2_DIF_JDATA); - if ((dip->i_di.di_flags & GFS2_DIF_INHERIT_DIRECTIO) || - gfs2_tune_get(sdp, gt_new_files_directio)) - di->di_flags |= cpu_to_be32(GFS2_DIF_DIRECTIO); } else if (S_ISDIR(mode)) { di->di_flags |= cpu_to_be32(dip->i_di.di_flags & - GFS2_DIF_INHERIT_DIRECTIO); - di->di_flags |= cpu_to_be32(dip->i_di.di_flags & GFS2_DIF_INHERIT_JDATA); } di->__pad1 = 0; - di->di_height = cpu_to_be32(0); + di->di_payload_format = cpu_to_be32(S_ISDIR(mode) ? GFS2_FORMAT_DE : 0); + di->di_height = 0; di->__pad2 = 0; di->__pad3 = 0; - di->di_depth = cpu_to_be16(0); - di->di_entries = cpu_to_be32(0); + di->di_depth = 0; + di->di_entries = 0; memset(&di->__pad4, 0, sizeof(di->__pad4)); - di->di_eattr = cpu_to_be64(0); + di->di_eattr = 0; + di->di_atime_nsec = cpu_to_be32(tv.tv_nsec); + di->di_mtime_nsec = cpu_to_be32(tv.tv_nsec); + di->di_ctime_nsec = cpu_to_be32(tv.tv_nsec); memset(&di->di_reserved, 0, sizeof(di->di_reserved)); + + set_buffer_uptodate(dibh); - brelse(dibh); + *bhp = dibh; } static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, - unsigned int mode, struct gfs2_unlinked *ul) + unsigned int mode, const struct gfs2_inum_host *inum, + const u64 *generation, dev_t dev, struct buffer_head **bhp) { - struct gfs2_sbd *sdp = dip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); unsigned int uid, gid; int error; munge_mode_uid_gid(dip, &mode, &uid, &gid); - - gfs2_alloc_get(dip); + if (!gfs2_alloc_get(dip)) + return -ENOMEM; error = gfs2_quota_lock(dip, uid, gid); if (error) @@ -1077,49 +837,43 @@ static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, if (error) goto out_quota; - error = gfs2_trans_begin(sdp, RES_DINODE + RES_UNLINKED + - RES_QUOTA, 0); + error = gfs2_trans_begin(sdp, RES_DINODE + RES_QUOTA, 0); if (error) goto out_quota; - ul->ul_ut.ut_flags = 0; - error = gfs2_unlinked_ondisk_munge(sdp, ul); - - init_dinode(dip, gl, &ul->ul_ut.ut_inum, - mode, uid, gid); - + init_dinode(dip, gl, inum, mode, uid, gid, generation, dev, bhp); gfs2_quota_change(dip, +1, uid, gid); - gfs2_trans_end(sdp); - out_quota: +out_quota: gfs2_quota_unlock(dip); - - out: +out: gfs2_alloc_put(dip); - return error; } -static int link_dinode(struct gfs2_inode *dip, struct qstr *name, - struct gfs2_inode *ip, struct gfs2_unlinked *ul) +static int link_dinode(struct gfs2_inode *dip, const struct qstr *name, + struct gfs2_inode *ip) { - struct gfs2_sbd *sdp = dip->i_sbd; + struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); struct gfs2_alloc *al; int alloc_required; struct buffer_head *dibh; int error; al = gfs2_alloc_get(dip); + if (!al) + return -ENOMEM; error = gfs2_quota_lock(dip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); if (error) goto fail; - error = gfs2_diradd_alloc_required(dip, name, &alloc_required); + error = alloc_required = gfs2_diradd_alloc_required(&dip->i_inode, name); + if (alloc_required < 0) + goto fail_quota_locks; if (alloc_required) { - error = gfs2_quota_check(dip, dip->i_di.di_uid, - dip->i_di.di_gid); + error = gfs2_quota_check(dip, dip->i_inode.i_uid, dip->i_inode.i_gid); if (error) goto fail_quota_locks; @@ -1129,56 +883,79 @@ static int link_dinode(struct gfs2_inode *dip, struct qstr *name, if (error) goto fail_quota_locks; - error = gfs2_trans_begin(sdp, - sdp->sd_max_dirres + - al->al_rgd->rd_ri.ri_length + - 2 * RES_DINODE + RES_UNLINKED + + 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 fail_ipreserv; } else { - error = gfs2_trans_begin(sdp, - RES_LEAF + - 2 * RES_DINODE + - RES_UNLINKED, 0); + error = gfs2_trans_begin(sdp, RES_LEAF + 2 * RES_DINODE, 0); if (error) goto fail_quota_locks; } - error = gfs2_dir_add(dip, name, &ip->i_num, IF2DT(ip->i_di.di_mode)); + error = gfs2_dir_add(&dip->i_inode, name, ip, IF2DT(ip->i_inode.i_mode)); if (error) goto fail_end_trans; error = gfs2_meta_inode_buffer(ip, &dibh); if (error) goto fail_end_trans; - ip->i_di.di_nlink = 1; + ip->i_inode.i_nlink = 1; gfs2_trans_add_bh(ip->i_gl, dibh, 1); - gfs2_dinode_out(&ip->i_di, dibh->b_data); + gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); - - error = gfs2_unlinked_ondisk_rm(sdp, ul); - if (error) - goto fail_end_trans; - return 0; - fail_end_trans: +fail_end_trans: gfs2_trans_end(sdp); - fail_ipreserv: - if (dip->i_alloc.al_rgd) +fail_ipreserv: + if (dip->i_alloc->al_rgd) gfs2_inplace_release(dip); - fail_quota_locks: +fail_quota_locks: gfs2_quota_unlock(dip); - fail: +fail: gfs2_alloc_put(dip); - return error; } +static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip) +{ + int err; + size_t len; + void *value; + char *name; + struct gfs2_ea_request er; + + err = security_inode_init_security(&ip->i_inode, &dip->i_inode, + &name, &value, &len); + + if (err) { + if (err == -EOPNOTSUPP) + return 0; + return err; + } + + memset(&er, 0, sizeof(struct gfs2_ea_request)); + + er.er_type = GFS2_EATYPE_SECURITY; + er.er_name = name; + er.er_data = value; + er.er_name_len = strlen(name); + er.er_data_len = len; + + err = gfs2_ea_set_i(ip, &er); + + kfree(value); + kfree(name); + + return err; +} + /** * gfs2_createi - Create a new inode * @ghs: An array of two holders @@ -1195,23 +972,21 @@ static int link_dinode(struct gfs2_inode *dip, struct qstr *name, * Returns: An inode */ -struct inode *gfs2_createi(struct gfs2_holder *ghs, struct qstr *name, - unsigned int mode) +struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name, + unsigned int mode, dev_t dev) { - struct inode *inode; + struct inode *inode = NULL; struct gfs2_inode *dip = ghs->gh_gl->gl_object; - struct gfs2_sbd *sdp = dip->i_sbd; - struct gfs2_unlinked *ul; - struct gfs2_inode *ip; + struct inode *dir = &dip->i_inode; + struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); + struct gfs2_inum_host inum = { .no_addr = 0, .no_formal_ino = 0 }; int error; + u64 generation; + struct buffer_head *bh = NULL; if (!name->len || name->len > GFS2_FNAMESIZE) return ERR_PTR(-ENAMETOOLONG); - error = gfs2_unlinked_get(sdp, &ul); - if (error) - return ERR_PTR(error); - gfs2_holder_reinit(LM_ST_EXCLUSIVE, 0, ghs); error = gfs2_glock_nq(ghs); if (error) @@ -1221,131 +996,62 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, struct qstr *name, if (error) goto fail_gunlock; - error = pick_formal_ino(sdp, &ul->ul_ut.ut_inum.no_formal_ino); + error = pick_formal_ino(sdp, &inum.no_formal_ino); if (error) goto fail_gunlock; - error = alloc_dinode(dip, ul); + error = alloc_dinode(dip, &inum.no_addr, &generation); if (error) goto fail_gunlock; - if (ul->ul_ut.ut_inum.no_addr < dip->i_num.no_addr) { - gfs2_glock_dq(ghs); - - error = gfs2_glock_nq_num(sdp, - ul->ul_ut.ut_inum.no_addr, - &gfs2_inode_glops, - LM_ST_EXCLUSIVE, GL_SKIP, - ghs + 1); - if (error) { - gfs2_unlinked_put(sdp, ul); - return ERR_PTR(error); - } - - gfs2_holder_reinit(LM_ST_EXCLUSIVE, 0, ghs); - error = gfs2_glock_nq(ghs); - if (error) { - gfs2_glock_dq_uninit(ghs + 1); - gfs2_unlinked_put(sdp, ul); - return ERR_PTR(error); - } - - error = create_ok(dip, name, mode); - if (error) - goto fail_gunlock2; - } else { - error = gfs2_glock_nq_num(sdp, - ul->ul_ut.ut_inum.no_addr, - &gfs2_inode_glops, - LM_ST_EXCLUSIVE, GL_SKIP, - ghs + 1); - if (error) - goto fail_gunlock; - } + error = gfs2_glock_nq_num(sdp, inum.no_addr, &gfs2_inode_glops, + LM_ST_EXCLUSIVE, GL_SKIP, ghs + 1); + if (error) + goto fail_gunlock; - error = make_dinode(dip, ghs[1].gh_gl, mode, ul); + error = make_dinode(dip, ghs[1].gh_gl, mode, &inum, &generation, dev, &bh); if (error) goto fail_gunlock2; - error = gfs2_inode_get(ghs[1].gh_gl, &ul->ul_ut.ut_inum, CREATE, &ip); - if (error) + inode = gfs2_inode_lookup(dir->i_sb, IF2DT(mode), + inum.no_addr, + inum.no_formal_ino, 0); + if (IS_ERR(inode)) goto fail_gunlock2; - error = gfs2_inode_refresh(ip); + error = gfs2_inode_refresh(GFS2_I(inode)); if (error) - goto fail_iput; + goto fail_gunlock2; - error = gfs2_acl_create(dip, ip); + error = gfs2_acl_create(dip, GFS2_I(inode)); if (error) - goto fail_iput; + goto fail_gunlock2; - error = link_dinode(dip, name, ip, ul); + error = gfs2_security_init(dip, GFS2_I(inode)); if (error) - goto fail_iput; + goto fail_gunlock2; - gfs2_unlinked_put(sdp, ul); + error = link_dinode(dip, name, GFS2_I(inode)); + if (error) + goto fail_gunlock2; - inode = gfs2_ip2v(ip); - gfs2_inode_put(ip); - if (!inode) - return ERR_PTR(-ENOMEM); + if (bh) + brelse(bh); return inode; - fail_iput: - gfs2_inode_put(ip); - - fail_gunlock2: +fail_gunlock2: gfs2_glock_dq_uninit(ghs + 1); - - fail_gunlock: + if (inode && !IS_ERR(inode)) + iput(inode); +fail_gunlock: gfs2_glock_dq(ghs); - - fail: - gfs2_unlinked_put(sdp, ul); - +fail: + if (bh) + brelse(bh); return ERR_PTR(error); } /** - * gfs2_unlinki - Unlink a file - * @dip: The inode of the directory - * @name: The name of the file to be unlinked - * @ip: The inode of the file to be removed - * - * Assumes Glocks on both dip and ip are held. - * - * Returns: errno - */ - -int gfs2_unlinki(struct gfs2_inode *dip, struct qstr *name, - struct gfs2_inode *ip, struct gfs2_unlinked *ul) -{ - struct gfs2_sbd *sdp = dip->i_sbd; - int error; - - error = gfs2_dir_del(dip, name); - if (error) - return error; - - error = gfs2_change_nlink(ip, -1); - if (error) - return error; - - /* If this inode is being unlinked from the directory structure, - we need to mark that in the log so that it isn't lost during - a crash. */ - - if (!ip->i_di.di_nlink) { - ul->ul_ut.ut_inum = ip->i_num; - error = gfs2_unlinked_ondisk_add(sdp, ul); - if (!error) - set_bit(GLF_STICKY, &ip->i_gl->gl_flags); - } - - return error; -} - -/** * gfs2_rmdiri - Remove a directory * @dip: The parent directory of the directory to be removed * @name: The name of the directory to be removed @@ -1356,16 +1062,15 @@ int gfs2_unlinki(struct gfs2_inode *dip, struct qstr *name, * Returns: errno */ -int gfs2_rmdiri(struct gfs2_inode *dip, struct qstr *name, - struct gfs2_inode *ip, struct gfs2_unlinked *ul) +int gfs2_rmdiri(struct gfs2_inode *dip, const struct qstr *name, + struct gfs2_inode *ip) { - struct gfs2_sbd *sdp = dip->i_sbd; struct qstr dotname; int error; if (ip->i_di.di_entries != 2) { if (gfs2_consist_inode(ip)) - gfs2_dinode_print(&ip->i_di); + gfs2_dinode_print(ip); return -EIO; } @@ -1377,30 +1082,24 @@ int gfs2_rmdiri(struct gfs2_inode *dip, struct qstr *name, if (error) return error; - dotname.len = 1; - dotname.name = "."; + gfs2_str2qstr(&dotname, "."); error = gfs2_dir_del(ip, &dotname); if (error) return error; - dotname.len = 2; - dotname.name = ".."; + gfs2_str2qstr(&dotname, ".."); error = gfs2_dir_del(ip, &dotname); if (error) return error; - error = gfs2_change_nlink(ip, -2); + /* It looks odd, but it really should be done twice */ + error = gfs2_change_nlink(ip, -1); if (error) return error; - /* This inode is being unlinked from the directory structure and - we need to mark that in the log so that it isn't lost during - a crash. */ - - ul->ul_ut.ut_inum = ip->i_num; - error = gfs2_unlinked_ondisk_add(sdp, ul); - if (!error) - set_bit(GLF_STICKY, &ip->i_gl->gl_flags); + error = gfs2_change_nlink(ip, -1); + if (error) + return error; return error; } @@ -1416,92 +1115,33 @@ int gfs2_rmdiri(struct gfs2_inode *dip, struct qstr *name, * Returns: 0 if the parent/child relationship is correct, errno if it isn't */ -int gfs2_unlink_ok(struct gfs2_inode *dip, struct qstr *name, - struct gfs2_inode *ip) +int gfs2_unlink_ok(struct gfs2_inode *dip, const struct qstr *name, + const struct gfs2_inode *ip) { - struct gfs2_inum inum; - unsigned int type; int error; - if (IS_IMMUTABLE(ip->i_vnode) || IS_APPEND(ip->i_vnode)) + if (IS_IMMUTABLE(&ip->i_inode) || IS_APPEND(&ip->i_inode)) return -EPERM; - if ((dip->i_di.di_mode & S_ISVTX) && - dip->i_di.di_uid != current->fsuid && - ip->i_di.di_uid != current->fsuid && - !capable(CAP_FOWNER)) + if ((dip->i_inode.i_mode & S_ISVTX) && + dip->i_inode.i_uid != current->fsuid && + ip->i_inode.i_uid != current->fsuid && !capable(CAP_FOWNER)) return -EPERM; - if (IS_APPEND(dip->i_vnode)) + if (IS_APPEND(&dip->i_inode)) return -EPERM; - error = gfs2_repermission(dip->i_vnode, MAY_WRITE | MAY_EXEC, NULL); + error = gfs2_permission(&dip->i_inode, MAY_WRITE | MAY_EXEC); if (error) return error; - error = gfs2_dir_search(dip, name, &inum, &type); + error = gfs2_dir_check(&dip->i_inode, name, ip); if (error) return error; - if (!gfs2_inum_equal(&inum, &ip->i_num)) - return -ENOENT; - - if (IF2DT(ip->i_di.di_mode) != type) { - gfs2_consist_inode(dip); - return -EIO; - } - return 0; } -/* - * gfs2_ok_to_move - check if it's ok to move a directory to another directory - * @this: move this - * @to: to here - * - * Follow @to back to the root and make sure we don't encounter @this - * Assumes we already hold the rename lock. - * - * Returns: errno - */ - -int gfs2_ok_to_move(struct gfs2_inode *this, struct gfs2_inode *to) -{ - struct inode *dir = to->i_vnode; - struct super_block *sb = dir->i_sb; - struct inode *tmp; - struct qstr dotdot; - int error = 0; - - memset(&dotdot, 0, sizeof(struct qstr)); - dotdot.name = ".."; - dotdot.len = 2; - - igrab(dir); - - for (;;) { - if (dir == this->i_vnode) { - error = -EINVAL; - break; - } - if (dir == sb->s_root->d_inode) { - error = 0; - break; - } - - error = gfs2_lookupi(dir, &dotdot, 1, &tmp); - if (error) - break; - - iput(dir); - dir = tmp; - } - - iput(dir); - - return error; -} - /** * gfs2_readlinki - return the contents of a symlink * @ip: the symlink's inode @@ -1521,8 +1161,8 @@ int gfs2_readlinki(struct gfs2_inode *ip, char **buf, unsigned int *len) unsigned int x; int error; - gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &i_gh); - error = gfs2_glock_nq_atime(&i_gh); + gfs2_holder_init(ip->i_gl, LM_ST_SHARED, 0, &i_gh); + error = gfs2_glock_nq(&i_gh); if (error) { gfs2_holder_uninit(&i_gh); return error; @@ -1540,7 +1180,7 @@ int gfs2_readlinki(struct gfs2_inode *ip, char **buf, unsigned int *len) x = ip->i_di.di_size + 1; if (x > *len) { - *buf = kmalloc(x, GFP_KERNEL); + *buf = kmalloc(x, GFP_NOFS); if (!*buf) { error = -ENOMEM; goto out_brelse; @@ -1550,245 +1190,13 @@ int gfs2_readlinki(struct gfs2_inode *ip, char **buf, unsigned int *len) memcpy(*buf, dibh->b_data + sizeof(struct gfs2_dinode), x); *len = x; - out_brelse: +out_brelse: brelse(dibh); - - out: +out: gfs2_glock_dq_uninit(&i_gh); - - return error; -} - -/** - * gfs2_glock_nq_atime - Acquire a hold on an inode's glock, and - * conditionally update the inode's atime - * @gh: the holder to acquire - * - * Tests atime (access time) for gfs2_read, gfs2_readdir and gfs2_mmap - * Update if the difference between the current time and the inode's current - * atime is greater than an interval specified at mount. - * - * Returns: errno - */ - -int gfs2_glock_nq_atime(struct gfs2_holder *gh) -{ - struct gfs2_glock *gl = gh->gh_gl; - struct gfs2_sbd *sdp = gl->gl_sbd; - struct gfs2_inode *ip = gl->gl_object; - int64_t curtime, quantum = gfs2_tune_get(sdp, gt_atime_quantum); - unsigned int state; - int flags; - int error; - - if (gfs2_assert_warn(sdp, gh->gh_flags & GL_ATIME) || - gfs2_assert_warn(sdp, !(gh->gh_flags & GL_ASYNC)) || - gfs2_assert_warn(sdp, gl->gl_ops == &gfs2_inode_glops)) - return -EINVAL; - - state = gh->gh_state; - flags = gh->gh_flags; - - error = gfs2_glock_nq(gh); - if (error) - return error; - - if (test_bit(SDF_NOATIME, &sdp->sd_flags) || - (sdp->sd_vfs->s_flags & MS_RDONLY)) - return 0; - - curtime = get_seconds(); - if (curtime - ip->i_di.di_atime >= quantum) { - gfs2_glock_dq(gh); - gfs2_holder_reinit(LM_ST_EXCLUSIVE, - gh->gh_flags & ~LM_FLAG_ANY, - gh); - error = gfs2_glock_nq(gh); - if (error) - return error; - - /* Verify that atime hasn't been updated while we were - trying to get exclusive lock. */ - - curtime = get_seconds(); - if (curtime - ip->i_di.di_atime >= quantum) { - struct buffer_head *dibh; - - error = gfs2_trans_begin(sdp, RES_DINODE, 0); - if (error == -EROFS) - return 0; - if (error) - goto fail; - - error = gfs2_meta_inode_buffer(ip, &dibh); - if (error) - goto fail_end_trans; - - ip->i_di.di_atime = curtime; - - gfs2_trans_add_bh(ip->i_gl, dibh, 1); - gfs2_dinode_out(&ip->i_di, dibh->b_data); - brelse(dibh); - - gfs2_trans_end(sdp); - } - - /* If someone else has asked for the glock, - unlock and let them have it. Then reacquire - in the original state. */ - if (gfs2_glock_is_blocking(gl)) { - gfs2_glock_dq(gh); - gfs2_holder_reinit(state, flags, gh); - return gfs2_glock_nq(gh); - } - } - - return 0; - - fail_end_trans: - gfs2_trans_end(sdp); - - fail: - gfs2_glock_dq(gh); - - return error; -} - -/** - * glock_compare_atime - Compare two struct gfs2_glock structures for sort - * @arg_a: the first structure - * @arg_b: the second structure - * - * Returns: 1 if A > B - * -1 if A < B - * 0 if A = B - */ - -static int glock_compare_atime(const void *arg_a, const void *arg_b) -{ - struct gfs2_holder *gh_a = *(struct gfs2_holder **)arg_a; - struct gfs2_holder *gh_b = *(struct gfs2_holder **)arg_b; - struct lm_lockname *a = &gh_a->gh_gl->gl_name; - struct lm_lockname *b = &gh_b->gh_gl->gl_name; - int ret = 0; - - if (a->ln_number > b->ln_number) - ret = 1; - else if (a->ln_number < b->ln_number) - ret = -1; - else { - if (gh_a->gh_state == LM_ST_SHARED && - gh_b->gh_state == LM_ST_EXCLUSIVE) - ret = 1; - else if (gh_a->gh_state == LM_ST_SHARED && - (gh_b->gh_flags & GL_ATIME)) - ret = 1; - } - - return ret; -} - -/** - * gfs2_glock_nq_m_atime - acquire multiple glocks where one may need an - * atime update - * @num_gh: the number of structures - * @ghs: an array of struct gfs2_holder structures - * - * Returns: 0 on success (all glocks acquired), - * errno on failure (no glocks acquired) - */ - -int gfs2_glock_nq_m_atime(unsigned int num_gh, struct gfs2_holder *ghs) -{ - struct gfs2_holder **p; - unsigned int x; - int error = 0; - - if (!num_gh) - return 0; - - if (num_gh == 1) { - ghs->gh_flags &= ~(LM_FLAG_TRY | GL_ASYNC); - if (ghs->gh_flags & GL_ATIME) - error = gfs2_glock_nq_atime(ghs); - else - error = gfs2_glock_nq(ghs); - return error; - } - - p = kcalloc(num_gh, sizeof(struct gfs2_holder *), GFP_KERNEL); - if (!p) - return -ENOMEM; - - for (x = 0; x < num_gh; x++) - p[x] = &ghs[x]; - - sort(p, num_gh, sizeof(struct gfs2_holder *), glock_compare_atime,NULL); - - for (x = 0; x < num_gh; x++) { - p[x]->gh_flags &= ~(LM_FLAG_TRY | GL_ASYNC); - - if (p[x]->gh_flags & GL_ATIME) - error = gfs2_glock_nq_atime(p[x]); - else - error = gfs2_glock_nq(p[x]); - - if (error) { - while (x--) - gfs2_glock_dq(p[x]); - break; - } - } - - kfree(p); - return error; } -/** - * gfs2_try_toss_vnode - See if we can toss a vnode from memory - * @ip: the inode - * - * Returns: 1 if the vnode was tossed - */ - -void gfs2_try_toss_vnode(struct gfs2_inode *ip) -{ - struct inode *inode; - - inode = gfs2_ip2v_lookup(ip); - if (!inode) - return; - - d_prune_aliases(inode); - - if (S_ISDIR(ip->i_di.di_mode)) { - struct list_head *head = &inode->i_dentry; - struct dentry *d = NULL; - - spin_lock(&dcache_lock); - if (list_empty(head)) - spin_unlock(&dcache_lock); - else { - d = list_entry(head->next, struct dentry, d_alias); - dget_locked(d); - spin_unlock(&dcache_lock); - - if (have_submounts(d)) - dput(d); - else { - shrink_dcache_parent(d); - dput(d); - d_prune_aliases(inode); - } - } - } - - inode->i_nlink = 0; - iput(inode); -} - - static int __gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr) { @@ -1797,12 +1205,10 @@ __gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr) error = gfs2_meta_inode_buffer(ip, &dibh); if (!error) { - error = inode_setattr(ip->i_vnode, attr); - gfs2_assert_warn(ip->i_sbd, !error); - gfs2_inode_attr_out(ip); - + error = inode_setattr(&ip->i_inode, attr); + gfs2_assert_warn(GFS2_SB(&ip->i_inode), !error); gfs2_trans_add_bh(ip->i_gl, dibh, 1); - gfs2_dinode_out(&ip->i_di, dibh->b_data); + gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); } return error; @@ -1825,19 +1231,73 @@ int gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr) if (current->journal_info) return __gfs2_setattr_simple(ip, attr); - error = gfs2_trans_begin(ip->i_sbd, RES_DINODE, 0); + error = gfs2_trans_begin(GFS2_SB(&ip->i_inode), RES_DINODE, 0); if (error) return error; error = __gfs2_setattr_simple(ip, attr); - - gfs2_trans_end(ip->i_sbd); - + gfs2_trans_end(GFS2_SB(&ip->i_inode)); return error; } -int gfs2_repermission(struct inode *inode, int mask, struct nameidata *nd) +void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf) +{ + const struct gfs2_dinode_host *di = &ip->i_di; + struct gfs2_dinode *str = buf; + + str->di_header.mh_magic = cpu_to_be32(GFS2_MAGIC); + str->di_header.mh_type = cpu_to_be32(GFS2_METATYPE_DI); + str->di_header.__pad0 = 0; + str->di_header.mh_format = cpu_to_be32(GFS2_FORMAT_DI); + str->di_header.__pad1 = 0; + str->di_num.no_addr = cpu_to_be64(ip->i_no_addr); + str->di_num.no_formal_ino = cpu_to_be64(ip->i_no_formal_ino); + str->di_mode = cpu_to_be32(ip->i_inode.i_mode); + str->di_uid = cpu_to_be32(ip->i_inode.i_uid); + str->di_gid = cpu_to_be32(ip->i_inode.i_gid); + str->di_nlink = cpu_to_be32(ip->i_inode.i_nlink); + str->di_size = cpu_to_be64(di->di_size); + str->di_blocks = cpu_to_be64(gfs2_get_inode_blocks(&ip->i_inode)); + str->di_atime = cpu_to_be64(ip->i_inode.i_atime.tv_sec); + str->di_mtime = cpu_to_be64(ip->i_inode.i_mtime.tv_sec); + str->di_ctime = cpu_to_be64(ip->i_inode.i_ctime.tv_sec); + + str->di_goal_meta = cpu_to_be64(ip->i_goal); + str->di_goal_data = cpu_to_be64(ip->i_goal); + str->di_generation = cpu_to_be64(di->di_generation); + + str->di_flags = cpu_to_be32(di->di_flags); + str->di_height = cpu_to_be16(ip->i_height); + str->di_payload_format = cpu_to_be32(S_ISDIR(ip->i_inode.i_mode) && + !(ip->i_di.di_flags & GFS2_DIF_EXHASH) ? + GFS2_FORMAT_DE : 0); + str->di_depth = cpu_to_be16(ip->i_depth); + str->di_entries = cpu_to_be32(di->di_entries); + + str->di_eattr = cpu_to_be64(di->di_eattr); + str->di_atime_nsec = cpu_to_be32(ip->i_inode.i_atime.tv_nsec); + str->di_mtime_nsec = cpu_to_be32(ip->i_inode.i_mtime.tv_nsec); + str->di_ctime_nsec = cpu_to_be32(ip->i_inode.i_ctime.tv_nsec); +} + +void gfs2_dinode_print(const struct gfs2_inode *ip) { - return permission(inode, mask, nd); + const struct gfs2_dinode_host *di = &ip->i_di; + + printk(KERN_INFO " no_formal_ino = %llu\n", + (unsigned long long)ip->i_no_formal_ino); + printk(KERN_INFO " no_addr = %llu\n", + (unsigned long long)ip->i_no_addr); + printk(KERN_INFO " di_size = %llu\n", (unsigned long long)di->di_size); + printk(KERN_INFO " blocks = %llu\n", + (unsigned long long)gfs2_get_inode_blocks(&ip->i_inode)); + printk(KERN_INFO " i_goal = %llu\n", + (unsigned long long)ip->i_goal); + printk(KERN_INFO " di_flags = 0x%.8X\n", di->di_flags); + printk(KERN_INFO " i_height = %u\n", ip->i_height); + printk(KERN_INFO " i_depth = %u\n", ip->i_depth); + printk(KERN_INFO " di_entries = %u\n", di->di_entries); + printk(KERN_INFO " di_eattr = %llu\n", + (unsigned long long)di->di_eattr); }