summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorDavid Teigland <teigland@redhat.com>2006-01-16 16:50:04 +0000
committerSteven Whitehouse <swhiteho@redhat.com>2006-01-16 16:50:04 +0000
commitb3b94faa5fe5968827ba0640ee9fba4b3e7f736e (patch)
tree70bd6068b050d2c46e338484f8b03fae4365c6c3 /fs
parentf7825dcf8c7301cfd3724eb40c5b443cc85ab7b8 (diff)
[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>
Diffstat (limited to 'fs')
-rw-r--r--fs/gfs2/Kconfig46
-rw-r--r--fs/gfs2/Makefile44
-rw-r--r--fs/gfs2/acl.c312
-rw-r--r--fs/gfs2/acl.h37
-rw-r--r--fs/gfs2/bits.c178
-rw-r--r--fs/gfs2/bits.h28
-rw-r--r--fs/gfs2/bmap.c1206
-rw-r--r--fs/gfs2/bmap.h39
-rw-r--r--fs/gfs2/daemon.c225
-rw-r--r--fs/gfs2/daemon.h20
-rw-r--r--fs/gfs2/dir.c2157
-rw-r--r--fs/gfs2/dir.h51
-rw-r--r--fs/gfs2/eaops.c185
-rw-r--r--fs/gfs2/eaops.h30
-rw-r--r--fs/gfs2/eattr.c1620
-rw-r--r--fs/gfs2/eattr.h90
-rw-r--r--fs/gfs2/format.h21
-rw-r--r--fs/gfs2/gfs2.h62
-rw-r--r--fs/gfs2/glock.c2513
-rw-r--r--fs/gfs2/glock.h143
-rw-r--r--fs/gfs2/glops.c487
-rw-r--r--fs/gfs2/glops.h23
-rw-r--r--fs/gfs2/incore.h703
-rw-r--r--fs/gfs2/inode.c1805
-rw-r--r--fs/gfs2/inode.h74
-rw-r--r--fs/gfs2/jdata.c382
-rw-r--r--fs/gfs2/jdata.h52
-rw-r--r--fs/gfs2/lm.c235
-rw-r--r--fs/gfs2/lm.h42
-rw-r--r--fs/gfs2/lm_interface.h295
-rw-r--r--fs/gfs2/locking.c192
-rw-r--r--fs/gfs2/log.c659
-rw-r--r--fs/gfs2/log.h68
-rw-r--r--fs/gfs2/lops.c534
-rw-r--r--fs/gfs2/lops.h96
-rw-r--r--fs/gfs2/lvb.c48
-rw-r--r--fs/gfs2/lvb.h28
-rw-r--r--fs/gfs2/main.c103
-rw-r--r--fs/gfs2/meta_io.c876
-rw-r--r--fs/gfs2/meta_io.h88
-rw-r--r--fs/gfs2/mount.c211
-rw-r--r--fs/gfs2/mount.h15
-rw-r--r--fs/gfs2/ondisk.c590
-rw-r--r--fs/gfs2/ops_address.c515
-rw-r--r--fs/gfs2/ops_address.h15
-rw-r--r--fs/gfs2/ops_dentry.c117
-rw-r--r--fs/gfs2/ops_dentry.h15
-rw-r--r--fs/gfs2/ops_export.c310
-rw-r--r--fs/gfs2/ops_export.h15
-rw-r--r--fs/gfs2/ops_file.c1597
-rw-r--r--fs/gfs2/ops_file.h16
-rw-r--r--fs/gfs2/ops_fstype.c879
-rw-r--r--fs/gfs2/ops_fstype.h15
-rw-r--r--fs/gfs2/ops_inode.c1265
-rw-r--r--fs/gfs2/ops_inode.h18
-rw-r--r--fs/gfs2/ops_super.c401
-rw-r--r--fs/gfs2/ops_super.h15
-rw-r--r--fs/gfs2/ops_vm.c199
-rw-r--r--fs/gfs2/ops_vm.h16
-rw-r--r--fs/gfs2/page.c273
-rw-r--r--fs/gfs2/page.h23
-rw-r--r--fs/gfs2/quota.c1238
-rw-r--r--fs/gfs2/quota.h34
-rw-r--r--fs/gfs2/recovery.c570
-rw-r--r--fs/gfs2/recovery.h32
-rw-r--r--fs/gfs2/resize.c291
-rw-r--r--fs/gfs2/resize.h19
-rw-r--r--fs/gfs2/rgrp.c1361
-rw-r--r--fs/gfs2/rgrp.h62
-rw-r--r--fs/gfs2/super.c944
-rw-r--r--fs/gfs2/super.h55
-rw-r--r--fs/gfs2/sys.c640
-rw-r--r--fs/gfs2/sys.h24
-rw-r--r--fs/gfs2/trans.c214
-rw-r--r--fs/gfs2/trans.h40
-rw-r--r--fs/gfs2/unlinked.c453
-rw-r--r--fs/gfs2/unlinked.h25
-rw-r--r--fs/gfs2/util.c273
-rw-r--r--fs/gfs2/util.h180
79 files changed, 28772 insertions, 0 deletions
diff --git a/fs/gfs2/Kconfig b/fs/gfs2/Kconfig
new file mode 100644
index 000000000000..17cb44bea1c0
--- /dev/null
+++ b/fs/gfs2/Kconfig
@@ -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.
+
diff --git a/fs/gfs2/Makefile b/fs/gfs2/Makefile
new file mode 100644
index 000000000000..b1bac4f199db
--- /dev/null
+++ b/fs/gfs2/Makefile
@@ -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/
+
diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c
new file mode 100644
index 000000000000..33c465a2ab53
--- /dev/null
+++ b/fs/gfs2/acl.c
@@ -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;
+}
+
diff --git a/fs/gfs2/acl.h b/fs/gfs2/acl.h
new file mode 100644
index 000000000000..a174b4f6bcc2
--- /dev/null
+++ b/fs/gfs2/acl.h
@@ -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__ */
diff --git a/fs/gfs2/bits.c b/fs/gfs2/bits.c
new file mode 100644
index 000000000000..57d420a86adf
--- /dev/null
+++ b/fs/gfs2/bits.c
@@ -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) {