mirror of
https://github.com/Dasharo/linux.git
synced 2026-03-06 15:25:10 -08:00
[GFS2] The core of GFS2
This patch contains all the core files for GFS2. Signed-off-by: David Teigland <teigland@redhat.com> Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
This commit is contained in:
committed by
Steven Whitehouse
parent
f7825dcf8c
commit
b3b94faa5f
46
fs/gfs2/Kconfig
Normal file
46
fs/gfs2/Kconfig
Normal file
@@ -0,0 +1,46 @@
|
||||
config GFS2_FS
|
||||
tristate "GFS2 file system support"
|
||||
default m
|
||||
depends on EXPERIMENTAL
|
||||
select FS_POSIX_ACL
|
||||
select SYSFS
|
||||
help
|
||||
A cluster filesystem.
|
||||
|
||||
Allows a cluster of computers to simultaneously use a block device
|
||||
that is shared between them (with FC, iSCSI, NBD, etc...). GFS reads
|
||||
and writes to the block device like a local filesystem, but also uses
|
||||
a lock module to allow the computers coordinate their I/O so
|
||||
filesystem consistency is maintained. One of the nifty features of
|
||||
GFS is perfect consistency -- changes made to the filesystem on one
|
||||
machine show up immediately on all other machines in the cluster.
|
||||
|
||||
To use the GFS2 filesystem, you will need to enable one or more of
|
||||
the below locking modules. Documentation and utilities for GFS2 can
|
||||
be found here: http://sources.redhat.com/cluster/gfs/
|
||||
|
||||
config GFS2_FS_LOCKING_NOLOCK
|
||||
tristate "GFS2 \"nolock\" locking module"
|
||||
depends on GFS2_FS
|
||||
help
|
||||
Single node locking module for GFS2.
|
||||
|
||||
Use this module if you want to use GFS2 on a single node without
|
||||
its clustering features. You can still take advantage of the
|
||||
large file support, and upgrade to running a full cluster later on
|
||||
if required.
|
||||
|
||||
If you will only be using GFS2 in cluster mode, you do not need this
|
||||
module.
|
||||
|
||||
config GFS2_FS_LOCKING_DLM
|
||||
tristate "GFS2 DLM locking module"
|
||||
depends on GFS2_FS
|
||||
select DLM
|
||||
help
|
||||
Multiple node locking module for GFS2
|
||||
|
||||
Most users of GFS2 will require this module. It provides the locking
|
||||
interface between GFS2 and the DLM, which is required to use GFS2
|
||||
in a cluster environment.
|
||||
|
||||
44
fs/gfs2/Makefile
Normal file
44
fs/gfs2/Makefile
Normal file
@@ -0,0 +1,44 @@
|
||||
obj-$(CONFIG_GFS2_FS) += gfs2.o
|
||||
gfs2-y := \
|
||||
acl.o \
|
||||
bits.o \
|
||||
bmap.o \
|
||||
daemon.o \
|
||||
dir.o \
|
||||
eaops.o \
|
||||
eattr.o \
|
||||
glock.o \
|
||||
glops.o \
|
||||
inode.o \
|
||||
jdata.o \
|
||||
lm.o \
|
||||
log.o \
|
||||
lops.o \
|
||||
locking.o \
|
||||
lvb.o \
|
||||
main.o \
|
||||
meta_io.o \
|
||||
mount.o \
|
||||
ondisk.o \
|
||||
ops_address.o \
|
||||
ops_dentry.o \
|
||||
ops_export.o \
|
||||
ops_file.o \
|
||||
ops_fstype.o \
|
||||
ops_inode.o \
|
||||
ops_super.o \
|
||||
ops_vm.o \
|
||||
page.o \
|
||||
quota.o \
|
||||
resize.o \
|
||||
recovery.o \
|
||||
rgrp.o \
|
||||
super.o \
|
||||
sys.o \
|
||||
trans.o \
|
||||
unlinked.o \
|
||||
util.o
|
||||
|
||||
obj-$(CONFIG_GFS2_LOCKING_NOLOCK) += locking/nolock/
|
||||
obj-$(CONFIG_GFS2_LOCKING_DLM) += locking/dlm/
|
||||
|
||||
312
fs/gfs2/acl.c
Normal file
312
fs/gfs2/acl.c
Normal file
@@ -0,0 +1,312 @@
|
||||
/*
|
||||
* 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/posix_acl.h>
|
||||
#include <linux/posix_acl_xattr.h>
|
||||
#include <asm/semaphore.h>
|
||||
|
||||
#include "gfs2.h"
|
||||
#include "acl.h"
|
||||
#include "eaops.h"
|
||||
#include "eattr.h"
|
||||
#include "glock.h"
|
||||
#include "inode.h"
|
||||
#include "meta_io.h"
|
||||
#include "trans.h"
|
||||
|
||||
#define ACL_ACCESS 1
|
||||
#define ACL_DEFAULT 0
|
||||
|
||||
int gfs2_acl_validate_set(struct gfs2_inode *ip, int access,
|
||||
struct gfs2_ea_request *er,
|
||||
int *remove, mode_t *mode)
|
||||
{
|
||||
struct posix_acl *acl;
|
||||
int error;
|
||||
|
||||
error = gfs2_acl_validate_remove(ip, access);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (!er->er_data)
|
||||
return -EINVAL;
|
||||
|
||||
acl = posix_acl_from_xattr(er->er_data, er->er_data_len);
|
||||
if (IS_ERR(acl))
|
||||
return PTR_ERR(acl);
|
||||
if (!acl) {
|
||||
*remove = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
error = posix_acl_valid(acl);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
if (access) {
|
||||
error = posix_acl_equiv_mode(acl, mode);
|
||||
if (!error)
|
||||
*remove = 1;
|
||||
else if (error > 0)
|
||||
error = 0;
|
||||
}
|
||||
|
||||
out:
|
||||
posix_acl_release(acl);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int gfs2_acl_validate_remove(struct gfs2_inode *ip, int access)
|
||||
{
|
||||
if (!ip->i_sbd->sd_args.ar_posix_acl)
|
||||
return -EOPNOTSUPP;
|
||||
if (current->fsuid != ip->i_di.di_uid && !capable(CAP_FOWNER))
|
||||
return -EPERM;
|
||||
if (S_ISLNK(ip->i_di.di_mode))
|
||||
return -EOPNOTSUPP;
|
||||
if (!access && !S_ISDIR(ip->i_di.di_mode))
|
||||
return -EACCES;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acl_get(struct gfs2_inode *ip, int access, struct posix_acl **acl,
|
||||
struct gfs2_ea_location *el, char **data, unsigned int *len)
|
||||
{
|
||||
struct gfs2_ea_request er;
|
||||
struct gfs2_ea_location el_this;
|
||||
int error;
|
||||
|
||||
if (!ip->i_di.di_eattr)
|
||||
return 0;
|
||||
|
||||
memset(&er, 0, sizeof(struct gfs2_ea_request));
|
||||
if (access) {
|
||||
er.er_name = GFS2_POSIX_ACL_ACCESS;
|
||||
er.er_name_len = GFS2_POSIX_ACL_ACCESS_LEN;
|
||||
} else {
|
||||
er.er_name = GFS2_POSIX_ACL_DEFAULT;
|
||||
er.er_name_len = GFS2_POSIX_ACL_DEFAULT_LEN;
|
||||
}
|
||||
er.er_type = GFS2_EATYPE_SYS;
|
||||
|
||||
if (!el)
|
||||
el = &el_this;
|
||||
|
||||
error = gfs2_ea_find(ip, &er, el);
|
||||
if (error)
|
||||
return error;
|
||||
if (!el->el_ea)
|
||||
return 0;
|
||||
if (!GFS2_EA_DATA_LEN(el->el_ea))
|
||||
goto out;
|
||||
|
||||
er.er_data_len = GFS2_EA_DATA_LEN(el->el_ea);
|
||||
er.er_data = kmalloc(er.er_data_len, GFP_KERNEL);
|
||||
error = -ENOMEM;
|
||||
if (!er.er_data)
|
||||
goto out;
|
||||
|
||||
error = gfs2_ea_get_copy(ip, el, er.er_data);
|
||||
if (error)
|
||||
goto out_kfree;
|
||||
|
||||
if (acl) {
|
||||
*acl = posix_acl_from_xattr(er.er_data, er.er_data_len);
|
||||
if (IS_ERR(*acl))
|
||||
error = PTR_ERR(*acl);
|
||||
}
|
||||
|
||||
out_kfree:
|
||||
if (error || !data)
|
||||
kfree(er.er_data);
|
||||
else {
|
||||
*data = er.er_data;
|
||||
*len = er.er_data_len;
|
||||
}
|
||||
|
||||
out:
|
||||
if (error || el == &el_this)
|
||||
brelse(el->el_bh);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* gfs2_check_acl_locked - Check an ACL to see if we're allowed to do something
|
||||
* @inode: the file we want to do something to
|
||||
* @mask: what we want to do
|
||||
*
|
||||
* Returns: errno
|
||||
*/
|
||||
|
||||
int gfs2_check_acl_locked(struct inode *inode, int mask)
|
||||
{
|
||||
struct posix_acl *acl = NULL;
|
||||
int error;
|
||||
|
||||
error = acl_get(get_v2ip(inode), ACL_ACCESS, &acl, NULL, NULL, NULL);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (acl) {
|
||||
error = posix_acl_permission(inode, acl, mask);
|
||||
posix_acl_release(acl);
|
||||
return error;
|
||||
}
|
||||
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
int gfs2_check_acl(struct inode *inode, int mask)
|
||||
{
|
||||
struct gfs2_inode *ip = get_v2ip(inode);
|
||||
struct gfs2_holder i_gh;
|
||||
int error;
|
||||
|
||||
error = gfs2_glock_nq_init(ip->i_gl,
|
||||
LM_ST_SHARED, LM_FLAG_ANY,
|
||||
&i_gh);
|
||||
if (!error) {
|
||||
error = gfs2_check_acl_locked(inode, mask);
|
||||
gfs2_glock_dq_uninit(&i_gh);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int munge_mode(struct gfs2_inode *ip, mode_t mode)
|
||||
{
|
||||
struct gfs2_sbd *sdp = ip->i_sbd;
|
||||
struct buffer_head *dibh;
|
||||
int error;
|
||||
|
||||
error = gfs2_trans_begin(sdp, RES_DINODE, 0);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = gfs2_meta_inode_buffer(ip, &dibh);
|
||||
if (!error) {
|
||||
gfs2_assert_withdraw(sdp,
|
||||
(ip->i_di.di_mode & S_IFMT) == (mode & S_IFMT));
|
||||
ip->i_di.di_mode = mode;
|
||||
gfs2_trans_add_bh(ip->i_gl, dibh);
|
||||
gfs2_dinode_out(&ip->i_di, dibh->b_data);
|
||||
brelse(dibh);
|
||||
}
|
||||
|
||||
gfs2_trans_end(sdp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip)
|
||||
{
|
||||
struct gfs2_sbd *sdp = dip->i_sbd;
|
||||
struct posix_acl *acl = NULL, *clone;
|
||||
struct gfs2_ea_request er;
|
||||
mode_t mode = ip->i_di.di_mode;
|
||||
int error;
|
||||
|
||||
if (!sdp->sd_args.ar_posix_acl)
|
||||
return 0;
|
||||
if (S_ISLNK(ip->i_di.di_mode))
|
||||
return 0;
|
||||
|
||||
memset(&er, 0, sizeof(struct gfs2_ea_request));
|
||||
er.er_type = GFS2_EATYPE_SYS;
|
||||
|
||||
error = acl_get(dip, ACL_DEFAULT, &acl, NULL,
|
||||
&er.er_data, &er.er_data_len);
|
||||
if (error)
|
||||
return error;
|
||||
if (!acl) {
|
||||
mode &= ~current->fs->umask;
|
||||
if (mode != ip->i_di.di_mode)
|
||||
error = munge_mode(ip, mode);
|
||||
return error;
|
||||
}
|
||||
|
||||
clone = posix_acl_clone(acl, GFP_KERNEL);
|
||||
error = -ENOMEM;
|
||||
if (!clone)
|
||||
goto out;
|
||||
posix_acl_release(acl);
|
||||
acl = clone;
|
||||
|
||||
if (S_ISDIR(ip->i_di.di_mode)) {
|
||||
er.er_name = GFS2_POSIX_ACL_DEFAULT;
|
||||
er.er_name_len = GFS2_POSIX_ACL_DEFAULT_LEN;
|
||||
error = gfs2_system_eaops.eo_set(ip, &er);
|
||||
if (error)
|
||||
goto out;
|
||||
}
|
||||
|
||||
error = posix_acl_create_masq(acl, &mode);
|
||||
if (error < 0)
|
||||
goto out;
|
||||
if (error > 0) {
|
||||
er.er_name = GFS2_POSIX_ACL_ACCESS;
|
||||
er.er_name_len = GFS2_POSIX_ACL_ACCESS_LEN;
|
||||
posix_acl_to_xattr(acl, er.er_data, er.er_data_len);
|
||||
er.er_mode = mode;
|
||||
er.er_flags = GFS2_ERF_MODE;
|
||||
error = gfs2_system_eaops.eo_set(ip, &er);
|
||||
if (error)
|
||||
goto out;
|
||||
} else
|
||||
munge_mode(ip, mode);
|
||||
|
||||
out:
|
||||
posix_acl_release(acl);
|
||||
kfree(er.er_data);
|
||||
return error;
|
||||
}
|
||||
|
||||
int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr)
|
||||
{
|
||||
struct posix_acl *acl = NULL, *clone;
|
||||
struct gfs2_ea_location el;
|
||||
char *data;
|
||||
unsigned int len;
|
||||
int error;
|
||||
|
||||
error = acl_get(ip, ACL_ACCESS, &acl, &el, &data, &len);
|
||||
if (error)
|
||||
return error;
|
||||
if (!acl)
|
||||
return gfs2_setattr_simple(ip, attr);
|
||||
|
||||
clone = posix_acl_clone(acl, GFP_KERNEL);
|
||||
error = -ENOMEM;
|
||||
if (!clone)
|
||||
goto out;
|
||||
posix_acl_release(acl);
|
||||
acl = clone;
|
||||
|
||||
error = posix_acl_chmod_masq(acl, attr->ia_mode);
|
||||
if (!error) {
|
||||
posix_acl_to_xattr(acl, data, len);
|
||||
error = gfs2_ea_acl_chmod(ip, &el, attr, data);
|
||||
}
|
||||
|
||||
out:
|
||||
posix_acl_release(acl);
|
||||
brelse(el.el_bh);
|
||||
kfree(data);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
37
fs/gfs2/acl.h
Normal file
37
fs/gfs2/acl.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __ACL_DOT_H__
|
||||
#define __ACL_DOT_H__
|
||||
|
||||
#define GFS2_POSIX_ACL_ACCESS "posix_acl_access"
|
||||
#define GFS2_POSIX_ACL_ACCESS_LEN 16
|
||||
#define GFS2_POSIX_ACL_DEFAULT "posix_acl_default"
|
||||
#define GFS2_POSIX_ACL_DEFAULT_LEN 17
|
||||
|
||||
#define GFS2_ACL_IS_ACCESS(name, len) \
|
||||
((len) == GFS2_POSIX_ACL_ACCESS_LEN && \
|
||||
!memcmp(GFS2_POSIX_ACL_ACCESS, (name), (len)))
|
||||
|
||||
#define GFS2_ACL_IS_DEFAULT(name, len) \
|
||||
((len) == GFS2_POSIX_ACL_DEFAULT_LEN && \
|
||||
!memcmp(GFS2_POSIX_ACL_DEFAULT, (name), (len)))
|
||||
|
||||
struct gfs2_ea_request;
|
||||
|
||||
int gfs2_acl_validate_set(struct gfs2_inode *ip, int access,
|
||||
struct gfs2_ea_request *er,
|
||||
int *remove, mode_t *mode);
|
||||
int gfs2_acl_validate_remove(struct gfs2_inode *ip, int access);
|
||||
int gfs2_check_acl_locked(struct inode *inode, int mask);
|
||||
int gfs2_check_acl(struct inode *inode, int mask);
|
||||
int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip);
|
||||
int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr);
|
||||
|
||||
#endif /* __ACL_DOT_H__ */
|
||||
178
fs/gfs2/bits.c
Normal file
178
fs/gfs2/bits.c
Normal file
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* These routines are used by the resource group routines (rgrp.c)
|
||||
* to keep track of block allocation. Each block is represented by two
|
||||
* bits. One bit indicates whether or not the block is used. (1=used,
|
||||
* 0=free) The other bit indicates whether or not the block contains a
|
||||
* dinode or not. (1=dinode, 0=not-dinode) So, each byte represents
|
||||
* GFS2_NBBY (i.e. 4) blocks.
|
||||
*/
|
||||
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/buffer_head.h>
|
||||
#include <asm/semaphore.h>
|
||||
|
||||
#include "gfs2.h"
|
||||
#include "bits.h"
|
||||
|
||||
static const char valid_change[16] = {
|
||||
/* current */
|
||||
/* n */ 0, 1, 0, 1,
|
||||
/* e */ 1, 0, 0, 0,
|
||||
/* w */ 0, 0, 0, 0,
|
||||
1, 0, 0, 0
|
||||
};
|
||||
|
||||
/**
|
||||
* gfs2_setbit - Set a bit in the bitmaps
|
||||
* @buffer: the buffer that holds the bitmaps
|
||||
* @buflen: the length (in bytes) of the buffer
|
||||
* @block: the block to set
|
||||
* @new_state: the new state of the block
|
||||
*
|
||||
*/
|
||||
|
||||
void gfs2_setbit(struct gfs2_rgrpd *rgd, unsigned char *buffer,
|
||||
unsigned int buflen, uint32_t block, unsigned char new_state)
|
||||
{
|
||||
unsigned char *byte, *end, cur_state;
|
||||
unsigned int bit;
|
||||
|
||||
byte = buffer + (block / GFS2_NBBY);
|
||||
bit = (block % GFS2_NBBY) * GFS2_BIT_SIZE;
|
||||
end = buffer + buflen;
|
||||
|
||||
gfs2_assert(rgd->rd_sbd, byte < end);
|
||||
|
||||
cur_state = (*byte >> bit) & GFS2_BIT_MASK;
|
||||
|
||||
if (valid_change[new_state * 4 + cur_state]) {
|
||||
*byte ^= cur_state << bit;
|
||||
*byte |= new_state << bit;
|
||||
} else
|
||||
gfs2_consist_rgrpd(rgd);
|
||||
}
|
||||
|
||||
/**
|
||||
* gfs2_testbit - test a bit in the bitmaps
|
||||
* @buffer: the buffer that holds the bitmaps
|
||||
* @buflen: the length (in bytes) of the buffer
|
||||
* @block: the block to read
|
||||
*
|
||||
*/
|
||||
|
||||
unsigned char gfs2_testbit(struct gfs2_rgrpd *rgd, unsigned char *buffer,
|
||||
unsigned int buflen, uint32_t block)
|
||||
{
|
||||
unsigned char *byte, *end, cur_state;
|
||||
unsigned int bit;
|
||||
|
||||
byte = buffer + (block / GFS2_NBBY);
|
||||
bit = (block % GFS2_NBBY) * GFS2_BIT_SIZE;
|
||||
end = buffer + buflen;
|
||||
|
||||
gfs2_assert(rgd->rd_sbd, byte < end);
|
||||
|
||||
cur_state = (*byte >> bit) & GFS2_BIT_MASK;
|
||||
|
||||
return cur_state;
|
||||
}
|
||||
|
||||
/**
|
||||
* gfs2_bitfit - Search an rgrp's bitmap buffer to find a bit-pair representing
|
||||
* a block in a given allocation state.
|
||||
* @buffer: the buffer that holds the bitmaps
|
||||
* @buflen: the length (in bytes) of the buffer
|
||||
* @goal: start search at this block's bit-pair (within @buffer)
|
||||
* @old_state: GFS2_BLKST_XXX the state of the block we're looking for;
|
||||
* bit 0 = alloc(1)/free(0), bit 1 = meta(1)/data(0)
|
||||
*
|
||||
* Scope of @goal and returned block number is only within this bitmap buffer,
|
||||
* not entire rgrp or filesystem. @buffer will be offset from the actual
|
||||
* beginning of a bitmap block buffer, skipping any header structures.
|
||||
*
|
||||
* Return: the block number (bitmap buffer scope) that was found
|
||||
*/
|
||||
|
||||
uint32_t gfs2_bitfit(struct gfs2_rgrpd *rgd, unsigned char *buffer,
|
||||
unsigned int buflen, uint32_t goal,
|
||||
unsigned char old_state)
|
||||
{
|
||||
unsigned char *byte, *end, alloc;
|
||||
uint32_t blk = goal;
|
||||
unsigned int bit;
|
||||
|
||||
byte = buffer + (goal / GFS2_NBBY);
|
||||
bit = (goal % GFS2_NBBY) * GFS2_BIT_SIZE;
|
||||
end = buffer + buflen;
|
||||
alloc = (old_state & 1) ? 0 : 0x55;
|
||||
|
||||
while (byte < end) {
|
||||
if ((*byte & 0x55) == alloc) {
|
||||
blk += (8 - bit) >> 1;
|
||||
|
||||
bit = 0;
|
||||
byte++;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (((*byte >> bit) & GFS2_BIT_MASK) == old_state)
|
||||
return blk;
|
||||
|
||||
bit += GFS2_BIT_SIZE;
|
||||
if (bit >= 8) {
|
||||
bit = 0;
|
||||
byte++;
|
||||
}
|
||||
|
||||
blk++;
|
||||
}
|
||||
|
||||
return BFITNOENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* gfs2_bitcount - count the number of bits in a certain state
|
||||
* @buffer: the buffer that holds the bitmaps
|
||||
* @buflen: the length (in bytes) of the buffer
|
||||
* @state: the state of the block we're looking for
|
||||
*
|
||||
* Returns: The number of bits
|
||||
*/
|
||||
|
||||
uint32_t gfs2_bitcount(struct gfs2_rgrpd *rgd, unsigned char *buffer,
|
||||
unsigned int buflen, unsigned char state)
|
||||
{
|
||||
unsigned char *byte = buffer;
|
||||
unsigned char *end = buffer + buflen;
|
||||
unsigned char state1 = state << 2;
|
||||
unsigned char state2 = state << 4;
|
||||
unsigned char state3 = state << 6;
|
||||
uint32_t count = 0;
|
||||
|
||||
for (; byte < end; byte++) {
|
||||
if (((*byte) & 0x03) == state)
|
||||
count++;
|
||||
if (((*byte) & 0x0C) == state1)
|
||||
count++;
|
||||
if (((*byte) & 0x30) == state2)
|
||||
count++;
|
||||
if (((*byte) & 0xC0) == state3)
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
28
fs/gfs2/bits.h
Normal file
28
fs/gfs2/bits.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __BITS_DOT_H__
|
||||
#define __BITS_DOT_H__
|
||||
|
||||
#define BFITNOENT 0xFFFFFFFF
|
||||
|
||||
void gfs2_setbit(struct gfs2_rgrpd *rgd,
|
||||
unsigned char *buffer, unsigned int buflen,
|
||||
uint32_t block, unsigned char new_state);
|
||||
unsigned char gfs2_testbit(struct gfs2_rgrpd *rgd,
|
||||
unsigned char *buffer, unsigned int buflen,
|
||||
uint32_t block);
|
||||
uint32_t gfs2_bitfit(struct gfs2_rgrpd *rgd,
|
||||
unsigned char *buffer, unsigned int buflen,
|
||||
uint32_t goal, unsigned char old_state);
|
||||
uint32_t gfs2_bitcount(struct gfs2_rgrpd *rgd,
|
||||
unsigned char *buffer, unsigned int buflen,
|
||||
unsigned char state);
|
||||
|
||||
#endif /* __BITS_DOT_H__ */
|
||||
1206
fs/gfs2/bmap.c
Normal file
1206
fs/gfs2/bmap.c
Normal file
File diff suppressed because it is too large
Load Diff
39
fs/gfs2/bmap.h
Normal file
39
fs/gfs2/bmap.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __BMAP_DOT_H__
|
||||
#define __BMAP_DOT_H__
|
||||
|
||||
typedef int (*gfs2_unstuffer_t) (struct gfs2_inode * ip,
|
||||
struct buffer_head * dibh, uint64_t block,
|
||||
void *private);
|
||||
int gfs2_unstuffer_sync(struct gfs2_inode *ip, struct buffer_head *dibh,
|
||||
uint64_t block, void *private);
|
||||
int gfs2_unstuff_dinode(struct gfs2_inode *ip, gfs2_unstuffer_t unstuffer,
|
||||
void *private);
|
||||
|
||||
int gfs2_block_map(struct gfs2_inode *ip,
|
||||
uint64_t lblock, int *new,
|
||||
uint64_t *dblock, uint32_t *extlen);
|
||||
|
||||
typedef int (*gfs2_truncator_t) (struct gfs2_inode * ip, uint64_t size);
|
||||
int gfs2_truncatei(struct gfs2_inode *ip, uint64_t size,
|
||||
gfs2_truncator_t truncator);
|
||||
int gfs2_truncatei_resume(struct gfs2_inode *ip);
|
||||
int gfs2_file_dealloc(struct gfs2_inode *ip);
|
||||
|
||||
void gfs2_write_calc_reserv(struct gfs2_inode *ip, unsigned int len,
|
||||
unsigned int *data_blocks,
|
||||
unsigned int *ind_blocks);
|
||||
int gfs2_write_alloc_required(struct gfs2_inode *ip, uint64_t offset,
|
||||
unsigned int len, int *alloc_required);
|
||||
|
||||
int gfs2_get_file_meta(struct gfs2_inode *ip, struct gfs2_user_buffer *ub);
|
||||
|
||||
#endif /* __BMAP_DOT_H__ */
|
||||
225
fs/gfs2/daemon.c
Normal file
225
fs/gfs2/daemon.c
Normal file
@@ -0,0 +1,225 @@
|
||||
/*
|
||||
* 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/kthread.h>
|
||||
#include <linux/delay.h>
|
||||
#include <asm/semaphore.h>
|
||||
|
||||
#include "gfs2.h"
|
||||
#include "daemon.h"
|
||||
#include "glock.h"
|
||||
#include "log.h"
|
||||
#include "quota.h"
|
||||
#include "recovery.h"
|
||||
#include "super.h"
|
||||
#include "unlinked.h"
|
||||
|
||||
/* This uses schedule_timeout() instead of msleep() because it's good for
|
||||
the daemons to wake up more often than the timeout when unmounting so
|
||||
the user's unmount doesn't sit there forever.
|
||||
|
||||
The kthread functions used to start these daemons block and flush signals. */
|
||||
|
||||
/**
|
||||
* gfs2_scand - Look for cached glocks and inodes to toss from memory
|
||||
* @sdp: Pointer to GFS2 superblock
|
||||
*
|
||||
* One of these daemons runs, finding candidates to add to sd_reclaim_list.
|
||||
* See gfs2_glockd()
|
||||
*/
|
||||
|
||||
int gfs2_scand(void *data)
|
||||
{
|
||||
struct gfs2_sbd *sdp = (struct gfs2_sbd *)data;
|
||||
unsigned long t;
|
||||
|
||||
while (!kthread_should_stop()) {
|
||||
gfs2_scand_internal(sdp);
|
||||
t = gfs2_tune_get(sdp, gt_scand_secs) * HZ;
|
||||
schedule_timeout_interruptible(t);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* gfs2_glockd - Reclaim unused glock structures
|
||||
* @sdp: Pointer to GFS2 superblock
|
||||
*
|
||||
* One or more of these daemons run, reclaiming glocks on sd_reclaim_list.
|
||||
* Number of daemons can be set by user, with num_glockd mount option.
|
||||
*/
|
||||
|
||||
int gfs2_glockd(void *data)
|
||||
{
|
||||
struct gfs2_sbd *sdp = (struct gfs2_sbd *)data;
|
||||
DECLARE_WAITQUEUE(wait_chan, current);
|
||||
|
||||
while (!kthread_should_stop()) {
|
||||
while (atomic_read(&sdp->sd_reclaim_count))
|
||||
gfs2_reclaim_glock(sdp);
|
||||
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
add_wait_queue(&sdp->sd_reclaim_wq, &wait_chan);
|
||||
if (!atomic_read(&sdp->sd_reclaim_count) &&
|
||||
!kthread_should_stop())
|
||||
schedule();
|
||||
remove_wait_queue(&sdp->sd_reclaim_wq, &wait_chan);
|
||||
set_current_state(TASK_RUNNING);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* gfs2_recoverd - Recover dead machine's journals
|
||||
* @sdp: Pointer to GFS2 superblock
|
||||
*
|
||||
*/
|
||||
|
||||
int gfs2_recoverd(void *data)
|
||||
{
|
||||
struct gfs2_sbd *sdp = (struct gfs2_sbd *)data;
|
||||
unsigned long t;
|
||||
|
||||
while (!kthread_should_stop()) {
|
||||
gfs2_check_journals(sdp);
|
||||
t = gfs2_tune_get(sdp, gt_recoverd_secs) * HZ;
|
||||
schedule_timeout_interruptible(t);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* gfs2_logd - Update log tail as Active Items get flushed to in-place blocks
|
||||
* @sdp: Pointer to GFS2 superblock
|
||||
*
|
||||
* Also, periodically check to make sure that we're using the most recent
|
||||
* journal index.
|
||||
*/
|
||||
|
||||
int gfs2_logd(void *data)
|
||||
{
|
||||
struct gfs2_sbd *sdp = (struct gfs2_sbd *)data;
|
||||
struct gfs2_holder ji_gh;
|
||||
unsigned long t;
|
||||
|
||||
while (!kthread_should_stop()) {
|
||||
/* Advance the log tail */
|
||||
|
||||
t = sdp->sd_log_flush_time +
|
||||
gfs2_tune_get(sdp, gt_log_flush_secs) * HZ;
|
||||
|
||||
gfs2_ail1_empty(sdp, DIO_ALL);
|
||||
|
||||
if (time_after_eq(jiffies, t)) {
|
||||
gfs2_log_flush(sdp);
|
||||
sdp->sd_log_flush_time = jiffies;
|
||||
}
|
||||
|
||||
/* Check for latest journal index */
|
||||
|
||||
t = sdp->sd_jindex_refresh_time +
|
||||
gfs2_tune_get(sdp, gt_jindex_refresh_secs) * HZ;
|
||||
|
||||
if (time_after_eq(jiffies, t)) {
|
||||
if (!gfs2_jindex_hold(sdp, &ji_gh))
|
||||
gfs2_glock_dq_uninit(&ji_gh);
|
||||
sdp->sd_jindex_refresh_time = jiffies;
|
||||
}
|
||||
|
||||
t = gfs2_tune_get(sdp, gt_logd_secs) * HZ;
|
||||
schedule_timeout_interruptible(t);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* gfs2_quotad - Write cached quota changes into the quota file
|
||||
* @sdp: Pointer to GFS2 superblock
|
||||
*
|
||||
*/
|
||||
|
||||
int gfs2_quotad(void *data)
|
||||
{
|
||||
struct gfs2_sbd *sdp = (struct gfs2_sbd *)data;
|
||||
unsigned long t;
|
||||
int error;
|
||||
|
||||
while (!kthread_should_stop()) {
|
||||
/* Update the master statfs file */
|
||||
|
||||
t = sdp->sd_statfs_sync_time +
|
||||
gfs2_tune_get(sdp, gt_statfs_quantum) * HZ;
|
||||
|
||||
if (time_after_eq(jiffies, t)) {
|
||||
error = gfs2_statfs_sync(sdp);
|
||||
if (error &&
|
||||
error != -EROFS &&
|
||||
!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))
|
||||
fs_err(sdp, "quotad: (1) error=%d\n", error);
|
||||
sdp->sd_statfs_sync_time = jiffies;
|
||||
}
|
||||
|
||||
/* Update quota file */
|
||||
|
||||
t = sdp->sd_quota_sync_time +
|
||||
gfs2_tune_get(sdp, gt_quota_quantum) * HZ;
|
||||
|
||||
if (time_after_eq(jiffies, t)) {
|
||||
error = gfs2_quota_sync(sdp);
|
||||
if (error &&
|
||||
error != -EROFS &&
|
||||
!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))
|
||||
fs_err(sdp, "quotad: (2) error=%d\n", error);
|
||||
sdp->sd_quota_sync_time = jiffies;
|
||||
}
|
||||
|
||||
gfs2_quota_scan(sdp);
|
||||
|
||||
t = gfs2_tune_get(sdp, gt_quotad_secs) * HZ;
|
||||
schedule_timeout_interruptible(t);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* gfs2_inoded - Deallocate unlinked inodes
|
||||
* @sdp: Pointer to GFS2 superblock
|
||||
*
|
||||
*/
|
||||
|
||||
int gfs2_inoded(void *data)
|
||||
{
|
||||
struct gfs2_sbd *sdp = (struct gfs2_sbd *)data;
|
||||
unsigned long t;
|
||||
int error;
|
||||
|
||||
while (!kthread_should_stop()) {
|
||||
error = gfs2_unlinked_dealloc(sdp);
|
||||
if (error &&
|
||||
error != -EROFS &&
|
||||
!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))
|
||||
fs_err(sdp, "inoded: error = %d\n", error);
|
||||
|
||||
t = gfs2_tune_get(sdp, gt_inoded_secs) * HZ;
|
||||
schedule_timeout_interruptible(t);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
20
fs/gfs2/daemon.h
Normal file
20
fs/gfs2/daemon.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __DAEMON_DOT_H__
|
||||
#define __DAEMON_DOT_H__
|
||||
|
||||
int gfs2_scand(void *data);
|
||||
int gfs2_glockd(void *data);
|
||||
int gfs2_recoverd(void *data);
|
||||
int gfs2_logd(void *data);
|
||||
int gfs2_quotad(void *data);
|
||||
int gfs2_inoded(void *data);
|
||||
|
||||
#endif /* __DAEMON_DOT_H__ */
|
||||
2157
fs/gfs2/dir.c
Normal file
2157
fs/gfs2/dir.c
Normal file
File diff suppressed because it is too large
Load Diff
51
fs/gfs2/dir.h
Normal file
51
fs/gfs2/dir.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __DIR_DOT_H__
|
||||
#define __DIR_DOT_H__
|
||||
|
||||
/**
|
||||
* gfs2_filldir_t - Report a directory entry to the caller of gfs2_dir_read()
|
||||
* @opaque: opaque data used by the function
|
||||
* @name: the name of the directory entry
|
||||
* @length: the length of the name
|
||||
* @offset: the entry's offset in the directory
|
||||
* @inum: the inode number the entry points to
|
||||
* @type: the type of inode the entry points to
|
||||
*
|
||||
* Returns: 0 on success, 1 if buffer full
|
||||
*/
|
||||
|
||||
typedef int (*gfs2_filldir_t) (void *opaque,
|
||||
const char *name, unsigned int length,
|
||||
uint64_t offset,
|
||||
struct gfs2_inum *inum, unsigned int type);
|
||||
|
||||
int gfs2_filecmp(struct qstr *file1, char *file2, int len_of_file2);
|
||||
int gfs2_dirent_alloc(struct gfs2_inode *dip, struct buffer_head *bh,
|
||||
int name_len, struct gfs2_dirent **dent_out);
|
||||
|
||||
int gfs2_dir_search(struct gfs2_inode *dip, struct qstr *filename,
|
||||
struct gfs2_inum *inum, unsigned int *type);
|
||||
int gfs2_dir_add(struct gfs2_inode *dip, struct qstr *filename,
|
||||
struct gfs2_inum *inum, unsigned int type);
|
||||
int gfs2_dir_del(struct gfs2_inode *dip, struct qstr *filename);
|
||||
int gfs2_dir_read(struct gfs2_inode *dip, uint64_t * offset, void *opaque,
|
||||
gfs2_filldir_t filldir);
|
||||
int gfs2_dir_mvino(struct gfs2_inode *dip, struct qstr *filename,
|
||||
struct gfs2_inum *new_inum, unsigned int new_type);
|
||||
|
||||
int gfs2_dir_exhash_dealloc(struct gfs2_inode *dip);
|
||||
|
||||
int gfs2_diradd_alloc_required(struct gfs2_inode *dip, struct qstr *filename,
|
||||
int *alloc_required);
|
||||
|
||||
int gfs2_get_dir_meta(struct gfs2_inode *ip, struct gfs2_user_buffer *ub);
|
||||
|
||||
#endif /* __DIR_DOT_H__ */
|
||||
185
fs/gfs2/eaops.c
Normal file
185
fs/gfs2/eaops.c
Normal file
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* 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/xattr.h>
|
||||
#include <asm/semaphore.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#include "gfs2.h"
|
||||
#include "acl.h"
|
||||
#include "eaops.h"
|
||||
#include "eattr.h"
|
||||
|
||||
/**
|
||||
* gfs2_ea_name2type - get the type of the ea, and truncate type from the name
|
||||
* @namep: ea name, possibly with type appended
|
||||
*
|
||||
* Returns: GFS2_EATYPE_XXX
|
||||
*/
|
||||
|
||||
unsigned int gfs2_ea_name2type(const char *name, char **truncated_name)
|
||||
{
|
||||
unsigned int type;
|
||||
|
||||
if (strncmp(name, "system.", 7) == 0) {
|
||||
type = GFS2_EATYPE_SYS;
|
||||
if (truncated_name)
|
||||
*truncated_name = strchr(name, '.') + 1;
|
||||
} else if (strncmp(name, "user.", 5) == 0) {
|
||||
type = GFS2_EATYPE_USR;
|
||||
if (truncated_name)
|
||||
*truncated_name = strchr(name, '.') + 1;
|
||||
} else {
|
||||
type = GFS2_EATYPE_UNUSED;
|
||||
if (truncated_name)
|
||||
*truncated_name = NULL;
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
static int user_eo_get(struct gfs2_inode *ip, struct gfs2_ea_request *er)
|
||||
{
|
||||
struct inode *inode = ip->i_vnode;
|
||||
int error = permission(inode, MAY_READ, NULL);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
return gfs2_ea_get_i(ip, er);
|
||||
}
|
||||
|
||||
static int user_eo_set(struct gfs2_inode *ip, struct gfs2_ea_request *er)
|
||||
{
|
||||
struct inode *inode = ip->i_vnode;
|
||||
|
||||
if (S_ISREG(inode->i_mode) ||
|
||||
(S_ISDIR(inode->i_mode) && !(inode->i_mode & S_ISVTX))) {
|
||||
int error = permission(inode, MAY_WRITE, NULL);
|
||||
if (error)
|
||||
return error;
|
||||
} else
|
||||
return -EPERM;
|
||||
|
||||
return gfs2_ea_set_i(ip, er);
|
||||
}
|
||||
|
||||
static int user_eo_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er)
|
||||
{
|
||||
struct inode *inode = ip->i_vnode;
|
||||
|
||||
if (S_ISREG(inode->i_mode) ||
|
||||
(S_ISDIR(inode->i_mode) && !(inode->i_mode & S_ISVTX))) {
|
||||
int error = permission(inode, MAY_WRITE, NULL);
|
||||
if (error)
|
||||
return error;
|
||||
} else
|
||||
return -EPERM;
|
||||
|
||||
return gfs2_ea_remove_i(ip, er);
|
||||
}
|
||||
|
||||
static int system_eo_get(struct gfs2_inode *ip, struct gfs2_ea_request *er)
|
||||
{
|
||||
if (!GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len) &&
|
||||
!GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len) &&
|
||||
!capable(CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
if (ip->i_sbd->sd_args.ar_posix_acl == 0 &&
|
||||
(GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len) ||
|
||||
GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len)))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
|
||||
|
||||
return gfs2_ea_get_i(ip, er);
|
||||
}
|
||||
|
||||
static int system_eo_set(struct gfs2_inode *ip, struct gfs2_ea_request *er)
|
||||
{
|
||||
int remove = 0;
|
||||
int error;
|
||||
|
||||
if (GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len)) {
|
||||
if (!(er->er_flags & GFS2_ERF_MODE)) {
|
||||
er->er_mode = ip->i_di.di_mode;
|
||||
er->er_flags |= GFS2_ERF_MODE;
|
||||
}
|
||||
error = gfs2_acl_validate_set(ip, 1, er,
|
||||
&remove, &er->er_mode);
|
||||
if (error)
|
||||
return error;
|
||||
error = gfs2_ea_set_i(ip, er);
|
||||
if (error)
|
||||
return error;
|
||||
if (remove)
|
||||
gfs2_ea_remove_i(ip, er);
|
||||
return 0;
|
||||
|
||||
} else if (GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len)) {
|
||||
error = gfs2_acl_validate_set(ip, 0, er,
|
||||
&remove, NULL);
|
||||
if (error)
|
||||
return error;
|
||||
if (!remove)
|
||||
error = gfs2_ea_set_i(ip, er);
|
||||
else {
|
||||
error = gfs2_ea_remove_i(ip, er);
|
||||
if (error == -ENODATA)
|
||||
error = 0;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
static int system_eo_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er)
|
||||
{
|
||||
if (GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len)) {
|
||||
int error = gfs2_acl_validate_remove(ip, 1);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
} else if (GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len)) {
|
||||
int error = gfs2_acl_validate_remove(ip, 0);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
} else
|
||||
return -EPERM;
|
||||
|
||||
return gfs2_ea_remove_i(ip, er);
|
||||
}
|
||||
|
||||
struct gfs2_eattr_operations gfs2_user_eaops = {
|
||||
.eo_get = user_eo_get,
|
||||
.eo_set = user_eo_set,
|
||||
.eo_remove = user_eo_remove,
|
||||
.eo_name = "user",
|
||||
};
|
||||
|
||||
struct gfs2_eattr_operations gfs2_system_eaops = {
|
||||
.eo_get = system_eo_get,
|
||||
.eo_set = system_eo_set,
|
||||
.eo_remove = system_eo_remove,
|
||||
.eo_name = "system",
|
||||
};
|
||||
|
||||
struct gfs2_eattr_operations *gfs2_ea_ops[] = {
|
||||
NULL,
|
||||
&gfs2_user_eaops,
|
||||
&gfs2_system_eaops,
|
||||
};
|
||||
|
||||
30
fs/gfs2/eaops.h
Normal file
30
fs/gfs2/eaops.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __EAOPS_DOT_H__
|
||||
#define __EAOPS_DOT_H__
|
||||
|
||||
struct gfs2_ea_request;
|
||||
|
||||
struct gfs2_eattr_operations {
|
||||
int (*eo_get) (struct gfs2_inode *ip, struct gfs2_ea_request *er);
|
||||
int (*eo_set) (struct gfs2_inode *ip, struct gfs2_ea_request *er);
|
||||
int (*eo_remove) (struct gfs2_inode *ip, struct gfs2_ea_request *er);
|
||||
char *eo_name;
|
||||
};
|
||||
|
||||
unsigned int gfs2_ea_name2type(const char *name, char **truncated_name);
|
||||
|
||||
extern struct gfs2_eattr_operations gfs2_user_eaops;
|
||||
extern struct gfs2_eattr_operations gfs2_system_eaops;
|
||||
|
||||
extern struct gfs2_eattr_operations *gfs2_ea_ops[];
|
||||
|
||||
#endif /* __EAOPS_DOT_H__ */
|
||||
|
||||
1620
fs/gfs2/eattr.c
Normal file
1620
fs/gfs2/eattr.c
Normal file
File diff suppressed because it is too large
Load Diff
90
fs/gfs2/eattr.h
Normal file
90
fs/gfs2/eattr.h
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __EATTR_DOT_H__
|
||||
#define __EATTR_DOT_H__
|
||||
|
||||
#define GFS2_EA_REC_LEN(ea) be32_to_cpu((ea)->ea_rec_len)
|
||||
#define GFS2_EA_DATA_LEN(ea) be32_to_cpu((ea)->ea_data_len)
|
||||
|
||||
#define GFS2_EA_SIZE(ea) \
|
||||
ALIGN(sizeof(struct gfs2_ea_header) + (ea)->ea_name_len + \
|
||||
((GFS2_EA_IS_STUFFED(ea)) ? GFS2_EA_DATA_LEN(ea) : \
|
||||
(sizeof(uint64_t) * (ea)->ea_num_ptrs)), 8)
|
||||
|
||||
#define GFS2_EA_STRLEN(ea) \
|
||||
((((ea)->ea_type == GFS2_EATYPE_USR) ? 5 : 7) + (ea)->ea_name_len + 1)
|
||||
|
||||
#define GFS2_EA_IS_STUFFED(ea) (!(ea)->ea_num_ptrs)
|
||||
#define GFS2_EA_IS_LAST(ea) ((ea)->ea_flags & GFS2_EAFLAG_LAST)
|
||||
|
||||
#define GFS2_EAREQ_SIZE_STUFFED(er) \
|
||||
ALIGN(sizeof(struct gfs2_ea_header) + (er)->er_name_len + (er)->er_data_len, 8)
|
||||
|
||||
#define GFS2_EAREQ_SIZE_UNSTUFFED(sdp, er) \
|
||||
ALIGN(sizeof(struct gfs2_ea_header) + (er)->er_name_len + \
|
||||
sizeof(uint64_t) * DIV_RU((er)->er_data_len, (sdp)->sd_jbsize), 8)
|
||||
|
||||
#define GFS2_EA2NAME(ea) ((char *)((struct gfs2_ea_header *)(ea) + 1))
|
||||
#define GFS2_EA2DATA(ea) (GFS2_EA2NAME(ea) + (ea)->ea_name_len)
|
||||
|
||||
#define GFS2_EA2DATAPTRS(ea) \
|
||||
((uint64_t *)(GFS2_EA2NAME(ea) + ALIGN((ea)->ea_name_len, 8)))
|
||||
|
||||
#define GFS2_EA2NEXT(ea) \
|
||||
((struct gfs2_ea_header *)((char *)(ea) + GFS2_EA_REC_LEN(ea)))
|
||||
|
||||
#define GFS2_EA_BH2FIRST(bh) \
|
||||
((struct gfs2_ea_header *)((bh)->b_data + sizeof(struct gfs2_meta_header)))
|
||||
|
||||
#define GFS2_ERF_MODE 0x80000000
|
||||
|
||||
struct gfs2_ea_request {
|
||||
char *er_name;
|
||||
char *er_data;
|
||||
unsigned int er_name_len;
|
||||
unsigned int er_data_len;
|
||||
unsigned int er_type; /* GFS2_EATYPE_... */
|
||||
int er_flags;
|
||||
mode_t er_mode;
|
||||
};
|
||||
|
||||
struct gfs2_ea_location {
|
||||
struct buffer_head *el_bh;
|
||||
struct gfs2_ea_header *el_ea;
|
||||
struct gfs2_ea_header *el_prev;
|
||||
};
|
||||
|
||||
int gfs2_ea_repack(struct gfs2_inode *ip);
|
||||
|
||||
int gfs2_ea_get_i(struct gfs2_inode *ip, struct gfs2_ea_request *er);
|
||||
int gfs2_ea_set_i(struct gfs2_inode *ip, struct gfs2_ea_request *er);
|
||||
int gfs2_ea_remove_i(struct gfs2_inode *ip, struct gfs2_ea_request *er);
|
||||
|
||||
int gfs2_ea_list(struct gfs2_inode *ip, struct gfs2_ea_request *er);
|
||||
int gfs2_ea_get(struct gfs2_inode *ip, struct gfs2_ea_request *er);
|
||||
int gfs2_ea_set(struct gfs2_inode *ip, struct gfs2_ea_request *er);
|
||||
int gfs2_ea_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er);
|
||||
|
||||
int gfs2_ea_dealloc(struct gfs2_inode *ip);
|
||||
|
||||
int gfs2_get_eattr_meta(struct gfs2_inode *ip, struct gfs2_user_buffer *ub);
|
||||
|
||||
/* Exported to acl.c */
|
||||
|
||||
int gfs2_ea_find(struct gfs2_inode *ip,
|
||||
struct gfs2_ea_request *er,
|
||||
struct gfs2_ea_location *el);
|
||||
int gfs2_ea_get_copy(struct gfs2_inode *ip,
|
||||
struct gfs2_ea_location *el,
|
||||
char *data);
|
||||
int gfs2_ea_acl_chmod(struct gfs2_inode *ip, struct gfs2_ea_location *el,
|
||||
struct iattr *attr, char *data);
|
||||
|
||||
#endif /* __EATTR_DOT_H__ */
|
||||
21
fs/gfs2/format.h
Normal file
21
fs/gfs2/format.h
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __FORMAT_DOT_H__
|
||||
#define __FORMAT_DOT_H__
|
||||
|
||||
static const uint32_t gfs2_old_fs_formats[] = {
|
||||
0
|
||||
};
|
||||
|
||||
static const uint32_t gfs2_old_multihost_formats[] = {
|
||||
0
|
||||
};
|
||||
|
||||
#endif /* __FORMAT_DOT_H__ */
|
||||
62
fs/gfs2/gfs2.h
Normal file
62
fs/gfs2/gfs2.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __GFS2_DOT_H__
|
||||
#define __GFS2_DOT_H__
|
||||
|
||||
#include <linux/gfs2_ondisk.h>
|
||||
|
||||
#include "lm_interface.h"
|
||||
#include "lvb.h"
|
||||
#include "incore.h"
|
||||
#include "util.h"
|
||||
|
||||
enum {
|
||||
NO_CREATE = 0,
|
||||
CREATE = 1,
|
||||
};
|
||||
|
||||
enum {
|
||||
NO_WAIT = 0,
|
||||
WAIT = 1,
|
||||
};
|
||||
|
||||
enum {
|
||||
NO_FORCE = 0,
|
||||
FORCE = 1,
|
||||
};
|
||||
|
||||
/* Divide num by den. Round up if there is a remainder. */
|
||||
#define DIV_RU(num, den) (((num) + (den) - 1) / (den))
|
||||
|
||||
#define GFS2_FAST_NAME_SIZE 8
|
||||
|
||||
#define get_v2sdp(sb) ((struct gfs2_sbd *)(sb)->s_fs_info)
|
||||
#define set_v2sdp(sb, sdp) (sb)->s_fs_info = (sdp)
|
||||
#define get_v2ip(inode) ((struct gfs2_inode *)(inode)->u.generic_ip)
|
||||
#define set_v2ip(inode, ip) (inode)->u.generic_ip = (ip)
|
||||
#define get_v2fp(file) ((struct gfs2_file *)(file)->private_data)
|
||||
#define set_v2fp(file, fp) (file)->private_data = (fp)
|
||||
#define get_v2bd(bh) ((struct gfs2_bufdata *)(bh)->b_private)
|
||||
#define set_v2bd(bh, bd) (bh)->b_private = (bd)
|
||||
#define get_v2db(bh) ((struct gfs2_databuf *)(bh)->b_private)
|
||||
#define set_v2db(bh, db) (bh)->b_private = (db)
|
||||
|
||||
#define get_transaction ((struct gfs2_trans *)(current->journal_info))
|
||||
#define set_transaction(tr) (current->journal_info) = (tr)
|
||||
|
||||
#define get_gl2ip(gl) ((struct gfs2_inode *)(gl)->gl_object)
|
||||
#define set_gl2ip(gl, ip) (gl)->gl_object = (ip)
|
||||
#define get_gl2rgd(gl) ((struct gfs2_rgrpd *)(gl)->gl_object)
|
||||
#define set_gl2rgd(gl, rgd) (gl)->gl_object = (rgd)
|
||||
#define get_gl2gl(gl) ((struct gfs2_glock *)(gl)->gl_object)
|
||||
#define set_gl2gl(gl, gl2) (gl)->gl_object = (gl2)
|
||||
|
||||
#endif /* __GFS2_DOT_H__ */
|
||||
|
||||
2513
fs/gfs2/glock.c
Normal file
2513
fs/gfs2/glock.c
Normal file
File diff suppressed because it is too large
Load Diff
143
fs/gfs2/glock.h
Normal file
143
fs/gfs2/glock.h
Normal file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __GLOCK_DOT_H__
|
||||
#define __GLOCK_DOT_H__
|
||||
|
||||
/* Flags for lock requests; used in gfs2_holder gh_flag field.
|
||||
From lm_interface.h:
|
||||
#define LM_FLAG_TRY 0x00000001
|
||||
#define LM_FLAG_TRY_1CB 0x00000002
|
||||
#define LM_FLAG_NOEXP 0x00000004
|
||||
#define LM_FLAG_ANY 0x00000008
|
||||
#define LM_FLAG_PRIORITY 0x00000010 */
|
||||
|
||||
#define GL_LOCAL_EXCL 0x00000020
|
||||
#define GL_ASYNC 0x00000040
|
||||
#define GL_EXACT 0x00000080
|
||||
#define GL_SKIP 0x00000100
|
||||
#define GL_ATIME 0x00000200
|
||||
#define GL_NOCACHE 0x00000400
|
||||
#define GL_SYNC 0x00000800
|
||||
#define GL_NOCANCEL 0x00001000
|
||||
#define GL_NEVER_RECURSE 0x00002000
|
||||
|
||||
#define GLR_TRYFAILED 13
|
||||
#define GLR_CANCELED 14
|
||||
|
||||
static inline int gfs2_glock_is_locked_by_me(struct gfs2_glock *gl)
|
||||
{
|
||||
struct gfs2_holder *gh;
|
||||
int locked = 0;
|
||||
|
||||
/* Look in glock's list of holders for one with current task as owner */
|
||||
spin_lock(&gl->gl_spin);
|
||||
list_for_each_entry(gh, &gl->gl_holders, gh_list) {
|
||||
if (gh->gh_owner == current) {
|
||||
locked = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock(&gl->gl_spin);
|
||||
|
||||
return locked;
|
||||
}
|
||||
|
||||
static inline int gfs2_glock_is_held_excl(struct gfs2_glock *gl)
|
||||
{
|
||||
return (gl->gl_state == LM_ST_EXCLUSIVE);
|
||||
}
|
||||
|
||||
static inline int gfs2_glock_is_held_dfrd(struct gfs2_glock *gl)
|
||||
{
|
||||
return (gl->gl_state == LM_ST_DEFERRED);
|
||||
}
|
||||
|
||||
static inline int gfs2_glock_is_held_shrd(struct gfs2_glock *gl)
|
||||
{
|
||||
return (gl->gl_state == LM_ST_SHARED);
|
||||
}
|
||||
|
||||
static inline int gfs2_glock_is_blocking(struct gfs2_glock *gl)
|
||||
{
|
||||
int ret;
|
||||
spin_lock(&gl->gl_spin);
|
||||
ret = !list_empty(&gl->gl_waiters2) || !list_empty(&gl->gl_waiters3);
|
||||
spin_unlock(&gl->gl_spin);
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct gfs2_glock *gfs2_glock_find(struct gfs2_sbd *sdp,
|
||||
struct lm_lockname *name);
|
||||
int gfs2_glock_get(struct gfs2_sbd *sdp,
|
||||
uint64_t number, struct gfs2_glock_operations *glops,
|
||||
int create, struct gfs2_glock **glp);
|
||||
void gfs2_glock_hold(struct gfs2_glock *gl);
|
||||
int gfs2_glock_put(struct gfs2_glock *gl);
|
||||
|
||||
void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, int flags,
|
||||
struct gfs2_holder *gh);
|
||||
void gfs2_holder_reinit(unsigned int state, int flags, struct gfs2_holder *gh);
|
||||
void gfs2_holder_uninit(struct gfs2_holder *gh);
|
||||
struct gfs2_holder *gfs2_holder_get(struct gfs2_glock *gl, unsigned int state,
|
||||
int flags, gfp_t gfp_flags);
|
||||
void gfs2_holder_put(struct gfs2_holder *gh);
|
||||
|
||||
void gfs2_glock_xmote_th(struct gfs2_glock *gl, unsigned int state, int flags);
|
||||
void gfs2_glock_drop_th(struct gfs2_glock *gl);
|
||||
|
||||
void gfs2_glmutex_lock(struct gfs2_glock *gl);
|
||||
int gfs2_glmutex_trylock(struct gfs2_glock *gl);
|
||||
void gfs2_glmutex_unlock(struct gfs2_glock *gl);
|
||||
|
||||
int gfs2_glock_nq(struct gfs2_holder *gh);
|
||||
int gfs2_glock_poll(struct gfs2_holder *gh);
|
||||
int gfs2_glock_wait(struct gfs2_holder *gh);
|
||||
void gfs2_glock_dq(struct gfs2_holder *gh);
|
||||
|
||||
void gfs2_glock_prefetch(struct gfs2_glock *gl, unsigned int state, int flags);
|
||||
void gfs2_glock_force_drop(struct gfs2_glock *gl);
|
||||
|
||||
int gfs2_glock_be_greedy(struct gfs2_glock *gl, unsigned int time);
|
||||
|
||||
int gfs2_glock_nq_init(struct gfs2_glock *gl, unsigned int state, int flags,
|
||||
struct gfs2_holder *gh);
|
||||
void gfs2_glock_dq_uninit(struct gfs2_holder *gh);
|
||||
int gfs2_glock_nq_num(struct gfs2_sbd *sdp,
|
||||
uint64_t number, struct gfs2_glock_operations *glops,
|
||||
unsigned int state, int flags, struct gfs2_holder *gh);
|
||||
|
||||
int gfs2_glock_nq_m(unsigned int num_gh, struct gfs2_holder *ghs);
|
||||
void gfs2_glock_dq_m(unsigned int num_gh, struct gfs2_holder *ghs);
|
||||
void gfs2_glock_dq_uninit_m(unsigned int num_gh, struct gfs2_holder *ghs);
|
||||
|
||||
void gfs2_glock_prefetch_num(struct gfs2_sbd *sdp, uint64_t number,
|
||||
struct gfs2_glock_operations *glops,
|
||||
unsigned int state, int flags);
|
||||
|
||||
/* Lock Value Block functions */
|
||||
|
||||
int gfs2_lvb_hold(struct gfs2_glock *gl);
|
||||
void gfs2_lvb_unhold(struct gfs2_glock *gl);
|
||||
void gfs2_lvb_sync(struct gfs2_glock *gl);
|
||||
|
||||
void gfs2_glock_cb(lm_fsdata_t *fsdata, unsigned int type, void *data);
|
||||
|
||||
void gfs2_try_toss_inode(struct gfs2_sbd *sdp, struct gfs2_inum *inum);
|
||||
void gfs2_iopen_go_callback(struct gfs2_glock *gl, unsigned int state);
|
||||
|
||||
void gfs2_glock_schedule_for_reclaim(struct gfs2_glock *gl);
|
||||
void gfs2_reclaim_glock(struct gfs2_sbd *sdp);
|
||||
|
||||
void gfs2_scand_internal(struct gfs2_sbd *sdp);
|
||||
void gfs2_gl_hash_clear(struct gfs2_sbd *sdp, int wait);
|
||||
|
||||
int gfs2_dump_lockstate(struct gfs2_sbd *sdp);
|
||||
|
||||
#endif /* __GLOCK_DOT_H__ */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user