kernel-ark/fs/gfs2/ops_dentry.c
Steven Whitehouse 71b86f562b [GFS2] Further updates to dir and logging code
This reduces the size of the directory code by about 3k and gets
readdir() to use the functions which were introduced in the previous
directory code update.

Two memory allocations are merged into one. Eliminates zeroing of some
buffers which were never used before they were initialised by
other data.

There is still scope for further improvement in the directory code.

On the logging side, a hand created mutex has been replaced by a
standard Linux mutex in the log allocation code.

Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2006-03-28 14:14:04 -05:00

125 lines
2.6 KiB
C

/*
* Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
* Copyright (C) 2004-2005 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.
*/
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/completion.h>
#include <linux/buffer_head.h>
#include <linux/smp_lock.h>
#include <linux/gfs2_ondisk.h>
#include <linux/crc32.h>
#include <asm/semaphore.h>
#include "gfs2.h"
#include "lm_interface.h"
#include "incore.h"
#include "dir.h"
#include "glock.h"
#include "ops_dentry.h"
#include "util.h"
/**
* gfs2_drevalidate - Check directory lookup consistency
* @dentry: the mapping to check
* @nd:
*
* Check to make sure the lookup necessary to arrive at this inode from its
* parent is still good.
*
* Returns: 1 if the dentry is ok, 0 if it isn't
*/
static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd)
{
struct dentry *parent = dget_parent(dentry);
struct gfs2_sbd *sdp = parent->d_inode->i_sb->s_fs_info;
struct gfs2_inode *dip = parent->d_inode->u.generic_ip;
struct inode *inode = dentry->d_inode;
struct gfs2_holder d_gh;
struct gfs2_inode *ip;
struct gfs2_inum inum;
unsigned int type;
int error;
if (inode && is_bad_inode(inode))
goto invalid;
if (sdp->sd_args.ar_localcaching)
goto valid;
error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh);
if (error)
goto fail;
error = gfs2_dir_search(parent->d_inode, &dentry->d_name, &inum, &type);
switch (error) {
case 0:
if (!inode)
goto invalid_gunlock;
break;
case -ENOENT:
if (!inode)
goto valid_gunlock;
goto invalid_gunlock;
default:
goto fail_gunlock;
}
ip = inode->u.generic_ip;
if (!gfs2_inum_equal(&ip->i_num, &inum))
goto invalid_gunlock;
if (IF2DT(ip->i_di.di_mode) != type) {
gfs2_consist_inode(dip);
goto fail_gunlock;
}
valid_gunlock:
gfs2_glock_dq_uninit(&d_gh);
valid:
dput(parent);
return 1;
invalid_gunlock:
gfs2_glock_dq_uninit(&d_gh);
invalid:
if (inode && S_ISDIR(inode->i_mode)) {
if (have_submounts(dentry))
goto valid;
shrink_dcache_parent(dentry);
}
d_drop(dentry);
dput(parent);
return 0;
fail_gunlock:
gfs2_glock_dq_uninit(&d_gh);
fail:
dput(parent);
return 0;
}
static int gfs2_dhash(struct dentry *dentry, struct qstr *str)
{
str->hash = gfs2_disk_hash(str->name, str->len);
return 0;
}
struct dentry_operations gfs2_dops = {
.d_revalidate = gfs2_drevalidate,
.d_hash = gfs2_dhash,
};