Commit 71b86f56 authored by Steven Whitehouse's avatar Steven Whitehouse

[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: default avatarSteven Whitehouse <swhiteho@redhat.com>
parent 94aabbd9
......@@ -13,6 +13,7 @@
#include <linux/completion.h>
#include <linux/buffer_head.h>
#include <linux/gfs2_ondisk.h>
#include <linux/crc32.h>
#include <asm/semaphore.h>
#include "gfs2.h"
......
This diff is collapsed.
......@@ -32,7 +32,7 @@ int gfs2_dir_search(struct inode *dir, const struct qstr *filename,
int gfs2_dir_add(struct inode *inode, const struct qstr *filename,
const struct gfs2_inum *inum, unsigned int type);
int gfs2_dir_del(struct gfs2_inode *dip, const struct qstr *filename);
int gfs2_dir_read(struct gfs2_inode *dip, uint64_t * offset, void *opaque,
int gfs2_dir_read(struct inode *inode, uint64_t * offset, void *opaque,
gfs2_filldir_t filldir);
int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename,
struct gfs2_inum *new_inum, unsigned int new_type);
......@@ -44,6 +44,19 @@ int gfs2_diradd_alloc_required(struct inode *dir,
int gfs2_dir_get_buffer(struct gfs2_inode *ip, uint64_t block, int new,
struct buffer_head **bhp);
static inline uint32_t gfs2_disk_hash(const char *data, int len)
{
return crc32_le(0xFFFFFFFF, data, len) ^ 0xFFFFFFFF;
}
static inline void gfs2_str2qstr(struct qstr *name, const char *fname)
{
name->name = fname;
name->len = strlen(fname);
name->hash = gfs2_disk_hash(name->name, name->len);
}
/* N.B. This probably ought to take inum & type as args as well */
static inline void gfs2_qstr2dirent(const struct qstr *name, u16 reclen, struct gfs2_dirent *dent)
{
......
......@@ -634,8 +634,7 @@ struct gfs2_sbd {
struct list_head sd_log_le_databuf;
unsigned int sd_log_blks_free;
struct list_head sd_log_blks_list;
wait_queue_head_t sd_log_blks_wait;
struct mutex sd_log_reserve_mutex;
uint64_t sd_log_sequence;
unsigned int sd_log_head;
......
......@@ -15,6 +15,7 @@
#include <linux/posix_acl.h>
#include <linux/sort.h>
#include <linux/gfs2_ondisk.h>
#include <linux/crc32.h>
#include <asm/semaphore.h>
#include "gfs2.h"
......@@ -701,9 +702,7 @@ int gfs2_change_nlink(struct gfs2_inode *ip, int diff)
struct inode *gfs2_lookup_simple(struct inode *dip, const char *name)
{
struct qstr qstr;
qstr.name = name;
qstr.len = strlen(name);
qstr.hash = gfs2_disk_hash(qstr.name, qstr.len);
gfs2_str2qstr(&qstr, name);
return gfs2_lookupi(dip, &qstr, 1, NULL);
}
......@@ -1389,9 +1388,7 @@ int gfs2_rmdiri(struct gfs2_inode *dip, struct qstr *name,
if (error)
return error;
dotname.len = 1;
dotname.name = ".";
dotname.hash = gfs2_disk_hash(dotname.name, dotname.len);
gfs2_str2qstr(&dotname, ".");
error = gfs2_dir_del(ip, &dotname);
if (error)
return error;
......@@ -1487,10 +1484,7 @@ int gfs2_ok_to_move(struct gfs2_inode *this, struct gfs2_inode *to)
struct qstr dotdot;
int error = 0;
memset(&dotdot, 0, sizeof(struct qstr));
dotdot.name = "..";
dotdot.len = 2;
dotdot.hash = gfs2_disk_hash(dotdot.name, dotdot.len);
gfs2_str2qstr(&dotdot, "..");
igrab(dir);
......
......@@ -13,6 +13,7 @@
#include <linux/completion.h>
#include <linux/buffer_head.h>
#include <linux/gfs2_ondisk.h>
#include <linux/crc32.h>
#include <asm/semaphore.h>
#include "gfs2.h"
......@@ -24,18 +25,13 @@
#include "lops.h"
#include "meta_io.h"
#include "util.h"
#include "dir.h"
#define PULL 1
static void do_lock_wait(struct gfs2_sbd *sdp, wait_queue_head_t *wq,
atomic_t *a)
{
wait_event(*wq, atomic_read(a) ? 0 : 1);
}
static void lock_for_trans(struct gfs2_sbd *sdp)
{
do_lock_wait(sdp, &sdp->sd_log_trans_wq, &sdp->sd_log_flush_count);
wait_event(sdp->sd_log_trans_wq, atomic_read(&sdp->sd_log_flush_count) ? 0 : 1);
atomic_inc(&sdp->sd_log_trans_count);
}
......@@ -49,7 +45,7 @@ static void unlock_from_trans(struct gfs2_sbd *sdp)
static void gfs2_lock_for_flush(struct gfs2_sbd *sdp)
{
atomic_inc(&sdp->sd_log_flush_count);
do_lock_wait(sdp, &sdp->sd_log_flush_wq, &sdp->sd_log_trans_count);
wait_event(sdp->sd_log_flush_wq, atomic_read(&sdp->sd_log_trans_count) ? 0 : 1);
}
static void gfs2_unlock_from_flush(struct gfs2_sbd *sdp)
......@@ -191,37 +187,19 @@ static void ail2_empty(struct gfs2_sbd *sdp, unsigned int new_tail)
int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks)
{
LIST_HEAD(list);
unsigned int try = 0;
if (gfs2_assert_warn(sdp, blks) ||
gfs2_assert_warn(sdp, blks <= sdp->sd_jdesc->jd_blocks))
return -EINVAL;
mutex_lock(&sdp->sd_log_reserve_mutex);
for (;;) {
gfs2_log_lock(sdp);
if (list_empty(&list)) {
list_add_tail(&list, &sdp->sd_log_blks_list);
while (sdp->sd_log_blks_list.next != &list) {
DECLARE_WAITQUEUE(__wait_chan, current);
set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(&sdp->sd_log_blks_wait,
&__wait_chan);
gfs2_log_unlock(sdp);
schedule();
gfs2_log_lock(sdp);
remove_wait_queue(&sdp->sd_log_blks_wait,
&__wait_chan);
set_current_state(TASK_RUNNING);
}
}
/* Never give away the last block so we can
always pull the tail if we need to. */
if (sdp->sd_log_blks_free > blks) {
sdp->sd_log_blks_free -= blks;
list_del(&list);
gfs2_log_unlock(sdp);
wake_up(&sdp->sd_log_blks_wait);
mutex_unlock(&sdp->sd_log_reserve_mutex);
break;
}
......
......@@ -14,6 +14,7 @@
#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"
......
......@@ -13,6 +13,7 @@
#include <linux/completion.h>
#include <linux/buffer_head.h>
#include <linux/gfs2_ondisk.h>
#include <linux/crc32.h>
#include <asm/semaphore.h>
#include "gfs2.h"
......@@ -153,7 +154,7 @@ static int gfs2_get_name(struct dentry *parent, char *name,
if (error)
return error;
error = gfs2_dir_read(dip, &offset, &gnfd, get_name_filldir);
error = gfs2_dir_read(dir, &offset, &gnfd, get_name_filldir);
gfs2_glock_dq_uninit(&gh);
......@@ -165,12 +166,11 @@ static int gfs2_get_name(struct dentry *parent, char *name,
static struct dentry *gfs2_get_parent(struct dentry *child)
{
struct qstr dotdot = { .name = "..", .len = 2 };
struct qstr dotdot;
struct inode *inode;
struct dentry *dentry;
dotdot.hash = gfs2_disk_hash(dotdot.name, dotdot.len);
gfs2_str2qstr(&dotdot, "..");
inode = gfs2_lookupi(child->d_inode, &dotdot, 1, NULL);
if (!inode)
......
......@@ -19,6 +19,8 @@
#include <linux/smp_lock.h>
#include <linux/fs.h>
#include <linux/gfs2_ondisk.h>
#include <linux/ext2_fs.h>
#include <linux/crc32.h>
#include <asm/semaphore.h>
#include <asm/uaccess.h>
......@@ -39,6 +41,7 @@
#include "rgrp.h"
#include "trans.h"
#include "util.h"
#include "eaops.h"
/* "bad" is for NFS support */
struct filldir_bad_entry {
......@@ -357,7 +360,8 @@ static int filldir_reg_func(void *opaque, const char *name, unsigned int length,
static int readdir_reg(struct file *file, void *dirent, filldir_t filldir)
{
struct gfs2_inode *dip = file->f_mapping->host->u.generic_ip;
struct inode *dir = file->f_mapping->host;
struct gfs2_inode *dip = dir->u.generic_ip;
struct filldir_reg fdr;
struct gfs2_holder d_gh;
uint64_t offset = file->f_pos;
......@@ -375,7 +379,7 @@ static int readdir_reg(struct file *file, void *dirent, filldir_t filldir)
return error;
}
error = gfs2_dir_read(dip, &offset, &fdr, filldir_reg_func);
error = gfs2_dir_read(dir, &offset, &fdr, filldir_reg_func);
gfs2_glock_dq_uninit(&d_gh);
......@@ -446,7 +450,8 @@ static int filldir_bad_func(void *opaque, const char *name, unsigned int length,
static int readdir_bad(struct file *file, void *dirent, filldir_t filldir)
{
struct gfs2_inode *dip = file->f_mapping->host->u.generic_ip;
struct inode *dir = file->f_mapping->host;
struct gfs2_inode *dip = dir->u.generic_ip;
struct gfs2_sbd *sdp = dip->i_sbd;
struct filldir_reg fdr;
unsigned int entries, size;
......@@ -479,7 +484,7 @@ static int readdir_bad(struct file *file, void *dirent, filldir_t filldir)
goto out;
}
error = gfs2_dir_read(dip, &offset, fdb, filldir_bad_func);
error = gfs2_dir_read(dir, &offset, fdb, filldir_bad_func);
gfs2_glock_dq_uninit(&d_gh);
......@@ -531,6 +536,210 @@ static int gfs2_readdir(struct file *file, void *dirent, filldir_t filldir)
return error;
}
const struct gfs2_flag_eattr {
u32 flag;
u32 ext2;
} gfs2_flag_eattrs[] = {
{
.flag = GFS2_DIF_IMMUTABLE,
.ext2 = EXT2_IMMUTABLE_FL,
}, {
.flag = GFS2_DIF_APPENDONLY,
.ext2 = EXT2_APPEND_FL,
}, {
.flag = GFS2_DIF_JDATA,
.ext2 = EXT2_JOURNAL_DATA_FL,
}, {
.flag = GFS2_DIF_EXHASH,
.ext2 = EXT2_INDEX_FL,
}, {
.flag = GFS2_DIF_EA_INDIRECT,
}, {
.flag = GFS2_DIF_DIRECTIO,
}, {
.flag = GFS2_DIF_NOATIME,
.ext2 = EXT2_NOATIME_FL,
}, {
.flag = GFS2_DIF_SYNC,
.ext2 = EXT2_SYNC_FL,
}, {
.flag = GFS2_DIF_SYSTEM,
}, {
.flag = GFS2_DIF_TRUNC_IN_PROG,
}, {
.flag = GFS2_DIF_INHERIT_JDATA,
}, {
.flag = GFS2_DIF_INHERIT_DIRECTIO,
}, {
},
};
static const struct gfs2_flag_eattr *get_by_ext2(u32 ext2)
{
const struct gfs2_flag_eattr *p = gfs2_flag_eattrs;
for(; p->flag; p++) {
if (ext2 == p->ext2)
return p;
}
return NULL;
}
static const struct gfs2_flag_eattr *get_by_gfs2(u32 gfs2)
{
const struct gfs2_flag_eattr *p = gfs2_flag_eattrs;
for(; p->flag; p++) {
if (gfs2 == p->flag)
return p;
}
return NULL;
}
static u32 gfs2_flags_to_ext2(u32 gfs2)
{
const struct gfs2_flag_eattr *ea;
u32 ext2 = 0;
u32 mask = 1;
for(; mask != 0; mask <<=1) {
if (mask & gfs2) {
ea = get_by_gfs2(mask);
if (ea)
ext2 |= ea->ext2;
}
}
return ext2;
}
static int gfs2_flags_from_ext2(u32 *gfs2, u32 ext2)
{
const struct gfs2_flag_eattr *ea;
u32 mask = 1;
for(; mask != 0; mask <<= 1) {
if (mask & ext2) {
ea = get_by_ext2(mask);
if (ea == NULL)
return -EINVAL;
*gfs2 |= ea->flag;
}
}
return 0;
}
static int get_ext2_flags(struct inode *inode, u32 __user *ptr)
{
struct gfs2_inode *ip = inode->u.generic_ip;
struct gfs2_holder gh;
int error;
u32 ext2;
gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &gh);
error = gfs2_glock_nq_m_atime(1, &gh);
if (error)
return error;
ext2 = gfs2_flags_to_ext2(ip->i_di.di_flags);
if (put_user(ext2, ptr))
error = -EFAULT;
gfs2_glock_dq_m(1, &gh);
gfs2_holder_uninit(&gh);
return error;
}
/* Flags that can be set by user space */
#define GFS2_FLAGS_USER_SET (GFS2_DIF_JDATA| \
GFS2_DIF_DIRECTIO| \
GFS2_DIF_IMMUTABLE| \
GFS2_DIF_APPENDONLY| \
GFS2_DIF_NOATIME| \
GFS2_DIF_SYNC| \
GFS2_DIF_SYSTEM| \
GFS2_DIF_INHERIT_DIRECTIO| \
GFS2_DIF_INHERIT_JDATA)
/**
* gfs2_set_flags - set flags on an inode
* @inode: The inode
* @flags: The flags to set
* @mask: Indicates which flags are valid
*
*/
static int gfs2_set_flags(struct inode *inode, u32 flags, u32 mask)
{
struct gfs2_inode *ip = inode->u.generic_ip;
struct buffer_head *bh;
struct gfs2_holder gh;
int error;
u32 new_flags;
gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
if (error)
return error;
new_flags = (ip->i_di.di_flags & ~mask) | (flags & mask);
if ((new_flags ^ flags) == 0)
goto out;
error = -EINVAL;
if ((new_flags ^ flags) & ~GFS2_FLAGS_USER_SET)
goto out;
if (S_ISDIR(inode->i_mode)) {
if ((new_flags ^ flags) & (GFS2_DIF_JDATA | GFS2_DIF_DIRECTIO))
goto out;
} else if (S_ISREG(inode->i_mode)) {
if ((new_flags ^ flags) & (GFS2_DIF_INHERIT_DIRECTIO|
GFS2_DIF_INHERIT_JDATA))
goto out;
} else
goto out;
error = -EPERM;
if (IS_IMMUTABLE(inode) && (new_flags & GFS2_DIF_IMMUTABLE))
goto out;
if (IS_APPEND(inode) && (new_flags & GFS2_DIF_APPENDONLY))
goto out;
error = gfs2_repermission(inode, MAY_WRITE, NULL);
if (error)
goto out;
error = gfs2_meta_inode_buffer(ip, &bh);
if (error)
goto out;
gfs2_trans_add_bh(ip->i_gl, bh, 1);
ip->i_di.di_flags = new_flags;
gfs2_dinode_out(&ip->i_di, bh->b_data);
brelse(bh);
out:
gfs2_glock_dq_uninit(&gh);
return error;
}
static int set_ext2_flags(struct inode *inode, u32 __user *ptr)
{
u32 ext2, gfs2;
if (get_user(ext2, ptr))
return -EFAULT;
if (gfs2_flags_from_ext2(&gfs2, ext2))
return -EINVAL;
return gfs2_set_flags(inode, gfs2, ~0);
}
int gfs2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
unsigned long arg)
{
switch(cmd) {
case EXT2_IOC_GETFLAGS:
return get_ext2_flags(inode, (u32 __user *)arg);
case EXT2_IOC_SETFLAGS:
return set_ext2_flags(inode, (u32 __user *)arg);
}
return -ENOTTY;
}
/**
* gfs2_mmap -
* @file: The file to map
......@@ -832,6 +1041,7 @@ struct file_operations gfs2_file_fops = {
.write = generic_file_write,
.writev = generic_file_writev,
.aio_write = generic_file_aio_write,
.ioctl = gfs2_ioctl,
.mmap = gfs2_mmap,
.open = gfs2_open,
.release = gfs2_close,
......@@ -843,6 +1053,7 @@ struct file_operations gfs2_file_fops = {
struct file_operations gfs2_dir_fops = {
.readdir = gfs2_readdir,
.ioctl = gfs2_ioctl,
.open = gfs2_open,
.release = gfs2_close,
.fsync = gfs2_fsync,
......
......@@ -97,9 +97,7 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb)
INIT_LIST_HEAD(&sdp->sd_log_le_rg);
INIT_LIST_HEAD(&sdp->sd_log_le_databuf);
INIT_LIST_HEAD(&sdp->sd_log_blks_list);
init_waitqueue_head(&sdp->sd_log_blks_wait);
mutex_init(&sdp->sd_log_reserve_mutex);
INIT_LIST_HEAD(&sdp->sd_ail1_list);
INIT_LIST_HEAD(&sdp->sd_ail2_list);
......
......@@ -18,6 +18,7 @@
#include <linux/xattr.h>
#include <linux/posix_acl.h>
#include <linux/gfs2_ondisk.h>
#include <linux/crc32.h>
#include <asm/semaphore.h>
#include <asm/uaccess.h>
......@@ -417,18 +418,16 @@ static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode)
if (!gfs2_assert_withdraw(sdp, !error)) {
struct gfs2_dinode *di = (struct gfs2_dinode *)dibh->b_data;
struct gfs2_dirent *dent = (struct gfs2_dirent *)(di+1);
struct qstr str = { .name = ".", .len = 1 };
str.hash = gfs2_disk_hash(str.name, str.len);
struct qstr str;
gfs2_str2qstr(&str, ".");
gfs2_trans_add_bh(ip->i_gl, dibh, 1);
gfs2_qstr2dirent(&str, GFS2_DIRENT_SIZE(str.len), dent);
dent->de_inum = di->di_num; /* already GFS2 endian */
dent->de_type = DT_DIR;
di->di_entries = cpu_to_be32(1);
str.name = "..";
str.len = 2;
str.hash = gfs2_disk_hash(str.name, str.len);
gfs2_str2qstr(&str, "..");
dent = (struct gfs2_dirent *)((char*)dent + GFS2_DIRENT_SIZE(1));
gfs2_qstr2dirent(&str, dibh->b_size - GFS2_DIRENT_SIZE(1) - sizeof(struct gfs2_dinode), dent);
......@@ -772,9 +771,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
if (dir_rename) {
struct qstr name;
name.len = 2;
name.name = "..";
name.hash = gfs2_disk_hash(name.name, name.len);
gfs2_str2qstr(&name, "..");
error = gfs2_change_nlink(ndip, +1);
if (error)
......
......@@ -13,6 +13,7 @@
#include <linux/completion.h>
#include <linux/buffer_head.h>
#include <linux/gfs2_ondisk.h>
#include <linux/crc32.h>
#include <asm/semaphore.h>
#include "gfs2.h"
......@@ -27,6 +28,7 @@
#include "recovery.h"
#include "super.h"
#include "util.h"
#include "dir.h"
int gfs2_replay_read_block(struct gfs2_jdesc *jd, unsigned int blk,
struct buffer_head **bh)
......
......@@ -12,6 +12,7 @@
#include <linux/spinlock.h>
#include <linux/completion.h>
#include <linux/buffer_head.h>
#include <linux/crc32.h>
#include <linux/gfs2_ondisk.h>
#include <asm/semaphore.h>
......
......@@ -28,11 +28,6 @@ kmem_cache_t *gfs2_glock_cachep __read_mostly;
kmem_cache_t *gfs2_inode_cachep __read_mostly;
kmem_cache_t *gfs2_bufdata_cachep __read_mostly;
uint32_t gfs2_disk_hash(const char *data, int len)
{
return crc32_le(0xFFFFFFFF, data, len) ^ 0xFFFFFFFF;
}
void gfs2_assert_i(struct gfs2_sbd *sdp)
{
printk(KERN_EMERG "GFS2: fsid=%s: fatal assertion failed\n",
......
......@@ -10,8 +10,6 @@
#ifndef __UTIL_DOT_H__
#define __UTIL_DOT_H__
uint32_t gfs2_disk_hash(const char *data, int len);
#define fs_printk(level, fs, fmt, arg...) \
printk(level "GFS2: fsid=%s: " fmt , (fs)->sd_fsname , ## arg)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment