aboutsummaryrefslogtreecommitdiff
path: root/sys/gnu/fs/reiserfs
diff options
context:
space:
mode:
authorJean-Sébastien Pédron <dumbbell@FreeBSD.org>2005-06-18 17:10:50 +0000
committerJean-Sébastien Pédron <dumbbell@FreeBSD.org>2005-06-18 17:10:50 +0000
commitd6d3f5ac42522f52e90791ccc99cb54f53e41307 (patch)
treec098f3ed0a96017bac6283248e8dcc6e9dd9f895 /sys/gnu/fs/reiserfs
parentbecbf981db1df1d4536dde255123dc1dc9fa8a06 (diff)
downloadsrc-d6d3f5ac42522f52e90791ccc99cb54f53e41307.tar.gz
src-d6d3f5ac42522f52e90791ccc99cb54f53e41307.zip
Moving reiserfs from sys/gnu to sys/gnu/fs. This was discussed on arch@.
Reviewed by: mux (mentor) Approved by: re (scottl)
Notes
Notes: svn path=/head/; revision=147476
Diffstat (limited to 'sys/gnu/fs/reiserfs')
-rw-r--r--sys/gnu/fs/reiserfs/README163
-rw-r--r--sys/gnu/fs/reiserfs/reiserfs_fs.h1298
-rw-r--r--sys/gnu/fs/reiserfs/reiserfs_fs_i.h90
-rw-r--r--sys/gnu/fs/reiserfs/reiserfs_fs_sb.h143
-rw-r--r--sys/gnu/fs/reiserfs/reiserfs_hashes.c217
-rw-r--r--sys/gnu/fs/reiserfs/reiserfs_inode.c926
-rw-r--r--sys/gnu/fs/reiserfs/reiserfs_item_ops.c158
-rw-r--r--sys/gnu/fs/reiserfs/reiserfs_mount.h47
-rw-r--r--sys/gnu/fs/reiserfs/reiserfs_namei.c699
-rw-r--r--sys/gnu/fs/reiserfs/reiserfs_prints.c307
-rw-r--r--sys/gnu/fs/reiserfs/reiserfs_stree.c760
-rw-r--r--sys/gnu/fs/reiserfs/reiserfs_vfsops.c1186
-rw-r--r--sys/gnu/fs/reiserfs/reiserfs_vnops.c353
13 files changed, 6347 insertions, 0 deletions
diff --git a/sys/gnu/fs/reiserfs/README b/sys/gnu/fs/reiserfs/README
new file mode 100644
index 000000000000..f3917c1be08a
--- /dev/null
+++ b/sys/gnu/fs/reiserfs/README
@@ -0,0 +1,163 @@
+$FreeBSD$
+
+[LICENSING]
+
+ReiserFS is hereby licensed under the GNU General
+Public License version 2.
+
+Source code files that contain the phrase "licensing governed by
+reiserfs/README" are "governed files" throughout this file. Governed
+files are licensed under the GPL. The portions of them owned by Hans
+Reiser, or authorized to be licensed by him, have been in the past,
+and likely will be in the future, licensed to other parties under
+other licenses. If you add your code to governed files, and don't
+want it to be owned by Hans Reiser, put your copyright label on that
+code so the poor blight and his customers can keep things straight.
+All portions of governed files not labeled otherwise are owned by Hans
+Reiser, and by adding your code to it, widely distributing it to
+others or sending us a patch, and leaving the sentence in stating that
+licensing is governed by the statement in this file, you accept this.
+It will be a kindness if you identify whether Hans Reiser is allowed
+to license code labeled as owned by you on your behalf other than
+under the GPL, because he wants to know if it is okay to do so and put
+a check in the mail to you (for non-trivial improvements) when he
+makes his next sale. He makes no guarantees as to the amount if any,
+though he feels motivated to motivate contributors, and you can surely
+discuss this with him before or after contributing. You have the
+right to decline to allow him to license your code contribution other
+than under the GPL.
+
+Further licensing options are available for commercial and/or other
+interests directly from Hans Reiser: hans@reiser.to. If you interpret
+the GPL as not allowing those additional licensing options, you read
+it wrongly, and Richard Stallman agrees with me, when carefully read
+you can see that those restrictions on additional terms do not apply
+to the owner of the copyright, and my interpretation of this shall
+govern for this license.
+
+Finally, nothing in this license shall be interpreted to allow you to
+fail to fairly credit me, or to remove my credits, without my
+permission, unless you are an end user not redistributing to others.
+If you have doubts about how to properly do that, or about what is
+fair, ask. (Last I spoke with him Richard was contemplating how best
+to address the fair crediting issue in the next GPL version.)
+
+[END LICENSING]
+
+Reiserfs is a file system based on balanced tree algorithms, which is
+described at http://devlinux.com/namesys.
+
+Stop reading here. Go there, then return.
+
+Send bug reports to yura@namesys.botik.ru.
+
+mkreiserfs and other utilities are in reiserfs/utils, or wherever your
+Linux provider put them. There is some disagreement about how useful
+it is for users to get their fsck and mkreiserfs out of sync with the
+version of reiserfs that is in their kernel, with many important
+distributors wanting them out of sync.:-) Please try to remember to
+recompile and reinstall fsck and mkreiserfs with every update of
+reiserfs, this is a common source of confusion. Note that some of the
+utilities cannot be compiled without accessing the balancing code
+which is in the kernel code, and relocating the utilities may require
+you to specify where that code can be found.
+
+Yes, if you update your reiserfs kernel module you do have to
+recompile your kernel, most of the time. The errors you get will be
+quite cryptic if your forget to do so.
+
+Real users, as opposed to folks who want to hack and then understand
+what went wrong, will want REISERFS_CHECK off.
+
+Hideous Commercial Pitch: Spread your development costs across other OS
+vendors. Select from the best in the world, not the best in your
+building, by buying from third party OS component suppliers. Leverage
+the software component development power of the internet. Be the most
+aggressive in taking advantage of the commercial possibilities of
+decentralized internet development, and add value through your branded
+integration that you sell as an operating system. Let your competitors
+be the ones to compete against the entire internet by themselves. Be
+hip, get with the new economic trend, before your competitors do. Send
+email to hans@reiser.to.
+
+To understand the code, after reading the website, start reading the
+code by reading reiserfs_fs.h first.
+
+Hans Reiser was the project initiator, primary architect, source of all
+funding for the first 5.5 years, and one of the programmers. He owns
+the copyright.
+
+Vladimir Saveljev was one of the programmers, and he worked long hours
+writing the cleanest code. He always made the effort to be the best he
+could be, and to make his code the best that it could be. What resulted
+was quite remarkable. I don't think that money can ever motivate someone
+to work the way he did, he is one of the most selfless men I know.
+
+Yura helps with benchmarking, coding hashes, and block pre-allocation
+code.
+
+Anatoly Pinchuk is a former member of our team who worked closely with
+Vladimir throughout the project's development. He wrote a quite
+substantial portion of the total code. He realized that there was a
+space problem with packing tails of files for files larger than a node
+that start on a node aligned boundary (there are reasons to want to node
+align files), and he invented and implemented indirect items and
+unformatted nodes as the solution.
+
+Konstantin Shvachko, with the help of the Russian version of a VC,
+tried to put me in a position where I was forced into giving control
+of the project to him. (Fortunately, as the person paying the money
+for all salaries from my dayjob I owned all copyrights, and you can't
+really force takeovers of sole proprietorships.) This was something
+curious, because he never really understood the value of our project,
+why we should do what we do, or why innovation was possible in
+general, but he was sure that he ought to be controlling it. Every
+innovation had to be forced past him while he was with us. He added
+two years to the time required to complete reiserfs, and was a net
+loss for me. Mikhail Gilula was a brilliant innovator who also left
+in a destructive way that erased the value of his contributions, and
+that he was shown much generosity just makes it more painful.
+
+Grigory Zaigralin was an extremely effective system administrator for
+our group.
+
+Igor Krasheninnikov was wonderful at hardware procurement, repair, and
+network installation.
+
+Jeremy Fitzhardinge wrote the teahash.c code, and he gives credit to a
+textbook he got the algorithm from in the code. Note that his analysis
+of how we could use the hashing code in making 32 bit NFS cookies work
+was probably more important than the actual algorithm. Colin Plumb also
+contributed to it.
+
+Chris Mason dived right into our code, and in just a few months produced
+the journaling code that dramatically increased the value of ReiserFS.
+He is just an amazing programmer.
+
+Igor Zagorovsky is writing much of the new item handler and extent code
+for our next major release.
+
+Alexander Zarochentcev (sometimes known as zam, or sasha), wrote the
+resizer, and is hard at work on implementing allocate on flush. SGI
+implemented allocate on flush before us for XFS, and generously took
+the time to convince me we should do it also. They are great people,
+and a great company.
+
+Yuri Shevchuk and Nikita Danilov are doing squid cache optimization.
+
+Vitaly Fertman is doing fsck.
+
+Jeff Mahoney, of SuSE, contributed a few cleanup fixes, most notably
+the endian safe patches which allow ReiserFS to run on any platform
+supported by the Linux kernel.
+
+SuSE, IntegratedLinux.com, Ecila, MP3.com, bigstorage.com, and the
+Alpha PC Company made it possible for me to not have a day job
+anymore, and to dramatically increase our staffing. Ecila funded
+hypertext feature development, MP3.com funded journaling, SuSE funded
+core development, IntegratedLinux.com funded squid web cache
+appliances, bigstorage.com funded HSM, and the alpha PC company funded
+the alpha port. Many of these tasks were helped by sponsors other
+than the ones just named. SuSE has helped in much more than just
+funding....
+
diff --git a/sys/gnu/fs/reiserfs/reiserfs_fs.h b/sys/gnu/fs/reiserfs/reiserfs_fs.h
new file mode 100644
index 000000000000..d1b923306e5a
--- /dev/null
+++ b/sys/gnu/fs/reiserfs/reiserfs_fs.h
@@ -0,0 +1,1298 @@
+/*-
+ * Copyright 2000 Hans Reiser
+ * See README for licensing and copyright details
+ *
+ * Ported to FreeBSD by Jean-Sébastien Pédron <jspedron@club-internet.fr>
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _GNU_REISERFS_REISERFS_FS_H
+#define _GNU_REISERFS_REISERFS_FS_H
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <sys/endian.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/mount.h>
+#include <sys/namei.h>
+#include <sys/proc.h>
+#include <sys/vnode.h>
+#include <sys/unistd.h>
+
+#include <sys/bio.h>
+#include <sys/buf.h>
+#include <sys/conf.h>
+#include <sys/fcntl.h>
+#include <sys/syslog.h>
+
+#include <sys/malloc.h>
+#include <sys/dirent.h>
+#include <sys/stat.h>
+//#include <sys/mutex.h>
+
+#include <sys/ctype.h>
+#include <sys/bitstring.h>
+
+#include <geom/geom.h>
+#include <geom/geom_vfs.h>
+
+#ifdef __i386__
+# include <gnu/fs/ext2fs/i386-bitops.h>
+#else
+# include <gnu/fs/ext2fs/ext2_bitops.h>
+#endif
+
+#include <gnu/fs/reiserfs/reiserfs_mount.h>
+#include <gnu/fs/reiserfs/reiserfs_fs_sb.h>
+#include <gnu/fs/reiserfs/reiserfs_fs_i.h>
+
+/* n must be power of 2 */
+#define _ROUND_UP(x, n) (((x) + (n) - 1u) & ~((n) - 1u))
+
+/* To be ok for alpha and others we have to align structures to 8 byte
+ * boundary. */
+#define ROUND_UP(x) _ROUND_UP(x, 8LL)
+
+/* -------------------------------------------------------------------
+ * Global variables
+ * -------------------------------------------------------------------*/
+
+extern struct vop_vector reiserfs_vnodeops;
+extern struct vop_vector reiserfs_specops;
+
+/* -------------------------------------------------------------------
+ * Super block
+ * -------------------------------------------------------------------*/
+
+#define REISERFS_BSIZE 1024
+
+/* ReiserFS leaves the first 64k unused, so that partition labels have
+ * enough space. If someone wants to write a fancy bootloader that needs
+ * more than 64k, let us know, and this will be increased in size.
+ * This number must be larger than than the largest block size on any
+ * platform, or code will break. -Hans */
+#define REISERFS_DISK_OFFSET 64
+#define REISERFS_DISK_OFFSET_IN_BYTES \
+ ((REISERFS_DISK_OFFSET) * (REISERFS_BSIZE))
+
+/* The spot for the super in versions 3.5 - 3.5.10 (inclusive) */
+#define REISERFS_OLD_DISK_OFFSET 8
+#define REISERFS_OLD_DISK_OFFSET_IN_BYTES \
+ ((REISERFS_OLD_DISK_OFFSET) * (REISERFS_BSIZE))
+
+/*
+ * Structure of a super block on disk, a version of which in RAM is
+ * often accessed as REISERFS_SB(s)->r_rs. The version in RAM is part of
+ * a larger structure containing fields never written to disk.
+ */
+
+#define UNSET_HASH 0 /* read_super will guess about, what hash names
+ in directories were sorted with */
+#define TEA_HASH 1
+#define YURA_HASH 2
+#define R5_HASH 3
+#define DEFAULT_HASH R5_HASH
+
+struct journal_params {
+ uint32_t jp_journal_1st_block; /* Where does journal start
+ from on its device */
+ uint32_t jp_journal_dev; /* Journal device st_rdev */
+ uint32_t jp_journal_size; /* Size of the journal */
+ uint32_t jp_journal_trans_max; /* Max number of blocks in
+ a transaction */
+ uint32_t jp_journal_magic; /* Random value made on
+ fs creation (this was
+ sb_journal_block_count) */
+ uint32_t jp_journal_max_batch; /* Max number of blocks to
+ batch into a
+ transaction */
+ uint32_t jp_journal_max_commit_age; /* In seconds, how old can
+ an async commit be */
+ uint32_t jp_journal_max_trans_age; /* In seconds, how old a
+ transaction be */
+};
+
+struct reiserfs_super_block_v1 {
+ uint32_t s_block_count; /* Blocks count */
+ uint32_t s_free_blocks; /* Free blocks count */
+ uint32_t s_root_block; /* Root block number */
+
+ struct journal_params s_journal;
+
+ uint16_t s_blocksize;
+ uint16_t s_oid_maxsize;
+ uint16_t s_oid_cursize;
+ uint16_t s_umount_state;
+
+ char s_magic[10];
+
+ uint16_t s_fs_state;
+ uint32_t s_hash_function_code;
+ uint16_t s_tree_height;
+ uint16_t s_bmap_nr;
+ uint16_t s_version;
+ uint16_t s_reserved_for_journal;
+} __packed;
+
+#define SB_SIZE_V1 (sizeof(struct reiserfs_super_block_v1))
+
+struct reiserfs_super_block {
+ struct reiserfs_super_block_v1 s_v1;
+ uint32_t s_inode_generation;
+ uint32_t s_flags;
+ unsigned char s_uuid[16];
+ unsigned char s_label[16];
+ char s_unused[88];
+} __packed;
+
+#define SB_SIZE (sizeof(struct reiserfs_super_block))
+
+#define REISERFS_VERSION_1 0
+#define REISERFS_VERSION_2 2
+
+#define REISERFS_SB(sbi) (sbi)
+#define SB_DISK_SUPER_BLOCK(sbi) (REISERFS_SB(sbi)->s_rs)
+#define SB_V1_DISK_SUPER_BLOCK(sbi) (&(SB_DISK_SUPER_BLOCK(sbi)->s_v1))
+
+#define SB_BLOCKSIZE(sbi) \
+ le32toh((SB_V1_DISK_SUPER_BLOCK(sbi)->s_blocksize))
+#define SB_BLOCK_COUNT(sbi) \
+ le32toh((SB_V1_DISK_SUPER_BLOCK(sbi)->s_block_count))
+#define SB_FREE_BLOCKS(s) \
+ le32toh((SB_V1_DISK_SUPER_BLOCK(sbi)->s_free_blocks))
+
+#define SB_REISERFS_MAGIC(sbi) \
+ (SB_V1_DISK_SUPER_BLOCK(sbi)->s_magic)
+
+#define SB_ROOT_BLOCK(sbi) \
+ le32toh((SB_V1_DISK_SUPER_BLOCK(sbi)->s_root_block))
+
+#define SB_TREE_HEIGHT(sbi) \
+ le16toh((SB_V1_DISK_SUPER_BLOCK(sbi)->s_tree_height))
+
+#define SB_REISERFS_STATE(sbi) \
+ le16toh((SB_V1_DISK_SUPER_BLOCK(sbi)->s_umount_state))
+
+#define SB_VERSION(sbi) le16toh((SB_V1_DISK_SUPER_BLOCK(sbi)->s_version))
+#define SB_BMAP_NR(sbi) le16toh((SB_V1_DISK_SUPER_BLOCK(sbi)->s_bmap_nr))
+
+#define REISERFS_SUPER_MAGIC_STRING "ReIsErFs"
+#define REISER2FS_SUPER_MAGIC_STRING "ReIsEr2Fs"
+#define REISER2FS_JR_SUPER_MAGIC_STRING "ReIsEr3Fs"
+
+extern const char reiserfs_3_5_magic_string[];
+extern const char reiserfs_3_6_magic_string[];
+extern const char reiserfs_jr_magic_string[];
+
+int is_reiserfs_3_5(struct reiserfs_super_block *rs);
+int is_reiserfs_3_6(struct reiserfs_super_block *rs);
+int is_reiserfs_jr(struct reiserfs_super_block *rs);
+
+/* ReiserFS internal error code (used by search_by_key and fix_nodes) */
+#define IO_ERROR -2
+
+typedef uint32_t b_blocknr_t;
+typedef uint32_t unp_t;
+
+struct unfm_nodeinfo {
+ unp_t unfm_nodenum;
+ unsigned short unfm_freespace;
+};
+
+/* There are two formats of keys: 3.5 and 3.6 */
+#define KEY_FORMAT_3_5 0
+#define KEY_FORMAT_3_6 1
+
+/* There are two stat datas */
+#define STAT_DATA_V1 0
+#define STAT_DATA_V2 1
+
+#define REISERFS_I(ip) (ip)
+
+#define get_inode_item_key_version(ip) \
+ ((REISERFS_I(ip)->i_flags & i_item_key_version_mask) ? \
+ KEY_FORMAT_3_6 : KEY_FORMAT_3_5)
+
+#define set_inode_item_key_version(ip, version) ({ \
+ if ((version) == KEY_FORMAT_3_6) \
+ REISERFS_I(ip)->i_flags |= i_item_key_version_mask; \
+ else \
+ REISERFS_I(ip)->i_flags &= ~i_item_key_version_mask; \
+})
+
+#define get_inode_sd_version(ip) \
+ ((REISERFS_I(ip)->i_flags & i_stat_data_version_mask) ? \
+ STAT_DATA_V2 : STAT_DATA_V1)
+
+#define set_inode_sd_version(inode, version) ({ \
+ if((version) == STAT_DATA_V2) \
+ REISERFS_I(ip)->i_flags |= i_stat_data_version_mask; \
+ else \
+ REISERFS_I(ip)->i_flags &= ~i_stat_data_version_mask; \
+})
+
+/* Values for s_umount_state field */
+#define REISERFS_VALID_FS 1
+#define REISERFS_ERROR_FS 2
+
+/* There are 5 item types currently */
+#define TYPE_STAT_DATA 0
+#define TYPE_INDIRECT 1
+#define TYPE_DIRECT 2
+#define TYPE_DIRENTRY 3
+#define TYPE_MAXTYPE 3
+#define TYPE_ANY 15
+
+/* -------------------------------------------------------------------
+ * Key & item head
+ * -------------------------------------------------------------------*/
+
+struct offset_v1 {
+ uint32_t k_offset;
+ uint32_t k_uniqueness;
+} __packed;
+
+struct offset_v2 {
+#if BYTE_ORDER == LITTLE_ENDIAN
+ /* little endian version */
+ uint64_t k_offset:60;
+ uint64_t k_type:4;
+#else
+ /* big endian version */
+ uint64_t k_type:4;
+ uint64_t k_offset:60;
+#endif
+} __packed;
+
+#if (BYTE_ORDER == BIG_ENDIAN)
+typedef union {
+ struct offset_v2 offset_v2;
+ uint64_t linear;
+} __packed offset_v2_esafe_overlay;
+
+static inline uint16_t
+offset_v2_k_type(const struct offset_v2 *v2)
+{
+
+ offset_v2_esafe_overlay tmp = *(const offset_v2_esafe_overlay *)v2;
+ tmp.linear = le64toh(tmp.linear);
+ return ((tmp.offset_v2.k_type <= TYPE_MAXTYPE) ?
+ tmp.offset_v2.k_type : TYPE_ANY);
+}
+
+static inline void
+set_offset_v2_k_type(struct offset_v2 *v2, int type)
+{
+
+ offset_v2_esafe_overlay *tmp = (offset_v2_esafe_overlay *)v2;
+ tmp->linear = le64toh(tmp->linear);
+ tmp->offset_v2.k_type = type;
+ tmp->linear = htole64(tmp->linear);
+}
+
+static inline off_t
+offset_v2_k_offset(const struct offset_v2 *v2)
+{
+
+ offset_v2_esafe_overlay tmp = *(const offset_v2_esafe_overlay *)v2;
+ tmp.linear = le64toh(tmp.linear);
+ return (tmp.offset_v2.k_offset);
+}
+
+static inline void
+set_offset_v2_k_offset(struct offset_v2 *v2, off_t offset)
+{
+
+ offset_v2_esafe_overlay *tmp = (offset_v2_esafe_overlay *)v2;
+ tmp->linear = le64toh(tmp->linear);
+ tmp->offset_v2.k_offset = offset;
+ tmp->linear = htole64(tmp->linear);
+}
+#else /* BYTE_ORDER != BIG_ENDIAN */
+#define offset_v2_k_type(v2) ((v2)->k_type)
+#define set_offset_v2_k_type(v2, val) (offset_v2_k_type(v2) = (val))
+#define offset_v2_k_offset(v2) ((v2)->k_offset)
+#define set_offset_v2_k_offset(v2, val) (offset_v2_k_offset(v2) = (val))
+#endif /* BYTE_ORDER == BIG_ENDIAN */
+
+/*
+ * Key of an item determines its location in the S+tree, and
+ * is composed of 4 components
+ */
+struct key {
+ uint32_t k_dir_id; /* Packing locality: by default parent
+ directory object id */
+ uint32_t k_objectid; /* Object identifier */
+ union {
+ struct offset_v1 k_offset_v1;
+ struct offset_v2 k_offset_v2;
+ } __packed u;
+} __packed;
+
+struct cpu_key {
+ struct key on_disk_key;
+ int version;
+ int key_length; /* 3 in all cases but direct2indirect
+ and indirect2direct conversion */
+};
+
+/*
+ * Our function for comparing keys can compare keys of different
+ * lengths. It takes as a parameter the length of the keys it is to
+ * compare. These defines are used in determining what is to be passed
+ * to it as that parameter.
+ */
+#define REISERFS_FULL_KEY_LEN 4
+#define REISERFS_SHORT_KEY_LEN 2
+
+#define KEY_SIZE (sizeof(struct key))
+#define SHORT_KEY_SIZE (sizeof(uint32_t) + sizeof(uint32_t))
+
+/* Return values for search_by_key and clones */
+#define ITEM_FOUND 1
+#define ITEM_NOT_FOUND 0
+#define ENTRY_FOUND 1
+#define ENTRY_NOT_FOUND 0
+#define DIRECTORY_NOT_FOUND -1
+#define REGULAR_FILE_FOUND -2
+#define DIRECTORY_FOUND -3
+#define BYTE_FOUND 1
+#define BYTE_NOT_FOUND 0
+#define FILE_NOT_FOUND -1
+
+#define POSITION_FOUND 1
+#define POSITION_NOT_FOUND 0
+
+/* Return values for reiserfs_find_entry and search_by_entry_key */
+#define NAME_FOUND 1
+#define NAME_NOT_FOUND 0
+#define GOTO_PREVIOUS_ITEM 2
+#define NAME_FOUND_INVISIBLE 3
+
+/*
+ * Everything in the filesystem is stored as a set of items. The item
+ * head contains the key of the item, its free space (for indirect
+ * items) and specifies the location of the item itself within the
+ * block.
+ */
+struct item_head {
+ /*
+ * Everything in the tree is found by searching for it based on
+ * its key.
+ */
+ struct key ih_key;
+ union {
+ /*
+ * The free space in the last unformatted node of an
+ * indirect item if this is an indirect item. This
+ * equals 0xFFFF iff this is a direct item or stat data
+ * item. Note that the key, not this field, is used to
+ * determine the item type, and thus which field this
+ * union contains.
+ */
+ uint16_t ih_free_space_reserved;
+
+ /*
+ * If this is a directory item, this field equals the number of
+ * directory entries in the directory item.
+ */
+ uint16_t ih_entry_count;
+ } __packed u;
+ uint16_t ih_item_len; /* Total size of the item body */
+ uint16_t ih_item_location; /* An offset to the item body within
+ the block */
+ uint16_t ih_version; /* 0 for all old items, 2 for new
+ ones. Highest bit is set by fsck
+ temporary, cleaned after all
+ done */
+} __packed;
+
+/* Size of item header */
+#define IH_SIZE (sizeof(struct item_head))
+
+#define ih_free_space(ih) le16toh((ih)->u.ih_free_space_reserved)
+#define ih_version(ih) le16toh((ih)->ih_version)
+#define ih_entry_count(ih) le16toh((ih)->u.ih_entry_count)
+#define ih_location(ih) le16toh((ih)->ih_item_location)
+#define ih_item_len(ih) le16toh((ih)->ih_item_len)
+
+/*
+ * These operate on indirect items, where you've got an array of ints at
+ * a possibly unaligned location. These are a noop on IA32.
+ *
+ * p is the array of uint32_t, i is the index into the array, v is the
+ * value to store there.
+ */
+#define get_unaligned(ptr) \
+ ({ __typeof__(*(ptr)) __tmp; \
+ memcpy(&__tmp, (ptr), sizeof(*(ptr))); __tmp; })
+
+#define put_unaligned(val, ptr) \
+ ({ __typeof__(*(ptr)) __tmp = (val); \
+ memcpy((ptr), &__tmp, sizeof(*(ptr))); \
+ (void)0; })
+
+#define get_block_num(p, i) le32toh(get_unaligned((p) + (i)))
+#define put_block_num(p, i, v) put_unaligned(htole32(v), (p) + (i))
+
+/* In old version uniqueness field shows key type */
+#define V1_SD_UNIQUENESS 0
+#define V1_INDIRECT_UNIQUENESS 0xfffffffe
+#define V1_DIRECT_UNIQUENESS 0xffffffff
+#define V1_DIRENTRY_UNIQUENESS 500
+#define V1_ANY_UNIQUENESS 555
+
+/* Here are conversion routines */
+static inline int uniqueness2type(uint32_t uniqueness);
+static inline uint32_t type2uniqueness(int type);
+
+static inline int
+uniqueness2type(uint32_t uniqueness)
+{
+
+ switch ((int)uniqueness) {
+ case V1_SD_UNIQUENESS:
+ return (TYPE_STAT_DATA);
+ case V1_INDIRECT_UNIQUENESS:
+ return (TYPE_INDIRECT);
+ case V1_DIRECT_UNIQUENESS:
+ return (TYPE_DIRECT);
+ case V1_DIRENTRY_UNIQUENESS:
+ return (TYPE_DIRENTRY);
+ default:
+ log(LOG_NOTICE, "reiserfs: unknown uniqueness (%u)\n",
+ uniqueness);
+ case V1_ANY_UNIQUENESS:
+ return (TYPE_ANY);
+ }
+}
+
+static inline uint32_t
+type2uniqueness(int type)
+{
+
+ switch (type) {
+ case TYPE_STAT_DATA:
+ return (V1_SD_UNIQUENESS);
+ case TYPE_INDIRECT:
+ return (V1_INDIRECT_UNIQUENESS);
+ case TYPE_DIRECT:
+ return (V1_DIRECT_UNIQUENESS);
+ case TYPE_DIRENTRY:
+ return (V1_DIRENTRY_UNIQUENESS);
+ default:
+ log(LOG_NOTICE, "reiserfs: unknown type (%u)\n", type);
+ case TYPE_ANY:
+ return (V1_ANY_UNIQUENESS);
+ }
+}
+
+/*
+ * Key is pointer to on disk key which is stored in le, result is cpu,
+ * there is no way to get version of object from key, so, provide
+ * version to these defines.
+ */
+static inline off_t
+le_key_k_offset(int version, const struct key *key)
+{
+
+ return ((version == KEY_FORMAT_3_5) ?
+ le32toh(key->u.k_offset_v1.k_offset) :
+ offset_v2_k_offset(&(key->u.k_offset_v2)));
+}
+
+static inline off_t
+le_ih_k_offset(const struct item_head *ih)
+{
+
+ return (le_key_k_offset(ih_version(ih), &(ih->ih_key)));
+}
+
+static inline off_t
+le_key_k_type(int version, const struct key *key)
+{
+
+ return ((version == KEY_FORMAT_3_5) ?
+ uniqueness2type(le32toh(key->u.k_offset_v1.k_uniqueness)) :
+ offset_v2_k_type(&(key->u.k_offset_v2)));
+}
+
+static inline off_t
+le_ih_k_type(const struct item_head *ih)
+{
+ return (le_key_k_type(ih_version(ih), &(ih->ih_key)));
+}
+
+static inline void
+set_le_key_k_offset(int version, struct key *key, off_t offset)
+{
+
+ (version == KEY_FORMAT_3_5) ?
+ (key->u.k_offset_v1.k_offset = htole32(offset)) :
+ (set_offset_v2_k_offset(&(key->u.k_offset_v2), offset));
+}
+
+static inline void
+set_le_ih_k_offset(struct item_head *ih, off_t offset)
+{
+
+ set_le_key_k_offset(ih_version(ih), &(ih->ih_key), offset);
+}
+
+static inline void
+set_le_key_k_type(int version, struct key *key, int type)
+{
+
+ (version == KEY_FORMAT_3_5) ?
+ (key->u.k_offset_v1.k_uniqueness =
+ htole32(type2uniqueness(type))) :
+ (set_offset_v2_k_type(&(key->u.k_offset_v2), type));
+}
+
+static inline void
+set_le_ih_k_type(struct item_head *ih, int type)
+{
+
+ set_le_key_k_type(ih_version(ih), &(ih->ih_key), type);
+}
+
+#define is_direntry_le_key(version, key) \
+ (le_key_k_type(version, key) == TYPE_DIRENTRY)
+#define is_direct_le_key(version, key) \
+ (le_key_k_type(version, key) == TYPE_DIRECT)
+#define is_indirect_le_key(version, key) \
+ (le_key_k_type(version, key) == TYPE_INDIRECT)
+#define is_statdata_le_key(version, key) \
+ (le_key_k_type(version, key) == TYPE_STAT_DATA)
+
+/* Item header has version. */
+#define is_direntry_le_ih(ih) \
+ is_direntry_le_key(ih_version(ih), &((ih)->ih_key))
+#define is_direct_le_ih(ih) \
+ is_direct_le_key(ih_version(ih), &((ih)->ih_key))
+#define is_indirect_le_ih(ih) \
+ is_indirect_le_key(ih_version(ih), &((ih)->ih_key))
+#define is_statdata_le_ih(ih) \
+ is_statdata_le_key(ih_version(ih), &((ih)->ih_key))
+
+static inline void
+set_cpu_key_k_offset(struct cpu_key *key, off_t offset)
+{
+
+ (key->version == KEY_FORMAT_3_5) ?
+ (key->on_disk_key.u.k_offset_v1.k_offset = offset) :
+ (key->on_disk_key.u.k_offset_v2.k_offset = offset);
+}
+
+static inline void
+set_cpu_key_k_type(struct cpu_key *key, int type)
+{
+
+ (key->version == KEY_FORMAT_3_5) ?
+ (key->on_disk_key.u.k_offset_v1.k_uniqueness =
+ type2uniqueness(type)):
+ (key->on_disk_key.u.k_offset_v2.k_type = type);
+}
+
+#define is_direntry_cpu_key(key) (cpu_key_k_type (key) == TYPE_DIRENTRY)
+#define is_direct_cpu_key(key) (cpu_key_k_type (key) == TYPE_DIRECT)
+#define is_indirect_cpu_key(key) (cpu_key_k_type (key) == TYPE_INDIRECT)
+#define is_statdata_cpu_key(key) (cpu_key_k_type (key) == TYPE_STAT_DATA)
+
+/* Maximal length of item */
+#define MAX_ITEM_LEN(block_size) (block_size - BLKH_SIZE - IH_SIZE)
+#define MIN_ITEM_LEN 1
+
+/* Object identifier for root dir */
+#define REISERFS_ROOT_OBJECTID 2
+#define REISERFS_ROOT_PARENT_OBJECTID 1
+
+/* key is pointer to cpu key, result is cpu */
+static inline off_t
+cpu_key_k_offset(const struct cpu_key *key)
+{
+
+ return ((key->version == KEY_FORMAT_3_5) ?
+ key->on_disk_key.u.k_offset_v1.k_offset :
+ key->on_disk_key.u.k_offset_v2.k_offset);
+}
+
+static inline off_t
+cpu_key_k_type(const struct cpu_key *key)
+{
+
+ return ((key->version == KEY_FORMAT_3_5) ?
+ uniqueness2type(key->on_disk_key.u.k_offset_v1.k_uniqueness) :
+ key->on_disk_key.u.k_offset_v2.k_type);
+}
+
+/*
+ * Header of a disk block. More precisely, header of a formatted leaf
+ * or internal node, and not the header of an unformatted node.
+ */
+struct block_head {
+ uint16_t blk_level; /* Level of a block in the
+ tree. */
+ uint16_t blk_nr_item; /* Number of keys/items in a
+ block. */
+ uint16_t blk_free_space; /* Block free space in bytes. */
+ uint16_t blk_reserved; /* Dump this in v4/planA */
+ struct key blk_right_delim_key; /* Kept only for compatibility */
+};
+
+#define BLKH_SIZE (sizeof(struct block_head))
+#define blkh_level(p_blkh) (le16toh((p_blkh)->blk_level))
+#define blkh_nr_item(p_blkh) (le16toh((p_blkh)->blk_nr_item))
+#define blkh_free_space(p_blkh) (le16toh((p_blkh)->blk_free_space))
+
+#define FREE_LEVEL 0 /* When node gets removed from the tree its
+ blk_level is set to FREE_LEVEL. It is then
+ used to see whether the node is still in the
+ tree */
+
+/* Values for blk_level field of the struct block_head */
+#define DISK_LEAF_NODE_LEVEL 1 /* Leaf node level.*/
+
+/*
+ * Given the buffer head of a formatted node, resolve to the block head
+ * of that node.
+ */
+#define B_BLK_HEAD(p_s_bp) ((struct block_head *)((p_s_bp)->b_data))
+#define B_NR_ITEMS(p_s_bp) (blkh_nr_item(B_BLK_HEAD(p_s_bp)))
+#define B_LEVEL(p_s_bp) (blkh_level(B_BLK_HEAD(p_s_bp)))
+#define B_FREE_SPACE(p_s_bp) (blkh_free_space(B_BLK_HEAD(p_s_bp)))
+
+/* -------------------------------------------------------------------
+ * Stat data
+ * -------------------------------------------------------------------*/
+
+/*
+ * Old stat data is 32 bytes long. We are going to distinguish new one
+ * by different size.
+ */
+struct stat_data_v1 {
+ uint16_t sd_mode; /* File type, permissions */
+ uint16_t sd_nlink; /* Number of hard links */
+ uint16_t sd_uid; /* Owner */
+ uint16_t sd_gid; /* Group */
+ uint32_t sd_size; /* File size */
+ uint32_t sd_atime; /* Time of last access */
+ uint32_t sd_mtime; /* Time file was last modified */
+ uint32_t sd_ctime; /* Time inode (stat data) was last changed
+ (except changes to sd_atime and
+ sd_mtime) */
+ union {
+ uint32_t sd_rdev;
+ uint32_t sd_blocks; /* Number of blocks file uses */
+ } __packed u;
+ uint32_t sd_first_direct_byte; /* First byte of file which is
+ stored in a direct item:
+ except that if it equals 1
+ it is a symlink and if it
+ equals ~(uint32_t)0 there
+ is no direct item. The
+ existence of this field
+ really grates on me. Let's
+ replace it with a macro based
+ on sd_size and our tail
+ suppression policy. Someday.
+ -Hans */
+} __packed;
+
+#define SD_V1_SIZE (sizeof(struct stat_data_v1))
+#define stat_data_v1(ih) (ih_version (ih) == KEY_FORMAT_3_5)
+#define sd_v1_mode(sdp) (le16toh((sdp)->sd_mode))
+#define set_sd_v1_mode(sdp, v) ((sdp)->sd_mode = htole16(v))
+#define sd_v1_nlink(sdp) (le16toh((sdp)->sd_nlink))
+#define set_sd_v1_nlink(sdp, v) ((sdp)->sd_nlink = htole16(v))
+#define sd_v1_uid(sdp) (le16toh((sdp)->sd_uid))
+#define set_sd_v1_uid(sdp, v) ((sdp)->sd_uid = htole16(v))
+#define sd_v1_gid(sdp) (le16toh((sdp)->sd_gid))
+#define set_sd_v1_gid(sdp, v) ((sdp)->sd_gid = htole16(v))
+#define sd_v1_size(sdp) (le32toh((sdp)->sd_size))
+#define set_sd_v1_size(sdp, v) ((sdp)->sd_size = htole32(v))
+#define sd_v1_atime(sdp) (le32toh((sdp)->sd_atime))
+#define set_sd_v1_atime(sdp, v) ((sdp)->sd_atime = htole32(v))
+#define sd_v1_mtime(sdp) (le32toh((sdp)->sd_mtime))
+#define set_sd_v1_mtime(sdp, v) ((sdp)->sd_mtime = htole32(v))
+#define sd_v1_ctime(sdp) (le32toh((sdp)->sd_ctime))
+#define set_sd_v1_ctime(sdp, v) ((sdp)->sd_ctime = htole32(v))
+#define sd_v1_rdev(sdp) (le32toh((sdp)->u.sd_rdev))
+#define set_sd_v1_rdev(sdp, v) ((sdp)->u.sd_rdev = htole32(v))
+#define sd_v1_blocks(sdp) (le32toh((sdp)->u.sd_blocks))
+#define set_sd_v1_blocks(sdp, v) ((sdp)->u.sd_blocks = htole32(v))
+#define sd_v1_first_direct_byte(sdp) \
+ (le32toh((sdp)->sd_first_direct_byte))
+#define set_sd_v1_first_direct_byte(sdp, v) \
+ ((sdp)->sd_first_direct_byte = htole32(v))
+
+/*
+ * We want common flags to have the same values as in ext2,
+ * so chattr(1) will work without problems
+ */
+#include <gnu/fs/ext2fs/ext2_fs.h>
+#define REISERFS_IMMUTABLE_FL EXT2_IMMUTABLE_FL
+#define REISERFS_APPEND_FL EXT2_APPEND_FL
+#define REISERFS_SYNC_FL EXT2_SYNC_FL
+#define REISERFS_NOATIME_FL EXT2_NOATIME_FL
+#define REISERFS_NODUMP_FL EXT2_NODUMP_FL
+#define REISERFS_SECRM_FL EXT2_SECRM_FL
+#define REISERFS_UNRM_FL EXT2_UNRM_FL
+#define REISERFS_COMPR_FL EXT2_COMPR_FL
+#define REISERFS_NOTAIL_FL EXT2_NOTAIL_FL
+
+/*
+ * Stat Data on disk (reiserfs version of UFS disk inode minus the
+ * address blocks)
+ */
+struct stat_data {
+ uint16_t sd_mode; /* File type, permissions */
+ uint16_t sd_attrs; /* Persistent inode flags */
+ uint32_t sd_nlink; /* Number of hard links */
+ uint64_t sd_size; /* File size */
+ uint32_t sd_uid; /* Owner */
+ uint32_t sd_gid; /* Group */
+ uint32_t sd_atime; /* Time of last access */
+ uint32_t sd_mtime; /* Time file was last modified */
+ uint32_t sd_ctime; /* Time inode (stat data) was last changed
+ (except changes to sd_atime and
+ sd_mtime) */
+ uint32_t sd_blocks;
+ union {
+ uint32_t sd_rdev;
+ uint32_t sd_generation;
+ //uint32_t sd_first_direct_byte;
+ /*
+ * First byte of file which is stored in a
+ * direct item: except that if it equals 1
+ * it is a symlink and if it equals
+ * ~(uint32_t)0 there is no direct item. The
+ * existence of this field really grates
+ * on me. Let's replace it with a macro
+ * based on sd_size and our tail
+ * suppression policy?
+ */
+ } __packed u;
+} __packed;
+
+/* This is 44 bytes long */
+#define SD_SIZE (sizeof(struct stat_data))
+#define SD_V2_SIZE SD_SIZE
+#define stat_data_v2(ih) (ih_version (ih) == KEY_FORMAT_3_6)
+#define sd_v2_mode(sdp) (le16toh((sdp)->sd_mode))
+#define set_sd_v2_mode(sdp, v) ((sdp)->sd_mode = htole16(v))
+/* sd_reserved */
+/* set_sd_reserved */
+#define sd_v2_nlink(sdp) (le32toh((sdp)->sd_nlink))
+#define set_sd_v2_nlink(sdp, v) ((sdp)->sd_nlink = htole32(v))
+#define sd_v2_size(sdp) (le64toh((sdp)->sd_size))
+#define set_sd_v2_size(sdp, v) ((sdp)->sd_size = cpu_to_le64(v))
+#define sd_v2_uid(sdp) (le32toh((sdp)->sd_uid))
+#define set_sd_v2_uid(sdp, v) ((sdp)->sd_uid = htole32(v))
+#define sd_v2_gid(sdp) (le32toh((sdp)->sd_gid))
+#define set_sd_v2_gid(sdp, v) ((sdp)->sd_gid = htole32(v))
+#define sd_v2_atime(sdp) (le32toh((sdp)->sd_atime))
+#define set_sd_v2_atime(sdp, v) ((sdp)->sd_atime = htole32(v))
+#define sd_v2_mtime(sdp) (le32toh((sdp)->sd_mtime))
+#define set_sd_v2_mtime(sdp, v) ((sdp)->sd_mtime = htole32(v))
+#define sd_v2_ctime(sdp) (le32toh((sdp)->sd_ctime))
+#define set_sd_v2_ctime(sdp, v) ((sdp)->sd_ctime = htole32(v))
+#define sd_v2_blocks(sdp) (le32toh((sdp)->sd_blocks))
+#define set_sd_v2_blocks(sdp, v) ((sdp)->sd_blocks = htole32(v))
+#define sd_v2_rdev(sdp) (le32toh((sdp)->u.sd_rdev))
+#define set_sd_v2_rdev(sdp, v) ((sdp)->u.sd_rdev = htole32(v))
+#define sd_v2_generation(sdp) (le32toh((sdp)->u.sd_generation))
+#define set_sd_v2_generation(sdp, v) ((sdp)->u.sd_generation = htole32(v))
+#define sd_v2_attrs(sdp) (le16toh((sdp)->sd_attrs))
+#define set_sd_v2_attrs(sdp, v) ((sdp)->sd_attrs = htole16(v))
+
+/* -------------------------------------------------------------------
+ * Directory structure
+ * -------------------------------------------------------------------*/
+
+#define SD_OFFSET 0
+#define SD_UNIQUENESS 0
+#define DOT_OFFSET 1
+#define DOT_DOT_OFFSET 2
+#define DIRENTRY_UNIQUENESS 500
+
+#define FIRST_ITEM_OFFSET 1
+
+struct reiserfs_de_head {
+ uint32_t deh_offset; /* Third component of the directory
+ entry key */
+ uint32_t deh_dir_id; /* Objectid of the parent directory of
+ the object, that is referenced by
+ directory entry */
+ uint32_t deh_objectid; /* Objectid of the object, that is
+ referenced by directory entry */
+ uint16_t deh_location; /* Offset of name in the whole item */
+ uint16_t deh_state; /* Whether 1) entry contains stat data
+ (for future), and 2) whether entry
+ is hidden (unlinked) */
+} __packed;
+
+#define DEH_SIZE sizeof(struct reiserfs_de_head)
+#define deh_offset(p_deh) (le32toh((p_deh)->deh_offset))
+#define deh_dir_id(p_deh) (le32toh((p_deh)->deh_dir_id))
+#define deh_objectid(p_deh) (le32toh((p_deh)->deh_objectid))
+#define deh_location(p_deh) (le16toh((p_deh)->deh_location))
+#define deh_state(p_deh) (le16toh((p_deh)->deh_state))
+
+#define put_deh_offset(p_deh, v) ((p_deh)->deh_offset = htole32((v)))
+#define put_deh_dir_id(p_deh, v) ((p_deh)->deh_dir_id = htole32((v)))
+#define put_deh_objectid(p_deh, v) ((p_deh)->deh_objectid = htole32((v)))
+#define put_deh_location(p_deh, v) ((p_deh)->deh_location = htole16((v)))
+#define put_deh_state(p_deh, v) ((p_deh)->deh_state = htole16((v)))
+
+/* Empty directory contains two entries "." and ".." and their headers */
+#define EMPTY_DIR_SIZE \
+ (DEH_SIZE * 2 + ROUND_UP(strlen(".")) + ROUND_UP(strlen("..")))
+
+/* Old format directories have this size when empty */
+#define EMPTY_DIR_SIZE_V1 (DEH_SIZE * 2 + 3)
+
+#define DEH_Statdata 0 /* Not used now */
+#define DEH_Visible 2
+
+/* 64 bit systems (and the S/390) need to be aligned explicitly -jdm */
+#if BITS_PER_LONG == 64 || defined(__sparc64__)
+#define ADDR_UNALIGNED_BITS (3)
+#endif
+
+#ifdef ADDR_UNALIGNED_BITS
+#define aligned_address(addr) \
+ ((void *)((long)(addr) & ~((1UL << ADDR_UNALIGNED_BITS) - 1)))
+#define unaligned_offset(addr) \
+ (((int)((long)(addr) & ((1 << ADDR_UNALIGNED_BITS) - 1))) << 3)
+
+#define set_bit_unaligned(nr, addr) \
+ set_bit((nr) + unaligned_offset(addr), aligned_address(addr))
+#define clear_bit_unaligned(nr, addr) \
+ clear_bit((nr) + unaligned_offset(addr), aligned_address(addr))
+#define test_bit_unaligned(nr, addr) \
+ test_bit((nr) + unaligned_offset(addr), aligned_address(addr))
+#else /* !defined ADDR_UNALIGNED_BITS */
+#define set_bit_unaligned(nr, addr) set_bit(nr, addr)
+#define clear_bit_unaligned(nr, addr) clear_bit(nr, addr)
+#define test_bit_unaligned(nr, addr) test_bit(nr, addr)
+#endif /* defined ADDR_UNALIGNED_BITS */
+
+#define mark_de_with_sd(deh) \
+ set_bit_unaligned(DEH_Statdata, &((deh)->deh_state))
+#define mark_de_without_sd(deh) \
+ clear_bit_unaligned(DEH_Statdata, &((deh)->deh_state))
+#define mark_de_visible(deh) \
+ set_bit_unaligned (DEH_Visible, &((deh)->deh_state))
+#define mark_de_hidden(deh) \
+ clear_bit_unaligned (DEH_Visible, &((deh)->deh_state))
+
+#define de_with_sd(deh) \
+ test_bit_unaligned(DEH_Statdata, &((deh)->deh_state))
+#define de_visible(deh) \
+ test_bit_unaligned(DEH_Visible, &((deh)->deh_state))
+#define de_hidden(deh) \
+ !test_bit_unaligned(DEH_Visible, &((deh)->deh_state))
+
+/* Two entries per block (at least) */
+#define REISERFS_MAX_NAME(block_size) 255
+
+/*
+ * This structure is used for operations on directory entries. It is not
+ * a disk structure. When reiserfs_find_entry or search_by_entry_key
+ * find directory entry, they return filled reiserfs_dir_entry structure
+ */
+struct reiserfs_dir_entry {
+ struct buf *de_bp;
+ int de_item_num;
+ struct item_head *de_ih;
+ int de_entry_num;
+ struct reiserfs_de_head *de_deh;
+ int de_entrylen;
+ int de_namelen;
+ char *de_name;
+ char *de_gen_number_bit_string;
+
+ uint32_t de_dir_id;
+ uint32_t de_objectid;
+
+ struct cpu_key de_entry_key;
+};
+
+/* Pointer to file name, stored in entry */
+#define B_I_DEH_ENTRY_FILE_NAME(bp, ih, deh) \
+ (B_I_PITEM(bp, ih) + deh_location(deh))
+
+/* Length of name */
+#define I_DEH_N_ENTRY_FILE_NAME_LENGTH(ih, deh, entry_num) \
+ (I_DEH_N_ENTRY_LENGTH(ih, deh, entry_num) - \
+ (de_with_sd(deh) ? SD_SIZE : 0))
+
+/* Hash value occupies bits from 7 up to 30 */
+#define GET_HASH_VALUE(offset) ((offset) & 0x7fffff80LL)
+
+/* Generation number occupies 7 bits starting from 0 up to 6 */
+#define GET_GENERATION_NUMBER(offset) ((offset) & 0x7fLL)
+#define MAX_GENERATION_NUMBER 127
+
+/* Get item body */
+#define B_I_PITEM(bp, ih) ((bp)->b_data + ih_location(ih))
+#define B_I_DEH(bp, ih) ((struct reiserfs_de_head *)(B_I_PITEM(bp, ih)))
+
+/*
+ * Length of the directory entry in directory item. This define
+ * calculates length of i-th directory entry using directory entry
+ * locations from dir entry head. When it calculates length of 0-th
+ * directory entry, it uses length of whole item in place of entry
+ * location of the non-existent following entry in the calculation. See
+ * picture above.
+ */
+static inline int
+entry_length (const struct buf *bp, const struct item_head *ih,
+ int pos_in_item)
+{
+ struct reiserfs_de_head *deh;
+
+ deh = B_I_DEH(bp, ih) + pos_in_item;
+ if (pos_in_item)
+ return (deh_location(deh - 1) - deh_location(deh));
+
+ return (ih_item_len(ih) - deh_location(deh));
+}
+
+/*
+ * Number of entries in the directory item, depends on ENTRY_COUNT
+ * being at the start of directory dynamic data.
+ */
+#define I_ENTRY_COUNT(ih) (ih_entry_count((ih)))
+
+/* -------------------------------------------------------------------
+ * Disk child
+ * -------------------------------------------------------------------*/
+
+/*
+ * Disk child pointer: The pointer from an internal node of the tree
+ * to a node that is on disk.
+ */
+struct disk_child {
+ uint32_t dc_block_number; /* Disk child's block number. */
+ uint16_t dc_size; /* Disk child's used space. */
+ uint16_t dc_reserved;
+};
+
+#define DC_SIZE (sizeof(struct disk_child))
+#define dc_block_number(dc_p) (le32toh((dc_p)->dc_block_number))
+#define dc_size(dc_p) (le16toh((dc_p)->dc_size))
+#define put_dc_block_number(dc_p, val) \
+ do { (dc_p)->dc_block_number = htole32(val); } while (0)
+#define put_dc_size(dc_p, val) \
+ do { (dc_p)->dc_size = htole16(val); } while (0)
+
+/* Get disk child by buffer header and position in the tree node. */
+#define B_N_CHILD(p_s_bp, n_pos) \
+ ((struct disk_child *)((p_s_bp)->b_data + BLKH_SIZE + \
+ B_NR_ITEMS(p_s_bp) * KEY_SIZE + \
+ DC_SIZE * (n_pos)))
+
+/* Get disk child number by buffer header and position in the tree node. */
+#define B_N_CHILD_NUM(p_s_bp, n_pos) \
+ (dc_block_number(B_N_CHILD(p_s_bp, n_pos)))
+#define PUT_B_N_CHILD_NUM(p_s_bp, n_pos, val) \
+ (put_dc_block_number(B_N_CHILD(p_s_bp, n_pos), val))
+
+/* -------------------------------------------------------------------
+ * Path structures and defines
+ * -------------------------------------------------------------------*/
+
+struct path_element {
+ struct buf *pe_buffer; /* Pointer to the buffer at the path in
+ the tree. */
+ int pe_position; /* Position in the tree node which is
+ placed in the buffer above. */
+};
+
+#define MAX_HEIGHT 5 /* Maximal height of a tree. Don't
+ change this without changing
+ JOURNAL_PER_BALANCE_CNT */
+#define EXTENDED_MAX_HEIGHT 7 /* Must be equals MAX_HEIGHT +
+ FIRST_PATH_ELEMENT_OFFSET */
+#define FIRST_PATH_ELEMENT_OFFSET 2 /* Must be equal to at least 2. */
+#define ILLEGAL_PATH_ELEMENT_OFFSET 1 /* Must be equal to
+ FIRST_PATH_ELEMENT_OFFSET - 1 */
+#define MAX_FEB_SIZE 6 /* This MUST be MAX_HEIGHT + 1.
+ See about FEB below */
+
+struct path {
+ /* Length of the array below. */
+ int path_length;
+ /* Array of the path element */
+ struct path_element path_elements[EXTENDED_MAX_HEIGHT];
+ int pos_in_item;
+};
+
+#define pos_in_item(path) ((path)->pos_in_item)
+
+#define INITIALIZE_PATH(var) \
+ struct path var = { ILLEGAL_PATH_ELEMENT_OFFSET, }
+
+/* Get path element by path and path position. */
+#define PATH_OFFSET_PELEMENT(p_s_path, n_offset) \
+ ((p_s_path)->path_elements + (n_offset))
+
+/* Get buffer header at the path by path and path position. */
+#define PATH_OFFSET_PBUFFER(p_s_path, n_offset) \
+ (PATH_OFFSET_PELEMENT(p_s_path, n_offset)->pe_buffer)
+
+/* Get position in the element at the path by path and path position. */
+#define PATH_OFFSET_POSITION(p_s_path, n_offset) \
+ (PATH_OFFSET_PELEMENT(p_s_path, n_offset)->pe_position)
+
+#define PATH_PLAST_BUFFER(p_s_path) \
+ (PATH_OFFSET_PBUFFER((p_s_path), (p_s_path)->path_length))
+
+#define PATH_LAST_POSITION(p_s_path) \
+ (PATH_OFFSET_POSITION((p_s_path), (p_s_path)->path_length))
+
+#define PATH_PITEM_HEAD(p_s_path) \
+ B_N_PITEM_HEAD(PATH_PLAST_BUFFER(p_s_path), PATH_LAST_POSITION(p_s_path))
+
+#define get_last_bp(path) PATH_PLAST_BUFFER(path)
+#define get_ih(path) PATH_PITEM_HEAD(path)
+
+/* -------------------------------------------------------------------
+ * Misc.
+ * -------------------------------------------------------------------*/
+
+/* Size of pointer to the unformatted node. */
+#define UNFM_P_SIZE (sizeof(unp_t))
+#define UNFM_P_SHIFT 2
+
+/* In in-core inode key is stored on le form */
+#define INODE_PKEY(ip) ((struct key *)(REISERFS_I(ip)->i_key))
+
+#define MAX_UL_INT 0xffffffff
+#define MAX_INT 0x7ffffff
+#define MAX_US_INT 0xffff
+
+/* The purpose is to detect overflow of an unsigned short */
+#define REISERFS_LINK_MAX (MAX_US_INT - 1000)
+
+#define fs_generation(sbi) (REISERFS_SB(sbi)->s_generation_counter)
+#define get_generation(sbi) (fs_generation(sbi))
+
+#define __fs_changed(gen, sbi) (gen != get_generation (sbi))
+/*#define fs_changed(gen, sbi) ({ cond_resched(); \
+ __fs_changed(gen, sbi); })*/
+#define fs_changed(gen, sbi) (__fs_changed(gen, sbi))
+
+/* -------------------------------------------------------------------
+ * Fixate node
+ * -------------------------------------------------------------------*/
+
+/*
+ * To make any changes in the tree we always first find node, that
+ * contains item to be changed/deleted or place to insert a new item.
+ * We call this node S. To do balancing we need to decide what we will
+ * shift to left/right neighbor, or to a new node, where new item will
+ * be etc. To make this analysis simpler we build virtual node. Virtual
+ * node is an array of items, that will replace items of node S. (For
+ * instance if we are going to delete an item, virtual node does not
+ * contain it). Virtual node keeps information about item sizes and
+ * types, mergeability of first and last items, sizes of all entries in
+ * directory item. We use this array of items when calculating what we
+ * can shift to neighbors and how many nodes we have to have if we do
+ * not any shiftings, if we shift to left/right neighbor or to both.
+ */
+struct virtual_item {
+ int vi_index; /* Index in the array of item
+ operations */
+ unsigned short vi_type; /* Left/right mergeability */
+ unsigned short vi_item_len; /* Length of item that it will
+ have after balancing */
+ struct item_head *vi_ih;
+ const char *vi_item; /* Body of item (old or new) */
+ const void *vi_new_data; /* 0 always but paste mode */
+ void *vi_uarea; /* Item specific area */
+};
+
+struct virtual_node {
+ char *vn_free_ptr; /* This is a pointer to the free space
+ in the buffer */
+ unsigned short vn_nr_item; /* Number of items in virtual node */
+ short vn_size; /* Size of node , that node would have
+ if it has unlimited size and no
+ balancing is performed */
+ short vn_mode; /* Mode of balancing (paste, insert,
+ delete, cut) */
+ short vn_affected_item_num;
+ short vn_pos_in_item;
+ struct item_head *vn_ins_ih; /* Item header of inserted item, 0 for
+ other modes */
+ const void *vn_data;
+ struct virtual_item *vn_vi; /* Array of items (including a new one,
+ excluding item to be deleted) */
+};
+
+/* Used by directory items when creating virtual nodes */
+struct direntry_uarea {
+ int flags;
+ uint16_t entry_count;
+ uint16_t entry_sizes[1];
+} __packed;
+
+/* -------------------------------------------------------------------
+ * Tree balance
+ * -------------------------------------------------------------------*/
+
+struct reiserfs_iget_args {
+ uint32_t objectid;
+ uint32_t dirid;
+};
+
+struct item_operations {
+ int (*bytes_number)(struct item_head * ih, int block_size);
+ void (*decrement_key)(struct cpu_key *);
+ int (*is_left_mergeable)(struct key * ih, unsigned long bsize);
+ void (*print_item)(struct item_head *, char * item);
+ void (*check_item)(struct item_head *, char * item);
+
+ int (*create_vi)(struct virtual_node * vn,
+ struct virtual_item * vi, int is_affected, int insert_size);
+ int (*check_left)(struct virtual_item * vi, int free,
+ int start_skip, int end_skip);
+ int (*check_right)(struct virtual_item * vi, int free);
+ int (*part_size)(struct virtual_item * vi, int from, int to);
+ int (*unit_num)(struct virtual_item * vi);
+ void (*print_vi)(struct virtual_item * vi);
+};
+
+extern struct item_operations *item_ops[TYPE_ANY + 1];
+
+#define op_bytes_number(ih, bsize) \
+ item_ops[le_ih_k_type(ih)]->bytes_number(ih, bsize)
+
+#define COMP_KEYS comp_keys
+#define COMP_SHORT_KEYS comp_short_keys
+
+/* Get the item header */
+#define B_N_PITEM_HEAD(bp, item_num) \
+ ((struct item_head *)((bp)->b_data + BLKH_SIZE) + (item_num))
+
+/* Get key */
+#define B_N_PDELIM_KEY(bp, item_num) \
+ ((struct key *)((bp)->b_data + BLKH_SIZE) + (item_num))
+
+/* -------------------------------------------------------------------
+ * Function declarations
+ * -------------------------------------------------------------------*/
+
+/* reiserfs_stree.c */
+int B_IS_IN_TREE(const struct buf *p_s_bp);
+
+extern void copy_item_head(struct item_head * p_v_to,
+ const struct item_head * p_v_from);
+
+extern int comp_keys(const struct key *le_key,
+ const struct cpu_key *cpu_key);
+extern int comp_short_keys(const struct key *le_key,
+ const struct cpu_key *cpu_key);
+
+extern int comp_le_keys(const struct key *, const struct key *);
+
+static inline int
+le_key_version(const struct key *key)
+{
+ int type;
+
+ type = offset_v2_k_type(&(key->u.k_offset_v2));
+ if (type != TYPE_DIRECT && type != TYPE_INDIRECT &&
+ type != TYPE_DIRENTRY)
+ return (KEY_FORMAT_3_5);
+
+ return (KEY_FORMAT_3_6);
+}
+
+static inline void
+copy_key(struct key *to, const struct key *from)
+{
+
+ memcpy(to, from, KEY_SIZE);
+}
+
+const struct key *get_lkey(const struct path *p_s_chk_path,
+ const struct reiserfs_sb_info *p_s_sbi);
+const struct key *get_rkey(const struct path *p_s_chk_path,
+ const struct reiserfs_sb_info *p_s_sbi);
+inline int bin_search(const void * p_v_key, const void * p_v_base,
+ int p_n_num, int p_n_width, int * p_n_pos);
+
+void pathrelse(struct path *p_s_search_path);
+int reiserfs_check_path(struct path *p);
+
+int search_by_key(struct reiserfs_sb_info *p_s_sbi,
+ const struct cpu_key *p_s_key,
+ struct path *p_s_search_path,
+ int n_stop_level);
+#define search_item(sbi, key, path) \
+ search_by_key(sbi, key, path, DISK_LEAF_NODE_LEVEL)
+int search_for_position_by_key(struct reiserfs_sb_info *p_s_sbi,
+ const struct cpu_key *p_s_cpu_key,
+ struct path *p_s_search_path);
+void decrement_counters_in_path(struct path *p_s_search_path);
+
+/* reiserfs_inode.c */
+vop_read_t reiserfs_read;
+vop_inactive_t reiserfs_inactive;
+vop_reclaim_t reiserfs_reclaim;
+
+int reiserfs_get_block(struct reiserfs_node *ip, long block,
+ off_t offset, struct uio *uio);
+
+void make_cpu_key(struct cpu_key *cpu_key, struct reiserfs_node *ip,
+ off_t offset, int type, int key_length);
+
+void reiserfs_read_locked_inode(struct reiserfs_node *ip,
+ struct reiserfs_iget_args *args);
+int reiserfs_iget(struct mount *mp, const struct cpu_key *key,
+ struct vnode **vpp, struct thread *td);
+
+void sd_attrs_to_i_attrs(uint16_t sd_attrs, struct reiserfs_node *ip);
+void i_attrs_to_sd_attrs(struct reiserfs_node *ip, uint16_t *sd_attrs);
+
+/* reiserfs_namei.c */
+vop_readdir_t reiserfs_readdir;
+vop_cachedlookup_t reiserfs_lookup;
+
+void set_de_name_and_namelen(struct reiserfs_dir_entry * de);
+int search_by_entry_key(struct reiserfs_sb_info *sbi,
+ const struct cpu_key *key, struct path *path,
+ struct reiserfs_dir_entry *de);
+
+/* reiserfs_prints.c */
+char *reiserfs_hashname(int code);
+void reiserfs_dump_buffer(caddr_t buf, off_t len);
+
+#if defined(REISERFS_DEBUG)
+#define reiserfs_log(lvl, fmt, ...) \
+ log(lvl, "ReiserFS/%s: " fmt, __func__, ## __VA_ARGS__)
+#elif defined (REISERFS_DEBUG_CONS)
+#define reiserfs_log(lvl, fmt, ...) \
+ printf("%s:%d: " fmt, __func__, __LINE__, ## __VA_ARGS__)
+#else
+#define reiserfs_log(lvl, fmt, ...)
+#endif
+
+#define reiserfs_log_0(lvl, fmt, ...) \
+ printf("%s:%d: " fmt, __func__, __LINE__, ## __VA_ARGS__)
+
+/* reiserfs_hashes.c */
+uint32_t keyed_hash(const signed char *msg, int len);
+uint32_t yura_hash(const signed char *msg, int len);
+uint32_t r5_hash(const signed char *msg, int len);
+
+#define reiserfs_test_le_bit test_bit
+
+#endif /* !defined _GNU_REISERFS_REISERFS_FS_H */
diff --git a/sys/gnu/fs/reiserfs/reiserfs_fs_i.h b/sys/gnu/fs/reiserfs/reiserfs_fs_i.h
new file mode 100644
index 000000000000..a9aa7e53f2d7
--- /dev/null
+++ b/sys/gnu/fs/reiserfs/reiserfs_fs_i.h
@@ -0,0 +1,90 @@
+/*-
+ * Copyright 2000 Hans Reiser
+ * See README for licensing and copyright details
+ *
+ * Ported to FreeBSD by Jean-Sébastien Pédron <jspedron@club-internet.fr>
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _GNU_REISERFS_REISERFS_FS_I_H
+#define _GNU_REISERFS_REISERFS_FS_I_H
+
+#include <sys/queue.h>
+
+/* Bitmasks for i_flags field in reiserfs-specific part of inode */
+typedef enum {
+ /*
+ * This says what format of key do all items (but stat data) of
+ * an object have. If this is set, that format is 3.6 otherwise
+ * - 3.5
+ */
+ i_item_key_version_mask = 0x0001,
+ /* If this is unset, object has 3.5 stat data, otherwise, it has
+ * 3.6 stat data with 64bit size, 32bit nlink etc. */
+ i_stat_data_version_mask = 0x0002,
+ /* File might need tail packing on close */
+ i_pack_on_close_mask = 0x0004,
+ /* Don't pack tail of file */
+ i_nopack_mask = 0x0008,
+ /* If those is set, "safe link" was created for this file during
+ * truncate or unlink. Safe link is used to avoid leakage of disk
+ * space on crash with some files open, but unlinked. */
+ i_link_saved_unlink_mask = 0x0010,
+ i_link_saved_truncate_mask = 0x0020,
+ i_priv_object = 0x0080,
+ i_has_xattr_dir = 0x0100,
+} reiserfs_inode_flags;
+
+struct reiserfs_node {
+ struct vnode *i_vnode;
+ struct vnode *i_devvp;
+ struct cdev *i_dev;
+ ino_t i_number;
+
+ ino_t i_ino;
+
+ struct reiserfs_sb_info *i_reiserfs;
+
+ uint32_t i_flag; /* Flags, see below */
+ uint32_t i_key[4]; /* Key is still 4 32 bit
+ integers */
+ uint32_t i_flags; /* Transient inode flags that
+ are never stored on disk.
+ Bitmasks for this field
+ are defined above. */
+ uint32_t i_first_direct_byte; /* Offset of first byte stored
+ in direct item. */
+ uint32_t i_attrs; /* Copy of persistent inode
+ flags read from sd_attrs. */
+
+ uint16_t i_mode; /* IFMT, permissions. */
+ uint16_t i_nlink; /* File link count. */
+ uint64_t i_size; /* File byte count. */
+ uint32_t i_bytes;
+ uid_t i_uid; /* File owner. */
+ gid_t i_gid; /* File group. */
+ struct timespec i_atime; /* Last access time. */
+ struct timespec i_mtime; /* Last modified time. */
+ struct timespec i_ctime; /* Last inode change time. */
+
+ uint32_t i_blocks;
+ uint32_t i_generation;
+};
+
+#define VTOI(vp) ((struct reiserfs_node *)(vp)->v_data)
+#define ITOV(ip) ((ip)->i_vnode)
+
+/* These flags are kept in i_flag. */
+#define IN_HASHED 0x0020 /* Inode is on hash list */
+
+/* This overlays the fid structure (see mount.h) */
+struct rfid {
+ uint16_t rfid_len; /* Length of structure */
+ uint16_t rfid_pad; /* Force 32-bit alignment */
+ ino_t rfid_dirid; /* File key */
+ ino_t rfid_objectid;
+ uint32_t rfid_gen; /* Generation number */
+};
+
+#endif /* !defined _GNU_REISERFS_REISERFS_FS_I_H */
diff --git a/sys/gnu/fs/reiserfs/reiserfs_fs_sb.h b/sys/gnu/fs/reiserfs/reiserfs_fs_sb.h
new file mode 100644
index 000000000000..184e01c85957
--- /dev/null
+++ b/sys/gnu/fs/reiserfs/reiserfs_fs_sb.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2000 Hans Reiser
+ * See README for licensing and copyright details
+ *
+ * Ported to FreeBSD by Jean-Sébastien Pédron <jspedron@club-internet.fr>
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _GNU_REISERFS_REISERFS_FS_SB_H
+#define _GNU_REISERFS_REISERFS_FS_SB_H
+
+typedef uint32_t (*hashf_t)(const signed char *, int);
+
+#define sb_block_count(sbp) (le32toh((sbp)->s_v1.s_block_count))
+#define set_sb_block_count(sbp,v) ((sbp)->s_v1.s_block_count = htole32(v))
+#define sb_free_blocks(sbp) (le32toh((sbp)->s_v1.s_free_blocks))
+#define set_sb_free_blocks(sbp,v) ((sbp)->s_v1.s_free_blocks = htole32(v))
+#define sb_root_block(sbp) (le32toh((sbp)->s_v1.s_root_block))
+
+/* Bitmaps */
+struct reiserfs_bitmap_info {
+ uint16_t first_zero_hint;
+ uint16_t free_count;
+ //struct buf *bp; /* The actual bitmap */
+ caddr_t bp_data; /* The actual bitmap */
+};
+
+/* ReiserFS union of in-core super block data */
+struct reiserfs_sb_info {
+ struct reiserfs_super_block *s_rs;
+ struct reiserfs_bitmap_info *s_ap_bitmap;
+ struct vnode *s_devvp;
+
+ unsigned short s_mount_state;
+
+ hashf_t s_hash_function; /* Pointer to function which
+ is used to sort names in
+ directory. Set on mount */
+ unsigned long s_mount_opt; /* ReiserFS's mount options
+ are set here */
+ int s_generation_counter; /* Increased by one every
+ time the tree gets
+ re-balanced */
+ unsigned long s_properties; /* File system properties.
+ Currently holds on-disk
+ FS format */
+ uint16_t s_blocksize;
+ uint16_t s_blocksize_bits;
+ char s_rd_only; /* Is it read-only ? */
+ int s_is_unlinked_ok;
+};
+
+#define sb_version(sbi) (le16toh((sbi)->s_v1.s_version))
+#define set_sb_version(sbi, v) ((sbi)->s_v1.s_version = htole16(v))
+
+#define sb_blocksize(sbi) (le16toh((sbi)->s_v1.s_blocksize))
+#define set_sb_blocksize(sbi, v) ((sbi)->s_v1.s_blocksize = htole16(v))
+
+#define sb_hash_function_code(sbi) \
+ (le32toh((sbi)->s_v1.s_hash_function_code))
+#define set_sb_hash_function_code(sbi, v) \
+ ((sbi)->s_v1.s_hash_function_code = htole32(v))
+
+#define sb_bmap_nr(sbi) (le16toh((sbi)->s_v1.s_bmap_nr))
+#define set_sb_bmap_nr(sbi, v) ((sbi)->s_v1.s_bmap_nr = htole16(v))
+
+/* Definitions of reiserfs on-disk properties: */
+#define REISERFS_3_5 0
+#define REISERFS_3_6 1
+
+enum reiserfs_mount_options {
+ /* Mount options */
+ REISERFS_LARGETAIL, /* Large tails will be created in a session */
+ REISERFS_SMALLTAIL, /* Small (for files less than block size) tails
+ will be created in a session */
+ REPLAYONLY, /* Replay journal and return 0. Use by fsck */
+ REISERFS_CONVERT, /* -o conv: causes conversion of old format super
+ block to the new format. If not specified -
+ old partition will be dealt with in a manner
+ of 3.5.x */
+
+ /*
+ * -o hash={tea, rupasov, r5, detect} is meant for properly mounting
+ * reiserfs disks from 3.5.19 or earlier. 99% of the time, this option
+ * is not required. If the normal autodection code can't determine
+ * which hash to use (because both hases had the same value for a
+ * file) use this option to force a specific hash. It won't allow you
+ * to override the existing hash on the FS, so if you have a tea hash
+ * disk, and mount with -o hash=rupasov, the mount will fail.
+ */
+ FORCE_TEA_HASH, /* try to force tea hash on mount */
+ FORCE_RUPASOV_HASH, /* try to force rupasov hash on mount */
+ FORCE_R5_HASH, /* try to force rupasov hash on mount */
+ FORCE_HASH_DETECT, /* try to detect hash function on mount */
+
+ REISERFS_DATA_LOG,
+ REISERFS_DATA_ORDERED,
+ REISERFS_DATA_WRITEBACK,
+
+ /*
+ * used for testing experimental features, makes benchmarking new
+ * features with and without more convenient, should never be used by
+ * users in any code shipped to users (ideally)
+ */
+
+ REISERFS_NO_BORDER,
+ REISERFS_NO_UNHASHED_RELOCATION,
+ REISERFS_HASHED_RELOCATION,
+ REISERFS_ATTRS,
+ REISERFS_XATTRS,
+ REISERFS_XATTRS_USER,
+ REISERFS_POSIXACL,
+
+ REISERFS_TEST1,
+ REISERFS_TEST2,
+ REISERFS_TEST3,
+ REISERFS_TEST4,
+};
+
+#define reiserfs_r5_hash(sbi) \
+ (REISERFS_SB(sbi)->s_mount_opt & (1 << FORCE_R5_HASH))
+#define reiserfs_rupasov_hash(sbi) \
+ (REISERFS_SB(sbi)->s_mount_opt & (1 << FORCE_RUPASOV_HASH))
+#define reiserfs_tea_hash(sbi) \
+ (REISERFS_SB(sbi)->s_mount_opt & (1 << FORCE_TEA_HASH))
+#define reiserfs_hash_detect(sbi) \
+ (REISERFS_SB(sbi)->s_mount_opt & (1 << FORCE_HASH_DETECT))
+
+#define reiserfs_attrs(sbi) \
+ (REISERFS_SB(sbi)->s_mount_opt & (1 << REISERFS_ATTRS))
+
+#define reiserfs_data_log(sbi) \
+ (REISERFS_SB(sbi)->s_mount_opt & (1 << REISERFS_DATA_LOG))
+#define reiserfs_data_ordered(sbi) \
+ (REISERFS_SB(sbi)->s_mount_opt & (1 << REISERFS_DATA_ORDERED))
+#define reiserfs_data_writeback(sbi) \
+ (REISERFS_SB(sbi)->s_mount_opt & (1 << REISERFS_DATA_WRITEBACK))
+
+#define SB_BUFFER_WITH_SB(sbi) (REISERFS_SB(sbi)->s_sbh)
+#define SB_AP_BITMAP(sbi) (REISERFS_SB(sbi)->s_ap_bitmap)
+
+#endif /* !defined _GNU_REISERFS_REISERFS_FS_SB_H */
diff --git a/sys/gnu/fs/reiserfs/reiserfs_hashes.c b/sys/gnu/fs/reiserfs/reiserfs_hashes.c
new file mode 100644
index 000000000000..c42bbe2fd30c
--- /dev/null
+++ b/sys/gnu/fs/reiserfs/reiserfs_hashes.c
@@ -0,0 +1,217 @@
+/*-
+ * Copyright 2000 Hans Reiser
+ * See README for licensing and copyright details
+ *
+ * Ported to FreeBSD by Jean-Sébastien Pédron <jspedron@club-internet.fr>
+ *
+ * $FreeBSD$
+ */
+
+#include <gnu/fs/reiserfs/reiserfs_fs.h>
+
+/*
+ * Keyed 32-bit hash function using TEA in a Davis-Meyer function
+ * H0 = Key
+ * Hi = E Mi(Hi-1) + Hi-1
+ *
+ * (see Applied Cryptography, 2nd edition, p448).
+ *
+ * Jeremy Fitzhardinge <jeremy@zip.com.au> 1998
+ *
+ * Jeremy has agreed to the contents of README. -Hans
+ * Yura's function is added (04/07/2000)
+ */
+
+/*
+ * keyed_hash
+ * yura_hash
+ * r5_hash
+ */
+
+#define DELTA 0x9E3779B9
+#define FULLROUNDS 10 /* 32 is overkill, 16 is strong crypto */
+#define PARTROUNDS 6 /* 6 gets complete mixing */
+
+/* a, b, c, d - data; h0, h1 - accumulated hash */
+#define TEACORE(rounds) \
+ do { \
+ int n; \
+ uint32_t b0, b1; \
+ uint32_t sum; \
+ \
+ n = rounds; \
+ sum = 0; \
+ b0 = h0; \
+ b1 = h1; \
+ \
+ do { \
+ sum += DELTA; \
+ b0 += ((b1 << 4) + a) ^ (b1+sum) ^ ((b1 >> 5) + b); \
+ b1 += ((b0 << 4) + c) ^ (b0+sum) ^ ((b0 >> 5) + d); \
+ } while (--n); \
+ \
+ h0 += b0; \
+ h1 += b1; \
+ } while (0)
+
+uint32_t
+keyed_hash(const signed char *msg, int len)
+{
+ uint32_t k[] = { 0x9464a485, 0x542e1a94, 0x3e846bff, 0xb75bcfc3 };
+
+ uint32_t h0, h1;
+ uint32_t a, b, c, d;
+ uint32_t pad;
+ int i;
+
+ h0 = k[0];
+ h1 = k[1];
+
+ pad = (uint32_t)len | ((uint32_t)len << 8);
+ pad |= pad << 16;
+
+ while(len >= 16) {
+ a = (uint32_t)msg[ 0] |
+ (uint32_t)msg[ 1] << 8 |
+ (uint32_t)msg[ 2] << 16 |
+ (uint32_t)msg[ 3] << 24;
+ b = (uint32_t)msg[ 4] |
+ (uint32_t)msg[ 5] << 8 |
+ (uint32_t)msg[ 6] << 16 |
+ (uint32_t)msg[ 7] << 24;
+ c = (uint32_t)msg[ 8] |
+ (uint32_t)msg[ 9] << 8 |
+ (uint32_t)msg[10] << 16 |
+ (uint32_t)msg[11] << 24;
+ d = (uint32_t)msg[12] |
+ (uint32_t)msg[13] << 8 |
+ (uint32_t)msg[14] << 16 |
+ (uint32_t)msg[15] << 24;
+
+ TEACORE(PARTROUNDS);
+
+ len -= 16;
+ msg += 16;
+ }
+
+ if (len >= 12) {
+ a = (uint32_t)msg[ 0] |
+ (uint32_t)msg[ 1] << 8 |
+ (uint32_t)msg[ 2] << 16 |
+ (uint32_t)msg[ 3] << 24;
+ b = (uint32_t)msg[ 4] |
+ (uint32_t)msg[ 5] << 8 |
+ (uint32_t)msg[ 6] << 16 |
+ (uint32_t)msg[ 7] << 24;
+ c = (uint32_t)msg[ 8] |
+ (uint32_t)msg[ 9] << 8 |
+ (uint32_t)msg[10] << 16 |
+ (uint32_t)msg[11] << 24;
+
+ d = pad;
+ for(i = 12; i < len; i++) {
+ d <<= 8;
+ d |= msg[i];
+ }
+ } else if (len >= 8) {
+ a = (uint32_t)msg[ 0] |
+ (uint32_t)msg[ 1] << 8 |
+ (uint32_t)msg[ 2] << 16 |
+ (uint32_t)msg[ 3] << 24;
+ b = (uint32_t)msg[ 4] |
+ (uint32_t)msg[ 5] << 8 |
+ (uint32_t)msg[ 6] << 16 |
+ (uint32_t)msg[ 7] << 24;
+
+ c = d = pad;
+ for(i = 8; i < len; i++) {
+ c <<= 8;
+ c |= msg[i];
+ }
+ } else if (len >= 4) {
+ a = (uint32_t)msg[ 0] |
+ (uint32_t)msg[ 1] << 8 |
+ (uint32_t)msg[ 2] << 16 |
+ (uint32_t)msg[ 3] << 24;
+
+ b = c = d = pad;
+ for(i = 4; i < len; i++) {
+ b <<= 8;
+ b |= msg[i];
+ }
+ } else {
+ a = b = c = d = pad;
+ for(i = 0; i < len; i++) {
+ a <<= 8;
+ a |= msg[i];
+ }
+ }
+
+ TEACORE(FULLROUNDS);
+
+ /* return 0; */
+ return (h0 ^ h1);
+}
+
+/*
+ * What follows in this file is copyright 2000 by Hans Reiser, and the
+ * licensing of what follows is governed by README
+ * */
+uint32_t
+yura_hash(const signed char *msg, int len)
+{
+ int i;
+ int j, pow;
+ uint32_t a, c;
+
+ for (pow = 1, i = 1; i < len; i++)
+ pow = pow * 10;
+
+ if (len == 1)
+ a = msg[0] - 48;
+ else
+ a = (msg[0] - 48) * pow;
+
+ for (i = 1; i < len; i++) {
+ c = msg[i] - 48;
+ for (pow = 1, j = i; j < len - 1; j++)
+ pow = pow * 10;
+ a = a + c * pow;
+ }
+
+ for (; i < 40; i++) {
+ c = '0' - 48;
+ for (pow = 1, j = i; j < len - 1; j++)
+ pow = pow * 10;
+ a = a + c * pow;
+ }
+
+ for (; i < 256; i++) {
+ c = i;
+ for (pow = 1, j = i; j < len - 1; j++)
+ pow = pow * 10;
+ a = a + c * pow;
+ }
+
+ a = a << 7;
+ return (a);
+}
+
+uint32_t
+r5_hash(const signed char *msg, int len)
+{
+ uint32_t a;
+ const signed char *start;
+
+ a = 0;
+ start = msg;
+
+ while (*msg && msg < start + len) {
+ a += *msg << 4;
+ a += *msg >> 4;
+ a *= 11;
+ msg++;
+ }
+
+ return (a);
+}
diff --git a/sys/gnu/fs/reiserfs/reiserfs_inode.c b/sys/gnu/fs/reiserfs/reiserfs_inode.c
new file mode 100644
index 000000000000..13f88da7bdf4
--- /dev/null
+++ b/sys/gnu/fs/reiserfs/reiserfs_inode.c
@@ -0,0 +1,926 @@
+/*-
+ * Copyright 2000 Hans Reiser
+ * See README for licensing and copyright details
+ *
+ * Ported to FreeBSD by Jean-Sébastien Pédron <dumbbell@FreeBSD.org>
+ *
+ * $FreeBSD$
+ */
+
+#include <gnu/fs/reiserfs/reiserfs_fs.h>
+
+static b_strategy_t reiserfs_bufstrategy;
+
+/*
+ * Buffer operations for ReiserFS vnodes.
+ * We punt on VOP_BMAP, so we need to do strategy on the file's vnode
+ * rather than the underlying device's.
+ */
+static struct buf_ops reiserfs_vnbufops = {
+ .bop_name = "ReiserFS",
+ .bop_strategy = reiserfs_bufstrategy,
+};
+
+/* Default io size devuned in super.c */
+extern int reiserfs_default_io_size;
+void inode_set_bytes(struct reiserfs_node *ip, off_t bytes);
+
+/* Args for the create parameter of reiserfs_get_block */
+#define GET_BLOCK_NO_CREATE 0 /* Don't create new blocks or convert
+ tails */
+#define GET_BLOCK_CREATE 1 /* Add anything you need to find block */
+#define GET_BLOCK_NO_HOLE 2 /* Return ENOENT for file holes */
+#define GET_BLOCK_READ_DIRECT 4 /* Read the tail if indirect item not
+ found */
+#define GET_BLOCK_NO_ISEM 8 /* i_sem is not held, don't preallocate */
+#define GET_BLOCK_NO_DANGLE 16 /* Don't leave any transactions running */
+
+/* -------------------------------------------------------------------
+ * vnode operations
+ * -------------------------------------------------------------------*/
+
+int
+reiserfs_read(struct vop_read_args *ap)
+{
+ struct uio *uio;
+ struct vnode *vp;
+ struct reiserfs_node *ip;
+ struct reiserfs_sb_info *sbi;
+
+ int error;
+ long size;
+ daddr_t lbn;
+ off_t bytesinfile, offset;
+
+ uio = ap->a_uio;
+ vp = ap->a_vp;
+ ip = VTOI(vp);
+ sbi = ip->i_reiserfs;
+
+ size = sbi->s_blocksize;
+
+ for (error = 0; uio->uio_resid > 0;) {
+ if ((bytesinfile = ip->i_size - uio->uio_offset) <= 0)
+ break;
+
+ /* Compute the logical block number and its offset */
+ lbn = uio->uio_offset / size;
+ offset = uio->uio_offset % size;
+ reiserfs_log(LOG_DEBUG, "logical block number: %ju\n",
+ (intmax_t)lbn);
+ reiserfs_log(LOG_DEBUG, "block offset: %ju\n",
+ (intmax_t)offset);
+
+ /* Read file blocks */
+ reiserfs_log(LOG_DEBUG, "reiserfs_get_block(%ju)\n",
+ (intmax_t)lbn);
+ if ((error = reiserfs_get_block(ip, lbn, offset, uio)) != 0) {
+ reiserfs_log(LOG_DEBUG,
+ "reiserfs_get_block returned the error %d\n",
+ error);
+ break;
+ }
+ }
+
+ return (error);
+}
+
+static void
+reiserfs_bufstrategy(struct bufobj *bo, struct buf *bp)
+{
+ struct vnode *vp;
+ int rc;
+
+ vp = bo->bo_private;
+ KASSERT(bo == &vp->v_bufobj, ("BO/VP mismatch: vp %p bo %p != %p",
+ vp, &vp->v_bufobj, bo));
+ rc = VOP_STRATEGY(vp, bp);
+ KASSERT(rc == 0, ("ReiserFS VOP_STRATEGY failed: bp=%p, "
+ "vp=%p, rc=%d", bp, vp, rc));
+}
+
+int
+reiserfs_inactive(struct vop_inactive_args *ap)
+{
+ int error;
+ struct vnode *vp;
+ struct thread *td;
+ struct reiserfs_node *ip;
+
+ error = 0;
+ vp = ap->a_vp;
+ td = ap->a_td;
+ ip = VTOI(vp);
+
+ reiserfs_log(LOG_DEBUG, "deactivating inode used %d times\n",
+ vp->v_usecount);
+ if (prtactive && vrefcnt(vp) != 0)
+ vprint("ReiserFS/reclaim: pushing active", vp);
+
+#if 0
+ /* Ignore inodes related to stale file handles. */
+ if (ip->i_mode == 0)
+ goto out;
+
+out:
+#endif
+
+ /*
+ * If we are done with the inode, reclaim it so that it can be reused
+ * immediately.
+ */
+ if (ip->i_mode == 0) {
+ reiserfs_log(LOG_DEBUG, "recyling\n");
+ vrecycle(vp, td);
+ }
+
+ return (error);
+}
+
+int
+reiserfs_reclaim(struct vop_reclaim_args *ap)
+{
+ struct reiserfs_node *ip;
+ struct vnode *vp;
+
+ vp = ap->a_vp;
+
+ reiserfs_log(LOG_DEBUG, "reclaiming inode used %d times\n",
+ vp->v_usecount);
+ if (prtactive && vrefcnt(vp) != 0)
+ vprint("ReiserFS/reclaim: pushing active", vp);
+ ip = VTOI(vp);
+
+ /* XXX Update this node (write to the disk) */
+
+ /* Remove the inode from its hash chain. */
+ vfs_hash_remove(vp);
+
+ /* Purge old data structures associated with the inode. */
+ if (ip->i_devvp) {
+ reiserfs_log(LOG_DEBUG, "releasing device (0x%p)\n",
+ ip->i_devvp);
+ vrele(ip->i_devvp);
+ ip->i_devvp = NULL;
+ }
+
+ reiserfs_log(LOG_DEBUG, "free private data\n");
+ FREE(vp->v_data, M_REISERFSNODE);
+ vp->v_data = NULL;
+ vnode_destroy_vobject(vp);
+
+ return (0);
+}
+
+/* -------------------------------------------------------------------
+ * Functions from linux/fs/reiserfs/inode.c
+ * -------------------------------------------------------------------*/
+
+static void
+_make_cpu_key(struct cpu_key *key, int version,
+ uint32_t dirid, uint32_t objectid, off_t offset, int type, int length)
+{
+
+ key->version = version;
+
+ key->on_disk_key.k_dir_id = dirid;
+ key->on_disk_key.k_objectid = objectid;
+ set_cpu_key_k_offset(key, offset);
+ set_cpu_key_k_type(key, type);
+ key->key_length = length;
+}
+
+/*
+ * Take base of inode_key (it comes from inode always) (dirid, objectid)
+ * and version from an inode, set offset and type of key
+ */
+void
+make_cpu_key(struct cpu_key *key, struct reiserfs_node *ip, off_t offset,
+ int type, int length)
+{
+
+ _make_cpu_key(key, get_inode_item_key_version(ip),
+ le32toh(INODE_PKEY(ip)->k_dir_id),
+ le32toh(INODE_PKEY(ip)->k_objectid),
+ offset, type, length);
+}
+
+int
+reiserfs_get_block(struct reiserfs_node *ip, long block, off_t offset,
+ struct uio *uio)
+{
+ caddr_t blk = NULL, p;
+ struct cpu_key key;
+ /* unsigned long offset; */
+ INITIALIZE_PATH(path);
+ struct buf *bp, *blk_bp;
+ struct item_head *ih;
+ struct reiserfs_sb_info *sbi;
+ int blocknr, chars, done = 0, ret = 0, args = 0;
+
+ sbi = ip->i_reiserfs;
+
+ /* Prepare the key to look for the 'block'-th block of file */
+ reiserfs_log(LOG_DEBUG, "prepare cpu key\n");
+ make_cpu_key(&key, ip, (off_t)block * sbi->s_blocksize + 1, TYPE_ANY, 3);
+
+ /* research: */
+ reiserfs_log(LOG_DEBUG, "search for position\n");
+ if (search_for_position_by_key(sbi, &key, &path) != POSITION_FOUND) {
+ reiserfs_log(LOG_DEBUG, "position not found\n");
+ pathrelse(&path);
+#if 0
+ if (blk)
+ kunmap(bh_result->b_page);
+#endif
+ /*
+ * We do not return ENOENT if there is a hole but page is
+ * uptodate, because it means that there is some MMAPED data
+ * associated with it that is yet to be written to disk.
+ */
+ if ((args & GET_BLOCK_NO_HOLE)/* &&
+ !PageUptodate(bh_result->b_page)*/)
+ return (ENOENT);
+ return (0);
+ }
+ reiserfs_log(LOG_DEBUG, "position found\n");
+
+ bp = get_last_bp(&path);
+ ih = get_ih(&path);
+
+ if (is_indirect_le_ih(ih)) {
+ off_t xfersize;
+ uint32_t *ind_item = (uint32_t *)B_I_PITEM(bp, ih);
+
+ reiserfs_log(LOG_DEBUG, "item is INDIRECT\n");
+
+ blocknr = get_block_num(ind_item, path.pos_in_item);
+ reiserfs_log(LOG_DEBUG, "block number: %d "
+ "(ind_item=%p, pos_in_item=%u)\n",
+ blocknr, ind_item, path.pos_in_item);
+
+ xfersize = MIN(sbi->s_blocksize - offset,
+ ip->i_size - uio->uio_offset);
+ xfersize = MIN(xfersize, uio->uio_resid);
+
+ if (blocknr) {
+ ret = bread(sbi->s_devvp,
+ blocknr * btodb(sbi->s_blocksize),
+ sbi->s_blocksize, NOCRED, &blk_bp);
+ reiserfs_log(LOG_DEBUG, "xfersize: %ju\n",
+ (intmax_t)xfersize);
+ ret = uiomove(blk_bp->b_data + offset, xfersize, uio);
+ brelse(blk_bp);
+ } else {
+ /*
+ * We do not return ENOENT if there is a hole but
+ * page is uptodate, because it means That there
+ * is some MMAPED data associated with it that
+ * is yet to be written to disk.
+ */
+ if ((args & GET_BLOCK_NO_HOLE)/* &&
+ !PageUptodate(bh_result->b_page)*/)
+ ret = (ENOENT);
+
+ /* Skip this hole */
+ uio->uio_resid -= xfersize;
+ uio->uio_offset += xfersize;
+ }
+
+ pathrelse(&path);
+ return (ret);
+ }
+
+ reiserfs_log(LOG_DEBUG, "item should be DIRECT\n");
+
+#if 0
+ /* Requested data are in direct item(s) */
+ if (!(args & GET_BLOCK_READ_DIRECT)) {
+ /*
+ * We are called by bmap. FIXME: we can not map block of
+ * file when it is stored in direct item(s)
+ */
+ pathrelse(&path);
+#if 0
+ if (blk)
+ kunmap(bh_result->b_page);
+#endif
+ return (ENOENT);
+ }
+#endif
+
+#if 0
+ /*
+ * If we've got a direct item, and the buffer or page was uptodate, we
+ * don't want to pull data off disk again. Skip to the end, where we
+ * map the buffer and return
+ */
+ if (buffer_uptodate(bh_result)) {
+ goto finished;
+ } else
+ /*
+ * grab_tail_page can trigger calls to reiserfs_get_block
+ * on up to date pages without any buffers. If the page
+ * is up to date, we don't want read old data off disk.
+ * Set the up to date bit on the buffer instead and jump
+ * to the end
+ */
+ if (!bh_result->b_page || PageUptodate(bh_result->b_page)) {
+ set_buffer_uptodate(bh_result);
+ goto finished;
+ }
+#endif
+
+#if 0
+ /* Read file tail into part of page */
+ offset = (cpu_key_k_offset(&key) - 1) & (PAGE_CACHE_SIZE - 1);
+ fs_gen = get_generation(ip->i_reiserfs);
+ copy_item_head(&tmp_ih, ih);
+#endif
+
+#if 0
+ /*
+ * We only want to kmap if we are reading the tail into the page. this
+ * is not the common case, so we don't kmap until we are sure we need
+ * to. But, this means the item might move if kmap schedules
+ */
+ if (!blk) {
+ blk = (char *)kmap(bh_result->b_page);
+ if (fs_changed (fs_gen, sbi) && item_moved(&tmp_ih, &path))
+ goto research;
+ }
+ blk += offset;
+ memset(blk, 0, sbi->s_blocksize);
+#endif
+ if (!blk) {
+ reiserfs_log(LOG_DEBUG, "allocating buffer\n");
+ blk = malloc(ip->i_size, M_REISERFSNODE, M_WAITOK | M_ZERO);
+ if (!blk)
+ return (ENOMEM);
+ }
+ /* p += offset; */
+
+ p = blk;
+ do {
+ if (!is_direct_le_ih(ih)) {
+ reiserfs_log(LOG_ERR, "BUG\n");
+ return (ENOENT); /* XXX Wrong error code */
+ }
+
+ /*
+ * Make sure we don't read more bytes than actually exist
+ * in the file. This can happen in odd cases where i_size
+ * isn't correct, and when direct item padding results in
+ * a few extra bytes at the end of the direct item
+ */
+ if ((le_ih_k_offset(ih) + path.pos_in_item) > ip->i_size)
+ break;
+
+ if ((le_ih_k_offset(ih) - 1 + ih_item_len(ih)) > ip->i_size) {
+ chars = ip->i_size - (le_ih_k_offset(ih) - 1) -
+ path.pos_in_item;
+ done = 1;
+ } else {
+ chars = ih_item_len(ih) - path.pos_in_item;
+ }
+ reiserfs_log(LOG_DEBUG, "copying %d bytes\n", chars);
+ memcpy(p, B_I_PITEM(bp, ih) + path.pos_in_item, chars);
+ if (done) {
+ reiserfs_log(LOG_DEBUG, "copy done\n");
+ break;
+ }
+
+ p += chars;
+
+ if (PATH_LAST_POSITION(&path) != (B_NR_ITEMS(bp) - 1))
+ /*
+ * We done, if read direct item is not the last
+ * item of node
+ * FIXME: we could try to check right delimiting
+ * key to see whether direct item continues in
+ * the right neighbor or rely on i_size
+ */
+ break;
+
+ /* Update key to look for the next piece */
+ set_cpu_key_k_offset(&key, cpu_key_k_offset(&key) + chars);
+ if (search_for_position_by_key(sbi, &key, &path) !=
+ POSITION_FOUND)
+ /*
+ * We read something from tail, even if now we got
+ * IO_ERROR
+ */
+ break;
+
+ bp = get_last_bp(&path);
+ ih = get_ih(&path);
+ } while (1);
+
+ /* finished: */
+ pathrelse(&path);
+ /*
+ * This buffer has valid data, but isn't valid for io. mapping it to
+ * block #0 tells the rest of reiserfs it just has a tail in it
+ */
+ ret = uiomove(blk, ip->i_size, uio);
+ free(blk, M_REISERFSNODE);
+ return (ret);
+}
+
+/*
+ * Compute real number of used bytes by file
+ * Following three functions can go away when we'll have enough space in
+ * stat item
+ */
+static int
+real_space_diff(struct reiserfs_node *ip, int sd_size)
+{
+ int bytes;
+ off_t blocksize = ip->i_reiserfs->s_blocksize;
+
+ if (S_ISLNK(ip->i_mode) || S_ISDIR(ip->i_mode))
+ return (sd_size);
+
+ /* End of file is also in full block with indirect reference, so round
+ * up to the next block.
+ *
+ * There is just no way to know if the tail is actually packed on the
+ * file, so we have to assume it isn't. When we pack the tail, we add
+ * 4 bytes to pretend there really is an unformatted node pointer. */
+ bytes = ((ip->i_size + (blocksize - 1)) >>
+ ip->i_reiserfs->s_blocksize_bits) * UNFM_P_SIZE + sd_size;
+
+ return (bytes);
+}
+
+static inline off_t
+to_real_used_space(struct reiserfs_node *ip, unsigned long blocks, int sd_size)
+{
+
+ if (S_ISLNK(ip->i_mode) || S_ISDIR(ip->i_mode)) {
+ return ip->i_size + (off_t)(real_space_diff(ip, sd_size));
+ }
+
+ return ((off_t)real_space_diff(ip, sd_size)) + (((off_t)blocks) << 9);
+}
+
+void
+inode_set_bytes(struct reiserfs_node *ip, off_t bytes)
+{
+
+ ip->i_blocks = bytes >> 9;
+ ip->i_bytes = bytes & 511;
+}
+
+/* Called by read_locked_inode */
+static void
+init_inode(struct reiserfs_node *ip, struct path *path)
+{
+ struct buf *bp;
+ struct item_head *ih;
+ uint32_t rdev;
+
+ bp = PATH_PLAST_BUFFER(path);
+ ih = PATH_PITEM_HEAD(path);
+
+ reiserfs_log(LOG_DEBUG, "copy the key (objectid=%d, dirid=%d)\n",
+ ih->ih_key.k_objectid, ih->ih_key.k_dir_id);
+ copy_key(INODE_PKEY(ip), &(ih->ih_key));
+ /* ip->i_blksize = reiserfs_default_io_size; */
+
+ reiserfs_log(LOG_DEBUG, "reset some inode structure members\n");
+ REISERFS_I(ip)->i_flags = 0;
+#if 0
+ REISERFS_I(ip)->i_prealloc_block = 0;
+ REISERFS_I(ip)->i_prealloc_count = 0;
+ REISERFS_I(ip)->i_trans_id = 0;
+ REISERFS_I(ip)->i_jl = NULL;
+ REISERFS_I(ip)->i_acl_access = NULL;
+ REISERFS_I(ip)->i_acl_default = NULL;
+#endif
+
+ if (stat_data_v1(ih)) {
+ reiserfs_log(LOG_DEBUG, "reiserfs/init_inode: stat data v1\n");
+ struct stat_data_v1 *sd;
+ unsigned long blocks;
+
+ sd = (struct stat_data_v1 *)B_I_PITEM(bp, ih);
+
+ reiserfs_log(LOG_DEBUG,
+ "reiserfs/init_inode: filling more members\n");
+ set_inode_item_key_version(ip, KEY_FORMAT_3_5);
+ set_inode_sd_version(ip, STAT_DATA_V1);
+ ip->i_mode = sd_v1_mode(sd);
+ ip->i_nlink = sd_v1_nlink(sd);
+ ip->i_uid = sd_v1_uid(sd);
+ ip->i_gid = sd_v1_gid(sd);
+ ip->i_size = sd_v1_size(sd);
+ ip->i_atime.tv_sec = sd_v1_atime(sd);
+ ip->i_mtime.tv_sec = sd_v1_mtime(sd);
+ ip->i_ctime.tv_sec = sd_v1_ctime(sd);
+ ip->i_atime.tv_nsec = 0;
+ ip->i_ctime.tv_nsec = 0;
+ ip->i_mtime.tv_nsec = 0;
+
+ reiserfs_log(LOG_DEBUG, " mode = %08x\n", ip->i_mode);
+ reiserfs_log(LOG_DEBUG, " nlink = %d\n", ip->i_nlink);
+ reiserfs_log(LOG_DEBUG, " owner = %d:%d\n", ip->i_uid,
+ ip->i_gid);
+ reiserfs_log(LOG_DEBUG, " size = %ju\n",
+ (intmax_t)ip->i_size);
+ reiserfs_log(LOG_DEBUG, " atime = %jd\n",
+ (intmax_t)ip->i_atime.tv_sec);
+ reiserfs_log(LOG_DEBUG, " mtime = %jd\n",
+ (intmax_t)ip->i_mtime.tv_sec);
+ reiserfs_log(LOG_DEBUG, " ctime = %jd\n",
+ (intmax_t)ip->i_ctime.tv_sec);
+
+ ip->i_blocks = sd_v1_blocks(sd);
+ ip->i_generation = le32toh(INODE_PKEY(ip)->k_dir_id);
+ blocks = (ip->i_size + 511) >> 9;
+ blocks = _ROUND_UP(blocks, ip->i_reiserfs->s_blocksize >> 9);
+ if (ip->i_blocks > blocks) {
+ /*
+ * There was a bug in <= 3.5.23 when i_blocks could
+ * take negative values. Starting from 3.5.17 this
+ * value could even be stored in stat data. For such
+ * files we set i_blocks based on file size. Just 2
+ * notes: this can be wrong for sparce files. On-disk
+ * value will be only updated if file's inode will
+ * ever change.
+ */
+ ip->i_blocks = blocks;
+ }
+
+ rdev = sd_v1_rdev(sd);
+ REISERFS_I(ip)->i_first_direct_byte =
+ sd_v1_first_direct_byte(sd);
+
+ /*
+ * An early bug in the quota code can give us an odd number
+ * for the block count. This is incorrect, fix it here.
+ */
+ if (ip->i_blocks & 1) {
+ ip->i_blocks++ ;
+ }
+ inode_set_bytes(ip, to_real_used_space(ip, ip->i_blocks,
+ SD_V1_SIZE));
+
+ /*
+ * nopack is initially zero for v1 objects. For v2 objects,
+ * nopack is initialised from sd_attrs
+ */
+ REISERFS_I(ip)->i_flags &= ~i_nopack_mask;
+ reiserfs_log(LOG_DEBUG, "...done\n");
+ } else {
+ reiserfs_log(LOG_DEBUG, "stat data v2\n");
+ /*
+ * New stat data found, but object may have old items
+ * (directories and symlinks)
+ */
+ struct stat_data *sd = (struct stat_data *)B_I_PITEM(bp, ih);
+
+ reiserfs_log(LOG_DEBUG, "filling more members\n");
+ ip->i_mode = sd_v2_mode(sd);
+ ip->i_nlink = sd_v2_nlink(sd);
+ ip->i_uid = sd_v2_uid(sd);
+ ip->i_size = sd_v2_size(sd);
+ ip->i_gid = sd_v2_gid(sd);
+ ip->i_mtime.tv_sec = sd_v2_mtime(sd);
+ ip->i_atime.tv_sec = sd_v2_atime(sd);
+ ip->i_ctime.tv_sec = sd_v2_ctime(sd);
+ ip->i_ctime.tv_nsec = 0;
+ ip->i_mtime.tv_nsec = 0;
+ ip->i_atime.tv_nsec = 0;
+
+ reiserfs_log(LOG_DEBUG, " mode = %08x\n", ip->i_mode);
+ reiserfs_log(LOG_DEBUG, " nlink = %d\n", ip->i_nlink);
+ reiserfs_log(LOG_DEBUG, " owner = %d:%d\n", ip->i_uid,
+ ip->i_gid);
+ reiserfs_log(LOG_DEBUG, " size = %ju\n",
+ (intmax_t)ip->i_size);
+ reiserfs_log(LOG_DEBUG, " atime = %jd\n",
+ (intmax_t)ip->i_atime.tv_sec);
+ reiserfs_log(LOG_DEBUG, " mtime = %jd\n",
+ (intmax_t)ip->i_mtime.tv_sec);
+ reiserfs_log(LOG_DEBUG, " ctime = %jd\n",
+ (intmax_t)ip->i_ctime.tv_sec);
+
+ ip->i_blocks = sd_v2_blocks(sd);
+ rdev = sd_v2_rdev(sd);
+ reiserfs_log(LOG_DEBUG, " blocks = %u\n", ip->i_blocks);
+
+ if (S_ISCHR(ip->i_mode) || S_ISBLK(ip->i_mode))
+ ip->i_generation = le32toh(INODE_PKEY(ip)->k_dir_id);
+ else
+ ip->i_generation = sd_v2_generation(sd);
+
+ if (S_ISDIR(ip->i_mode) || S_ISLNK(ip->i_mode))
+ set_inode_item_key_version(ip, KEY_FORMAT_3_5);
+ else
+ set_inode_item_key_version(ip, KEY_FORMAT_3_6);
+
+ REISERFS_I(ip)->i_first_direct_byte = 0;
+ set_inode_sd_version(ip, STAT_DATA_V2);
+ inode_set_bytes(ip, to_real_used_space(ip, ip->i_blocks,
+ SD_V2_SIZE));
+
+ /*
+ * Read persistent inode attributes from sd and initalise
+ * generic inode flags from them
+ */
+ REISERFS_I(ip)->i_attrs = sd_v2_attrs(sd);
+ sd_attrs_to_i_attrs(sd_v2_attrs(sd), ip);
+ reiserfs_log(LOG_DEBUG, "...done\n");
+ }
+
+ pathrelse(path);
+ if (S_ISREG(ip->i_mode)) {
+ reiserfs_log(LOG_DEBUG, "this inode is a regular file\n");
+ //ip->i_op = &reiserfs_file_ip_operations;
+ //ip->i_fop = &reiserfs_file_operations;
+ //ip->i_mapping->a_ops = &reiserfs_address_space_operations ;
+ } else if (S_ISDIR(ip->i_mode)) {
+ reiserfs_log(LOG_DEBUG, "this inode is a directory\n");
+ //ip->i_op = &reiserfs_dir_ip_operations;
+ //ip->i_fop = &reiserfs_dir_operations;
+ } else if (S_ISLNK(ip->i_mode)) {
+ reiserfs_log(LOG_DEBUG, "this inode is a symlink\n");
+ //ip->i_op = &reiserfs_symlink_ip_operations;
+ //ip->i_mapping->a_ops = &reiserfs_address_space_operations;
+ } else {
+ reiserfs_log(LOG_DEBUG, "this inode is something unknown in "
+ "this universe\n");
+ ip->i_blocks = 0;
+ //ip->i_op = &reiserfs_special_ip_operations;
+ //init_special_ip(ip, ip->i_mode, new_decode_dev(rdev));
+ }
+}
+
+/*
+ * reiserfs_read_locked_inode is called to read the inode off disk, and
+ * it does a make_bad_inode when things go wrong. But, we need to make
+ * sure and clear the key in the private portion of the inode, otherwise
+ * a corresponding iput might try to delete whatever object the inode
+ * last represented.
+ */
+static void
+reiserfs_make_bad_inode(struct reiserfs_node *ip) {
+
+ memset(INODE_PKEY(ip), 0, KEY_SIZE);
+ //make_bad_inode(inode);
+}
+
+void
+reiserfs_read_locked_inode(struct reiserfs_node *ip,
+ struct reiserfs_iget_args *args)
+{
+ INITIALIZE_PATH(path_to_sd);
+ struct cpu_key key;
+ unsigned long dirino;
+ int retval;
+
+ dirino = args->dirid;
+
+ /*
+ * Set version 1, version 2 could be used too, because stat data
+ * key is the same in both versions
+ */
+ key.version = KEY_FORMAT_3_5;
+ key.on_disk_key.k_dir_id = dirino;
+ key.on_disk_key.k_objectid = ip->i_number;
+ key.on_disk_key.u.k_offset_v1.k_offset = SD_OFFSET;
+ key.on_disk_key.u.k_offset_v1.k_uniqueness = SD_UNIQUENESS;
+
+ /* Look for the object's stat data */
+ retval = search_item(ip->i_reiserfs, &key, &path_to_sd);
+ if (retval == IO_ERROR) {
+ reiserfs_log(LOG_ERR,
+ "I/O failure occured trying to find stat"
+ "data %u/%u\n",
+ key.on_disk_key.k_dir_id, key.on_disk_key.k_objectid);
+ reiserfs_make_bad_inode(ip);
+ return;
+ }
+ if (retval != ITEM_FOUND) {
+ /*
+ * A stale NFS handle can trigger this without it being
+ * an error
+ */
+ reiserfs_log(LOG_ERR,
+ "item not found (objectid=%u, dirid=%u)\n",
+ key.on_disk_key.k_objectid, key.on_disk_key.k_dir_id);
+ pathrelse(&path_to_sd);
+ reiserfs_make_bad_inode(ip);
+ ip->i_nlink = 0;
+ return;
+ }
+
+ init_inode(ip, &path_to_sd);
+
+ /*
+ * It is possible that knfsd is trying to access inode of a file
+ * that is being removed from the disk by some other thread. As
+ * we update sd on unlink all that is required is to check for
+ * nlink here. This bug was first found by Sizif when debugging
+ * SquidNG/Butterfly, forgotten, and found again after Philippe
+ * Gramoulle <philippe.gramoulle@mmania.com> reproduced it.
+ *
+ * More logical fix would require changes in fs/inode.c:iput() to
+ * remove inode from hash-table _after_ fs cleaned disk stuff up and
+ * in iget() to return NULL if I_FREEING inode is found in hash-table.
+ */
+ /*
+ * Currently there is one place where it's ok to meet inode with
+ * nlink == 0: processing of open-unlinked and half-truncated files
+ * during mount (fs/reiserfs/super.c:finish_unfinished()).
+ */
+ if((ip->i_nlink == 0) &&
+ !REISERFS_SB(ip->i_reiserfs)->s_is_unlinked_ok ) {
+ reiserfs_log(LOG_WARNING, "dead inode read from disk. This is "
+ "likely to be race with knfsd. Ignore");
+ reiserfs_make_bad_inode(ip);
+ }
+
+ /* Init inode should be relsing */
+ reiserfs_check_path(&path_to_sd);
+}
+
+int
+reiserfs_iget(
+ struct mount *mp, const struct cpu_key *key,
+ struct vnode **vpp, struct thread *td)
+{
+ int error, flags;
+ struct cdev *dev;
+ struct vnode *vp;
+ struct reiserfs_node *ip;
+ struct reiserfs_mount *rmp;
+
+ struct reiserfs_iget_args args;
+
+ //restart:
+ /* Check if the inode cache contains it */
+ // XXX LK_EXCLUSIVE ?
+ flags = LK_EXCLUSIVE;
+ error = vfs_hash_get(mp, key->on_disk_key.k_objectid, flags,
+ td, vpp, NULL, NULL);
+ if (error || *vpp != NULL)
+ return (error);
+
+ rmp = VFSTOREISERFS(mp);
+ dev = rmp->rm_dev;
+
+ /*
+ * If this MALLOC() is performed after the getnewvnode() it might
+ * block, leaving a vnode with a NULL v_data to be found by
+ * reiserfs_sync() if a sync happens to fire right then, which
+ * will cause a panic because reiserfs_sync() blindly dereferences
+ * vp->v_data (as well it should).
+ */
+ reiserfs_log(LOG_DEBUG, "malloc(struct reiserfs_node)\n");
+ ip = malloc(sizeof(struct reiserfs_node), M_REISERFSNODE,
+ M_WAITOK | M_ZERO);
+
+ /* Allocate a new vnode/inode. */
+ reiserfs_log(LOG_DEBUG, "getnewvnode\n");
+ if ((error =
+ getnewvnode("reiserfs", mp, &reiserfs_vnodeops, &vp)) != 0) {
+ *vpp = NULL;
+ free(ip, M_REISERFSNODE);
+ reiserfs_log(LOG_DEBUG, "getnewvnode FAILED\n");
+ return (error);
+ }
+
+ args.dirid = key->on_disk_key.k_dir_id;
+ args.objectid = key->on_disk_key.k_objectid;
+
+ reiserfs_log(LOG_DEBUG, "filling *ip\n");
+ vp->v_data = ip;
+ ip->i_vnode = vp;
+ ip->i_dev = dev;
+ ip->i_number = args.objectid;
+ ip->i_ino = args.dirid;
+ ip->i_reiserfs = rmp->rm_reiserfs;
+
+ vp->v_bufobj.bo_ops = &reiserfs_vnbufops;
+ vp->v_bufobj.bo_private = vp;
+
+ /* If this is the root node, set the VV_ROOT flag */
+ if (ip->i_number == REISERFS_ROOT_OBJECTID &&
+ ip->i_ino == REISERFS_ROOT_PARENT_OBJECTID)
+ vp->v_vflag |= VV_ROOT;
+
+#if 0
+ if (VOP_LOCK(vp, LK_EXCLUSIVE, td) != 0)
+ panic("reiserfs/iget: unexpected lock failure");
+
+ /*
+ * Exclusively lock the vnode before adding to hash. Note, that we
+ * must not release nor downgrade the lock (despite flags argument
+ * says) till it is fully initialized.
+ */
+ lockmgr(vp->v_vnlock, LK_EXCLUSIVE, (struct mtx *)0, td);
+#endif
+
+ error = vfs_hash_insert(vp, key->on_disk_key.k_objectid, flags,
+ td, vpp, NULL, NULL);
+ if (error || *vpp != NULL)
+ return (error);
+
+ /* Read the inode */
+ reiserfs_log(LOG_DEBUG, "call reiserfs_read_locked_inode ("
+ "objectid=%d,dirid=%d)\n", args.objectid, args.dirid);
+ reiserfs_read_locked_inode(ip, &args);
+
+ ip->i_devvp = rmp->rm_devvp;
+ VREF(ip->i_devvp);
+
+ switch(vp->v_type = IFTOVT(ip->i_mode)) {
+ case VBLK:
+ reiserfs_log(LOG_DEBUG, "vnode type VBLK\n");
+ vp->v_op = &reiserfs_specops;
+ break;
+#if 0
+ case VCHR:
+ reiserfs_log(LOG_DEBUG, "vnode type VCHR\n");
+ vp->v_op = &reiserfs_specops;
+ vp = addaliasu(vp, ip->i_rdev);
+ ip->i_vnode = vp;
+ break;
+ case VFIFO:
+ reiserfs_log(LOG_DEBUG, "vnode type VFIFO\n");
+ vp->v_op = reiserfs_fifoop_p;
+ break;
+#endif
+ default:
+ break;
+ }
+
+ *vpp = vp;
+ return (0);
+}
+
+void
+sd_attrs_to_i_attrs(uint16_t sd_attrs, struct reiserfs_node *ip)
+{
+
+ if (reiserfs_attrs(ip->i_reiserfs)) {
+#if 0
+ if (sd_attrs & REISERFS_SYNC_FL)
+ ip->i_flags |= S_SYNC;
+ else
+ ip->i_flags &= ~S_SYNC;
+#endif
+ if (sd_attrs & REISERFS_IMMUTABLE_FL)
+ ip->i_flags |= IMMUTABLE;
+ else
+ ip->i_flags &= ~IMMUTABLE;
+ if (sd_attrs & REISERFS_APPEND_FL)
+ ip->i_flags |= APPEND;
+ else
+ ip->i_flags &= ~APPEND;
+#if 0
+ if (sd_attrs & REISERFS_NOATIME_FL)
+ ip->i_flags |= S_NOATIME;
+ else
+ ip->i_flags &= ~S_NOATIME;
+ if (sd_attrs & REISERFS_NOTAIL_FL)
+ REISERFS_I(ip)->i_flags |= i_nopack_mask;
+ else
+ REISERFS_I(ip)->i_flags &= ~i_nopack_mask;
+#endif
+ }
+}
+
+void
+i_attrs_to_sd_attrs(struct reiserfs_node *ip, uint16_t *sd_attrs)
+{
+
+ if (reiserfs_attrs(ip->i_reiserfs)) {
+#if 0
+ if (ip->i_flags & S_SYNC)
+ *sd_attrs |= REISERFS_SYNC_FL;
+ else
+ *sd_attrs &= ~REISERFS_SYNC_FL;
+#endif
+ if (ip->i_flags & IMMUTABLE)
+ *sd_attrs |= REISERFS_IMMUTABLE_FL;
+ else
+ *sd_attrs &= ~REISERFS_IMMUTABLE_FL;
+ if (ip->i_flags & APPEND)
+ *sd_attrs |= REISERFS_APPEND_FL;
+ else
+ *sd_attrs &= ~REISERFS_APPEND_FL;
+#if 0
+ if (ip->i_flags & S_NOATIME)
+ *sd_attrs |= REISERFS_NOATIME_FL;
+ else
+ *sd_attrs &= ~REISERFS_NOATIME_FL;
+ if (REISERFS_I(ip)->i_flags & i_nopack_mask)
+ *sd_attrs |= REISERFS_NOTAIL_FL;
+ else
+ *sd_attrs &= ~REISERFS_NOTAIL_FL;
+#endif
+ }
+}
diff --git a/sys/gnu/fs/reiserfs/reiserfs_item_ops.c b/sys/gnu/fs/reiserfs/reiserfs_item_ops.c
new file mode 100644
index 000000000000..7b10183a79fb
--- /dev/null
+++ b/sys/gnu/fs/reiserfs/reiserfs_item_ops.c
@@ -0,0 +1,158 @@
+/*-
+ * Copyright 2000 Hans Reiser
+ * See README for licensing and copyright details
+ *
+ * Ported to FreeBSD by Jean-Sébastien Pédron <jspedron@club-internet.fr>
+ *
+ * $FreeBSD$
+ */
+
+#include <gnu/fs/reiserfs/reiserfs_fs.h>
+
+/* -------------------------------------------------------------------
+ * Stat data functions
+ * -------------------------------------------------------------------*/
+
+static int
+sd_bytes_number(struct item_head *ih, int block_size)
+{
+
+ return (0);
+}
+
+struct item_operations stat_data_ops = {
+ .bytes_number = sd_bytes_number,
+ //.decrement_key = sd_decrement_key,
+ //.is_left_mergeable = sd_is_left_mergeable,
+ //.print_item = sd_print_item,
+ //.check_item = sd_check_item,
+
+ //.create_vi = sd_create_vi,
+ //.check_left = sd_check_left,
+ //.check_right = sd_check_right,
+ //.part_size = sd_part_size,
+ //.unit_num = sd_unit_num,
+ //.print_vi = sd_print_vi
+};
+
+/* -------------------------------------------------------------------
+ * Direct item functions
+ * -------------------------------------------------------------------*/
+
+static int
+direct_bytes_number(struct item_head *ih, int block_size)
+{
+
+ return (ih_item_len(ih));
+}
+
+struct item_operations direct_ops = {
+ .bytes_number = direct_bytes_number,
+ //.decrement_key = direct_decrement_key,
+ //.is_left_mergeable = direct_is_left_mergeable,
+ //.print_item = direct_print_item,
+ //.check_item = direct_check_item,
+
+ //.create_vi = direct_create_vi,
+ //.check_left = direct_check_left,
+ //.check_right = direct_check_right,
+ //.part_size = direct_part_size,
+ //.unit_num = direct_unit_num,
+ //.print_vi = direct_print_vi
+};
+
+/* -------------------------------------------------------------------
+ * Indirect item functions
+ * -------------------------------------------------------------------*/
+
+static int
+indirect_bytes_number(struct item_head *ih, int block_size)
+{
+
+ return (ih_item_len(ih) / UNFM_P_SIZE * block_size);
+}
+
+struct item_operations indirect_ops = {
+ .bytes_number = indirect_bytes_number,
+ //.decrement_key = indirect_decrement_key,
+ //.is_left_mergeable = indirect_is_left_mergeable,
+ //.print_item = indirect_print_item,
+ //.check_item = indirect_check_item,
+
+ //.create_vi = indirect_create_vi,
+ //.check_left = indirect_check_left,
+ //.check_right = indirect_check_right,
+ //.part_size = indirect_part_size,
+ //.unit_num = indirect_unit_num,
+ //.print_vi = indirect_print_vi
+};
+
+/* -------------------------------------------------------------------
+ * Direntry functions
+ * -------------------------------------------------------------------*/
+
+static int
+direntry_bytes_number(struct item_head *ih, int block_size)
+{
+
+ reiserfs_log(LOG_WARNING, "bytes number is asked for direntry\n");
+ return (0);
+}
+
+struct item_operations direntry_ops = {
+ .bytes_number = direntry_bytes_number,
+ //.decrement_key = direntry_decrement_key,
+ //.is_left_mergeable = direntry_is_left_mergeable,
+ //.print_item = direntry_print_item,
+ //.check_item = direntry_check_item,
+
+ //.create_vi = direntry_create_vi,
+ //.check_left = direntry_check_left,
+ //.check_right = direntry_check_right,
+ //.part_size = direntry_part_size,
+ //.unit_num = direntry_unit_num,
+ //.print_vi = direntry_print_vi
+};
+
+/* -------------------------------------------------------------------
+ * Error catching functions to catch errors caused by incorrect item
+ * types.
+ * -------------------------------------------------------------------*/
+
+static int
+errcatch_bytes_number(struct item_head *ih, int block_size)
+{
+
+ reiserfs_log(LOG_WARNING, "invalid item type observed, run fsck ASAP");
+ return (0);
+}
+
+struct item_operations errcatch_ops = {
+ errcatch_bytes_number,
+ //errcatch_decrement_key,
+ //errcatch_is_left_mergeable,
+ //errcatch_print_item,
+ //errcatch_check_item,
+
+ //errcatch_create_vi,
+ //errcatch_check_left,
+ //errcatch_check_right,
+ //errcatch_part_size,
+ //errcatch_unit_num,
+ //errcatch_print_vi
+};
+
+#if !(TYPE_STAT_DATA == 0 && TYPE_INDIRECT == 1 && \
+ TYPE_DIRECT == 2 && TYPE_DIRENTRY == 3)
+#error
+#endif
+
+struct item_operations *item_ops[TYPE_ANY + 1] = {
+ &stat_data_ops,
+ &indirect_ops,
+ &direct_ops,
+ &direntry_ops,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ &errcatch_ops /* This is to catch errors with invalid type (15th
+ entry for TYPE_ANY) */
+};
diff --git a/sys/gnu/fs/reiserfs/reiserfs_mount.h b/sys/gnu/fs/reiserfs/reiserfs_mount.h
new file mode 100644
index 000000000000..0db218be938e
--- /dev/null
+++ b/sys/gnu/fs/reiserfs/reiserfs_mount.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2000 Hans Reiser
+ * See README for licensing and copyright details
+ *
+ * Ported to FreeBSD by Jean-Sébastien Pédron <jspedron@club-internet.fr>
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _GNU_REISERFS_REISERFS_MOUNT_H
+#define _GNU_REISERFS_REISERFS_MOUNT_H
+
+#define REISERFS_FOR_FREEBSD_VERSION "0.1.6"
+
+#if defined(_KERNEL)
+
+#ifdef MALLOC_DECLARE
+MALLOC_DECLARE(M_REISERFSMNT);
+MALLOC_DECLARE(M_REISERFSPATH);
+MALLOC_DECLARE(M_REISERFSNODE);
+MALLOC_DECLARE(M_REISERFSCOOKIES);
+#endif
+
+/* This structure describes the ReiserFS specific mount structure data. */
+struct reiserfs_mount {
+ struct mount *rm_mountp;
+ struct cdev *rm_dev;
+ struct vnode *rm_devvp;
+
+ struct reiserfs_sb_info *rm_reiserfs;
+
+ struct g_consumer *rm_cp;
+ struct bufobj *rm_bo;
+};
+
+/* Convert mount ptr to reiserfs_mount ptr. */
+#define VFSTOREISERFS(mp) ((struct reiserfs_mount *)((mp)->mnt_data))
+
+#endif /* defined(_KERNEL) */
+
+/* Arguments to mount ReiserFS filesystems. */
+struct reiserfs_args {
+ char *fspec; /* blocks special holding the fs to mount */
+ struct export_args export; /* network export information */
+};
+
+#endif /* !defined _GNU_REISERFS_REISERFS_MOUNT_H */
diff --git a/sys/gnu/fs/reiserfs/reiserfs_namei.c b/sys/gnu/fs/reiserfs/reiserfs_namei.c
new file mode 100644
index 000000000000..6234d1fbee9a
--- /dev/null
+++ b/sys/gnu/fs/reiserfs/reiserfs_namei.c
@@ -0,0 +1,699 @@
+/*-
+ * Copyright 2000 Hans Reiser
+ * See README for licensing and copyright details
+ *
+ * Ported to FreeBSD by Jean-Sébastien Pédron <jspedron@club-internet.fr>
+ *
+ * $FreeBSD$
+ */
+
+#include <gnu/fs/reiserfs/reiserfs_fs.h>
+
+static int reiserfs_find_entry(struct reiserfs_node *dp,
+ const char *name, int namelen,
+ struct path * path_to_entry, struct reiserfs_dir_entry *de);
+
+MALLOC_DEFINE(M_REISERFSCOOKIES, "ReiserFS cookies",
+ "ReiserFS VOP_READDIR cookies");
+
+/* -------------------------------------------------------------------
+ * Lookup functions
+ * -------------------------------------------------------------------*/
+
+int
+reiserfs_lookup(struct vop_cachedlookup_args *ap)
+{
+ int error, retval;
+ struct vnode *vdp = ap->a_dvp;
+ struct vnode **vpp = ap->a_vpp;
+ struct componentname *cnp = ap->a_cnp;
+
+ int flags = cnp->cn_flags;
+ struct thread *td = cnp->cn_thread;
+
+ struct vnode *vp;
+ struct vnode *pdp; /* Saved dp during symlink work */
+ struct reiserfs_node *dp;
+ struct reiserfs_dir_entry de;
+ INITIALIZE_PATH(path_to_entry);
+
+ char c = cnp->cn_nameptr[cnp->cn_namelen];
+ cnp->cn_nameptr[cnp->cn_namelen] = '\0';
+ reiserfs_log(LOG_DEBUG, "looking for `%s', %ld (%s)\n",
+ cnp->cn_nameptr, cnp->cn_namelen, cnp->cn_pnbuf);
+ cnp->cn_nameptr[cnp->cn_namelen] = c;
+
+ vp = NULL;
+ dp = VTOI(vdp);
+
+ if (REISERFS_MAX_NAME(dp->i_reiserfs->s_blocksize) < cnp->cn_namelen)
+ return (ENAMETOOLONG);
+
+ reiserfs_log(LOG_DEBUG, "searching entry\n");
+ de.de_gen_number_bit_string = 0;
+ retval = reiserfs_find_entry(dp, cnp->cn_nameptr, cnp->cn_namelen,
+ &path_to_entry, &de);
+ pathrelse(&path_to_entry);
+
+ if (retval == NAME_FOUND) {
+ reiserfs_log(LOG_DEBUG, "found\n");
+ } else {
+ reiserfs_log(LOG_DEBUG, "not found\n");
+ }
+
+ if (retval == NAME_FOUND) {
+#if 0
+ /* Hide the .reiserfs_priv directory */
+ if (reiserfs_xattrs(dp->i_reiserfs) &&
+ !old_format_only(dp->i_reiserfs) &&
+ REISERFS_SB(dp->i_reiserfs)->priv_root &&
+ REISERFS_SB(dp->i_reiserfs)->priv_root->d_inode &&
+ de.de_objectid == le32toh(INODE_PKEY(REISERFS_SB(
+ dp->i_reiserfs)->priv_root->d_inode)->k_objectid)) {
+ return (EACCES);
+ }
+#endif
+
+ reiserfs_log(LOG_DEBUG, "reading vnode\n");
+ pdp = vdp;
+ if (flags & ISDOTDOT) {
+ VOP_UNLOCK(pdp, 0, td);
+ error = reiserfs_iget(vdp->v_mount,
+ (struct cpu_key *)&(de.de_dir_id), &vp, td);
+ vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, td);
+ if (error != 0)
+ return (error);
+ *vpp = vp;
+ } else if (de.de_objectid == dp->i_number &&
+ de.de_dir_id == dp->i_ino) {
+ VREF(vdp); /* We want ourself, ie "." */
+ *vpp = vdp;
+ } else {
+ if ((error = reiserfs_iget(vdp->v_mount,
+ (struct cpu_key *)&(de.de_dir_id), &vp, td)) != 0)
+ return (error);
+ *vpp = vp;
+ }
+
+ /*
+ * Propogate the priv_object flag so we know we're in the
+ * priv tree
+ */
+ /*if (is_reiserfs_priv_object(dir))
+ REISERFS_I(inode)->i_flags |= i_priv_object;*/
+ } else {
+ if (retval == IO_ERROR) {
+ reiserfs_log(LOG_DEBUG, "IO error\n");
+ return (EIO);
+ }
+
+ return (ENOENT);
+ }
+
+ /* Insert name into cache if appropriate. */
+ if (cnp->cn_flags & MAKEENTRY)
+ cache_enter(vdp, *vpp, cnp);
+
+ reiserfs_log(LOG_DEBUG, "done\n");
+ return (0);
+}
+
+extern struct key MIN_KEY;
+
+int
+reiserfs_readdir(struct vop_readdir_args /* {
+ struct vnode *a_vp;
+ struct uio *a_uio;
+ struct ucred *a_cred;
+ int *a_eofflag;
+ int *a_ncookies;
+ u_long **a_cookies;
+ } */*ap)
+{
+ int error = 0;
+ struct dirent dstdp;
+ struct uio *uio = ap->a_uio;
+
+ off_t next_pos;
+ struct buf *bp;
+ struct item_head *ih;
+ struct cpu_key pos_key;
+ const struct key *rkey;
+ struct reiserfs_node *ip;
+ struct reiserfs_dir_entry de;
+ INITIALIZE_PATH(path_to_entry);
+ int entry_num, item_num, search_res;
+
+ /* The NFS part */
+ int ncookies = 0;
+ u_long *cookies = NULL;
+
+ /*
+ * Form key for search the next directory entry using f_pos field of
+ * file structure
+ */
+ ip = VTOI(ap->a_vp);
+ make_cpu_key(&pos_key,
+ ip, uio->uio_offset ? uio->uio_offset : DOT_OFFSET,
+ TYPE_DIRENTRY, 3);
+ next_pos = cpu_key_k_offset(&pos_key);
+
+ reiserfs_log(LOG_DEBUG, "listing entries for "
+ "(objectid=%d, dirid=%d)\n",
+ pos_key.on_disk_key.k_objectid, pos_key.on_disk_key.k_dir_id);
+ reiserfs_log(LOG_DEBUG, "uio_offset = %jd, uio_resid = %d\n",
+ (intmax_t)uio->uio_offset, uio->uio_resid);
+
+ if (ap->a_ncookies && ap->a_cookies) {
+ cookies = (u_long *)malloc(
+ uio->uio_resid / 16 * sizeof(u_long),
+ M_REISERFSCOOKIES, M_WAITOK);
+ }
+
+ while (1) {
+ //research:
+ /*
+ * Search the directory item, containing entry with
+ * specified key
+ */
+ reiserfs_log(LOG_DEBUG, "search directory to read\n");
+ search_res = search_by_entry_key(ip->i_reiserfs, &pos_key,
+ &path_to_entry, &de);
+ if (search_res == IO_ERROR) {
+ error = EIO;
+ goto out;
+ }
+
+ entry_num = de.de_entry_num;
+ item_num = de.de_item_num;
+ bp = de.de_bp;
+ ih = de.de_ih;
+
+ if (search_res == POSITION_FOUND ||
+ entry_num < I_ENTRY_COUNT(ih)) {
+ /*
+ * Go through all entries in the directory item
+ * beginning from the entry, that has been found.
+ */
+ struct reiserfs_de_head *deh = B_I_DEH(bp, ih) +
+ entry_num;
+
+ if (ap->a_ncookies == NULL) {
+ cookies = NULL;
+ } else {
+ //ncookies =
+ }
+
+ reiserfs_log(LOG_DEBUG,
+ "walking through directory entries\n");
+ for (; entry_num < I_ENTRY_COUNT(ih);
+ entry_num++, deh++) {
+ int d_namlen;
+ char *d_name;
+ off_t d_off;
+ ino_t d_ino;
+
+ if (!de_visible(deh)) {
+ /* It is hidden entry */
+ continue;
+ }
+
+ d_namlen = entry_length(bp, ih, entry_num);
+ d_name = B_I_DEH_ENTRY_FILE_NAME(bp, ih, deh);
+ if (!d_name[d_namlen - 1])
+ d_namlen = strlen(d_name);
+ reiserfs_log(LOG_DEBUG, " - `%s' (len=%d)\n",
+ d_name, d_namlen);
+
+ if (d_namlen > REISERFS_MAX_NAME(
+ ip->i_reiserfs->s_blocksize)) {
+ /* Too big to send back to VFS */
+ continue;
+ }
+
+#if 0
+ /* Ignore the .reiserfs_priv entry */
+ if (reiserfs_xattrs(ip->i_reiserfs) &&
+ !old_format_only(ip->i_reiserfs) &&
+ filp->f_dentry == ip->i_reiserfs->s_root &&
+ REISERFS_SB(ip->i_reiserfs)->priv_root &&
+ REISERFS_SB(ip->i_reiserfs)->priv_root->d_inode &&
+ deh_objectid(deh) ==
+ le32toh(INODE_PKEY(REISERFS_SB(
+ ip->i_reiserfs)->priv_root->d_inode)->k_objectid)) {
+ continue;
+ }
+#endif
+
+ d_off = deh_offset(deh);
+ d_ino = deh_objectid(deh);
+ uio->uio_offset = d_off;
+
+ /* Copy to user land */
+ dstdp.d_fileno = d_ino;
+ dstdp.d_type = DT_UNKNOWN;
+ dstdp.d_namlen = d_namlen;
+ dstdp.d_reclen = GENERIC_DIRSIZ(&dstdp);
+ bcopy(d_name, dstdp.d_name, dstdp.d_namlen);
+ bzero(dstdp.d_name + dstdp.d_namlen,
+ dstdp.d_reclen -
+ offsetof(struct dirent, d_name) -
+ dstdp.d_namlen);
+
+ if (d_namlen > 0) {
+ if (dstdp.d_reclen <= uio->uio_resid) {
+ reiserfs_log(LOG_DEBUG, " copying to user land\n");
+ error = uiomove(&dstdp,
+ dstdp.d_reclen, uio);
+ if (error)
+ goto end;
+ if (cookies != NULL) {
+ cookies[ncookies] =
+ d_off;
+ ncookies++;
+ }
+ } else
+ break;
+ } else {
+ error = EIO;
+ break;
+ }
+
+ next_pos = deh_offset(deh) + 1;
+ }
+ reiserfs_log(LOG_DEBUG, "...done\n");
+ }
+
+ reiserfs_log(LOG_DEBUG, "checking item num (%d == %d ?)\n",
+ item_num, B_NR_ITEMS(bp) - 1);
+ if (item_num != B_NR_ITEMS(bp) - 1) {
+ /* End of directory has been reached */
+ reiserfs_log(LOG_DEBUG, "end reached\n");
+ if (ap->a_eofflag)
+ *ap->a_eofflag = 1;
+ goto end;
+ }
+
+ /*
+ * Item we went through is last item of node. Using right
+ * delimiting key check is it directory end
+ */
+ reiserfs_log(LOG_DEBUG, "get right key\n");
+ rkey = get_rkey(&path_to_entry, ip->i_reiserfs);
+ reiserfs_log(LOG_DEBUG, "right key = (objectid=%d, dirid=%d)\n",
+ rkey->k_objectid, rkey->k_dir_id);
+
+ reiserfs_log(LOG_DEBUG, "compare it to MIN_KEY\n");
+ reiserfs_log(LOG_DEBUG, "MIN KEY = (objectid=%d, dirid=%d)\n",
+ MIN_KEY.k_objectid, MIN_KEY.k_dir_id);
+ if (comp_le_keys(rkey, &MIN_KEY) == 0) {
+ /* Set pos_key to key, that is the smallest and greater
+ * that key of the last entry in the item */
+ reiserfs_log(LOG_DEBUG, "continuing on the right\n");
+ set_cpu_key_k_offset(&pos_key, next_pos);
+ continue;
+ }
+
+ reiserfs_log(LOG_DEBUG, "compare it to pos_key\n");
+ reiserfs_log(LOG_DEBUG, "pos key = (objectid=%d, dirid=%d)\n",
+ pos_key.on_disk_key.k_objectid,
+ pos_key.on_disk_key.k_dir_id);
+ if (COMP_SHORT_KEYS(rkey, &pos_key)) {
+ /* End of directory has been reached */
+ reiserfs_log(LOG_DEBUG, "end reached (right)\n");
+ if (ap->a_eofflag)
+ *ap->a_eofflag = 1;
+ goto end;
+ }
+
+ /* Directory continues in the right neighboring block */
+ reiserfs_log(LOG_DEBUG, "continuing with a new offset\n");
+ set_cpu_key_k_offset(&pos_key,
+ le_key_k_offset(KEY_FORMAT_3_5, rkey));
+ reiserfs_log(LOG_DEBUG,
+ "new pos key = (objectid=%d, dirid=%d)\n",
+ pos_key.on_disk_key.k_objectid,
+ pos_key.on_disk_key.k_dir_id);
+ }
+
+end:
+ uio->uio_offset = next_pos;
+ pathrelse(&path_to_entry);
+ reiserfs_check_path(&path_to_entry);
+out:
+ if (error && cookies != NULL) {
+ free(cookies, M_REISERFSCOOKIES);
+ } else if (ap->a_ncookies != NULL && ap->a_cookies != NULL) {
+ *ap->a_ncookies = ncookies;
+ *ap->a_cookies = cookies;
+ }
+ return (error);
+}
+
+/* -------------------------------------------------------------------
+ * Functions from linux/fs/reiserfs/namei.c
+ * -------------------------------------------------------------------*/
+
+
+/*
+ * Directory item contains array of entry headers. This performs binary
+ * search through that array.
+ */
+static int
+bin_search_in_dir_item(struct reiserfs_dir_entry *de, off_t off)
+{
+ struct item_head *ih = de->de_ih;
+ struct reiserfs_de_head *deh = de->de_deh;
+ int rbound, lbound, j;
+
+ lbound = 0;
+ rbound = I_ENTRY_COUNT(ih) - 1;
+
+ for (j = (rbound + lbound) / 2; lbound <= rbound;
+ j = (rbound + lbound) / 2) {
+ if (off < deh_offset(deh + j)) {
+ rbound = j - 1;
+ continue;
+ }
+ if (off > deh_offset(deh + j)) {
+ lbound = j + 1;
+ continue;
+ }
+
+ /* This is not name found, but matched third key component */
+ de->de_entry_num = j;
+ return (NAME_FOUND);
+ }
+
+ de->de_entry_num = lbound;
+ return (NAME_NOT_FOUND);
+}
+
+/*
+ * Comment? Maybe something like set de to point to what the path
+ * points to?
+ */
+static inline void
+set_de_item_location(struct reiserfs_dir_entry *de, struct path *path)
+{
+
+ de->de_bp = get_last_bp(path);
+ de->de_ih = get_ih(path);
+ de->de_deh = B_I_DEH(de->de_bp, de->de_ih);
+ de->de_item_num = PATH_LAST_POSITION(path);
+}
+
+/*
+ * de_bh, de_ih, de_deh (points to first element of array), de_item_num
+ * is set
+ */
+inline void
+set_de_name_and_namelen(struct reiserfs_dir_entry *de)
+{
+ struct reiserfs_de_head *deh = de->de_deh + de->de_entry_num;
+
+ if (de->de_entry_num >= ih_entry_count(de->de_ih)) {
+ reiserfs_log(LOG_DEBUG, "BUG\n");
+ return;
+ }
+
+ de->de_entrylen = entry_length(de->de_bp, de->de_ih, de->de_entry_num);
+ de->de_namelen = de->de_entrylen - (de_with_sd(deh) ? SD_SIZE : 0);
+ de->de_name = B_I_PITEM(de->de_bp, de->de_ih) + deh_location(deh);
+ if (de->de_name[de->de_namelen - 1] == 0)
+ de->de_namelen = strlen(de->de_name);
+}
+
+/* What entry points to */
+static inline void
+set_de_object_key(struct reiserfs_dir_entry *de)
+{
+
+ if (de->de_entry_num >= ih_entry_count(de->de_ih)) {
+ reiserfs_log(LOG_DEBUG, "BUG\n");
+ return;
+ }
+ de->de_dir_id = deh_dir_id(&(de->de_deh[de->de_entry_num]));
+ de->de_objectid = deh_objectid(&(de->de_deh[de->de_entry_num]));
+}
+
+static inline void
+store_de_entry_key(struct reiserfs_dir_entry *de)
+{
+ struct reiserfs_de_head *deh = de->de_deh + de->de_entry_num;
+
+ if (de->de_entry_num >= ih_entry_count(de->de_ih)) {
+ reiserfs_log(LOG_DEBUG, "BUG\n");
+ return;
+ }
+
+ /* Store key of the found entry */
+ de->de_entry_key.version = KEY_FORMAT_3_5;
+ de->de_entry_key.on_disk_key.k_dir_id =
+ le32toh(de->de_ih->ih_key.k_dir_id);
+ de->de_entry_key.on_disk_key.k_objectid =
+ le32toh(de->de_ih->ih_key.k_objectid);
+ set_cpu_key_k_offset(&(de->de_entry_key), deh_offset(deh));
+ set_cpu_key_k_type(&(de->de_entry_key), TYPE_DIRENTRY);
+}
+
+/*
+ * We assign a key to each directory item, and place multiple entries in
+ * a single directory item. A directory item has a key equal to the key
+ * of the first directory entry in it.
+ *
+ * This function first calls search_by_key, then, if item whose first
+ * entry matches is not found it looks for the entry inside directory
+ * item found by search_by_key. Fills the path to the entry, and to the
+ * entry position in the item
+ */
+int
+search_by_entry_key(struct reiserfs_sb_info *sbi,
+ const struct cpu_key *key, struct path *path,
+ struct reiserfs_dir_entry *de)
+{
+ int retval;
+
+ reiserfs_log(LOG_DEBUG, "searching in (objectid=%d,dirid=%d)\n",
+ key->on_disk_key.k_objectid, key->on_disk_key.k_dir_id);
+ retval = search_item(sbi, key, path);
+ switch (retval) {
+ case ITEM_NOT_FOUND:
+ if (!PATH_LAST_POSITION(path)) {
+ reiserfs_log(LOG_DEBUG,
+ "search_by_key returned item position == 0");
+ pathrelse(path);
+ return (IO_ERROR);
+ }
+ PATH_LAST_POSITION(path)--;
+ reiserfs_log(LOG_DEBUG, "search_by_key did not found it\n");
+ break;
+ case ITEM_FOUND:
+ reiserfs_log(LOG_DEBUG, "search_by_key found it\n");
+ break;
+ case IO_ERROR:
+ return (retval);
+ default:
+ pathrelse(path);
+ reiserfs_log(LOG_DEBUG, "no path to here");
+ return (IO_ERROR);
+ }
+
+ reiserfs_log(LOG_DEBUG, "set item location\n");
+ set_de_item_location(de, path);
+
+ /*
+ * Binary search in directory item by third component of the
+ * key. Sets de->de_entry_num of de
+ */
+ reiserfs_log(LOG_DEBUG, "bin_search_in_dir_item\n");
+ retval = bin_search_in_dir_item(de, cpu_key_k_offset(key));
+ path->pos_in_item = de->de_entry_num;
+ if (retval != NAME_NOT_FOUND) {
+ /*
+ * Ugly, but rename needs de_bp, de_deh, de_name, de_namelen,
+ * de_objectid set
+ */
+ set_de_name_and_namelen(de);
+ set_de_object_key(de);
+ reiserfs_log(LOG_DEBUG, "set (objectid=%d,dirid=%d)\n",
+ de->de_objectid, de->de_dir_id);
+ }
+
+ return (retval);
+}
+
+static uint32_t
+get_third_component(struct reiserfs_sb_info *sbi, const char *name, int len)
+{
+ uint32_t res;
+
+ if (!len || (len == 1 && name[0] == '.'))
+ return (DOT_OFFSET);
+
+ if (len == 2 && name[0] == '.' && name[1] == '.')
+ return (DOT_DOT_OFFSET);
+
+ res = REISERFS_SB(sbi)->s_hash_function(name, len);
+
+ /* Take bits from 7-th to 30-th including both bounds */
+ res = GET_HASH_VALUE(res);
+ if (res == 0)
+ /*
+ * Needed to have no names before "." and ".." those have hash
+ * value == 0 and generation counters 1 and 2 accordingly
+ */
+ res = 128;
+
+ return (res + MAX_GENERATION_NUMBER);
+}
+
+static int
+reiserfs_match(struct reiserfs_dir_entry *de, const char *name, int namelen)
+{
+ int retval = NAME_NOT_FOUND;
+
+ if ((namelen == de->de_namelen) &&
+ !memcmp(de->de_name, name, de->de_namelen))
+ retval = (de_visible(de->de_deh + de->de_entry_num) ?
+ NAME_FOUND : NAME_FOUND_INVISIBLE);
+
+ return (retval);
+}
+
+/*
+ * de's de_bh, de_ih, de_deh, de_item_num, de_entry_num are set already
+ * Used when hash collisions exist
+ */
+static int
+linear_search_in_dir_item(struct cpu_key *key, struct reiserfs_dir_entry *de,
+ const char *name, int namelen)
+{
+ int i;
+ int retval;
+ struct reiserfs_de_head * deh = de->de_deh;
+
+ i = de->de_entry_num;
+
+ if (i == I_ENTRY_COUNT(de->de_ih) ||
+ GET_HASH_VALUE(deh_offset(deh + i)) !=
+ GET_HASH_VALUE(cpu_key_k_offset(key))) {
+ i--;
+ }
+
+ /*RFALSE( de->de_deh != B_I_DEH (de->de_bh, de->de_ih),
+ "vs-7010: array of entry headers not found");*/
+
+ deh += i;
+
+ for (; i >= 0; i--, deh--) {
+ if (GET_HASH_VALUE(deh_offset(deh)) !=
+ GET_HASH_VALUE(cpu_key_k_offset(key))) {
+ /*
+ * Hash value does not match, no need to check
+ * whole name
+ */
+ reiserfs_log(LOG_DEBUG, "name `%s' not found\n", name);
+ return (NAME_NOT_FOUND);
+ }
+
+ /* Mark that this generation number is used */
+ if (de->de_gen_number_bit_string)
+ set_bit(GET_GENERATION_NUMBER(deh_offset(deh)),
+ (unsigned long *)de->de_gen_number_bit_string);
+
+ /* Calculate pointer to name and namelen */
+ de->de_entry_num = i;
+ set_de_name_and_namelen(de);
+
+ if ((retval = reiserfs_match(de, name, namelen)) !=
+ NAME_NOT_FOUND) {
+ /*
+ * de's de_name, de_namelen, de_recordlen are set.
+ * Fill the rest:
+ */
+ /* key of pointed object */
+ set_de_object_key(de);
+ store_de_entry_key(de);
+
+ /* retval can be NAME_FOUND or NAME_FOUND_INVISIBLE */
+ reiserfs_log(LOG_DEBUG,
+ "reiserfs_match answered `%d'\n",
+ retval);
+ return (retval);
+ }
+ }
+
+ if (GET_GENERATION_NUMBER(le_ih_k_offset(de->de_ih)) == 0)
+ /*
+ * We have reached left most entry in the node. In common
+ * we have to go to the left neighbor, but if generation
+ * counter is 0 already, we know for sure, that there is
+ * no name with the same hash value
+ */
+ /* FIXME: this work correctly only because hash value can
+ * not be 0. Btw, in case of Yura's hash it is probably
+ * possible, so, this is a bug
+ */
+ return (NAME_NOT_FOUND);
+
+ /*RFALSE(de->de_item_num,
+ "vs-7015: two diritems of the same directory in one node?");*/
+
+ return (GOTO_PREVIOUS_ITEM);
+}
+
+/*
+ * May return NAME_FOUND, NAME_FOUND_INVISIBLE, NAME_NOT_FOUND
+ * FIXME: should add something like IOERROR
+ */
+static int
+reiserfs_find_entry(struct reiserfs_node *dp, const char *name, int namelen,
+ struct path * path_to_entry, struct reiserfs_dir_entry *de)
+{
+ struct cpu_key key_to_search;
+ int retval;
+
+ if (namelen > REISERFS_MAX_NAME(dp->i_reiserfs->s_blocksize))
+ return NAME_NOT_FOUND;
+
+ /* We will search for this key in the tree */
+ make_cpu_key(&key_to_search, dp,
+ get_third_component(dp->i_reiserfs, name, namelen),
+ TYPE_DIRENTRY, 3);
+
+ while (1) {
+ reiserfs_log(LOG_DEBUG, "search by entry key\n");
+ retval = search_by_entry_key(dp->i_reiserfs, &key_to_search,
+ path_to_entry, de);
+ if (retval == IO_ERROR) {
+ reiserfs_log(LOG_DEBUG, "IO error in %s\n",
+ __FUNCTION__);
+ return IO_ERROR;
+ }
+
+ /* Compare names for all entries having given hash value */
+ reiserfs_log(LOG_DEBUG, "linear search for `%s'\n", name);
+ retval = linear_search_in_dir_item(&key_to_search, de,
+ name, namelen);
+ if (retval != GOTO_PREVIOUS_ITEM) {
+ /*
+ * There is no need to scan directory anymore.
+ * Given entry found or does not exist
+ */
+ reiserfs_log(LOG_DEBUG, "linear search returned "
+ "(objectid=%d,dirid=%d)\n",
+ de->de_objectid, de->de_dir_id);
+ path_to_entry->pos_in_item = de->de_entry_num;
+ return retval;
+ }
+
+ /*
+ * There is left neighboring item of this directory and
+ * given entry can be there
+ */
+ set_cpu_key_k_offset(&key_to_search,
+ le_ih_k_offset(de->de_ih) - 1);
+ pathrelse(path_to_entry);
+ } /* while (1) */
+}
diff --git a/sys/gnu/fs/reiserfs/reiserfs_prints.c b/sys/gnu/fs/reiserfs/reiserfs_prints.c
new file mode 100644
index 000000000000..e48433ba0014
--- /dev/null
+++ b/sys/gnu/fs/reiserfs/reiserfs_prints.c
@@ -0,0 +1,307 @@
+/*-
+ * Copyright 2000 Hans Reiser
+ * See README for licensing and copyright details
+ *
+ * Ported to FreeBSD by Jean-Sébastien Pédron <jspedron@club-internet.fr>
+ *
+ * $FreeBSD$
+ */
+
+#include <gnu/fs/reiserfs/reiserfs_fs.h>
+
+#if 0
+static char error_buf[1024];
+static char fmt_buf[1024];
+static char off_buf[80];
+
+static char *
+reiserfs_cpu_offset(struct cpu_key *key)
+{
+
+ if (cpu_key_k_type(key) == TYPE_DIRENTRY)
+ sprintf(off_buf, "%Lu(%Lu)",
+ (unsigned long long)GET_HASH_VALUE(cpu_key_k_offset(key)),
+ (unsigned long long)GET_GENERATION_NUMBER(
+ cpu_key_k_offset(key)));
+ else
+ sprintf(off_buf, "0x%Lx",
+ (unsigned long long)cpu_key_k_offset(key));
+
+ return (off_buf);
+}
+
+static char *
+le_offset(struct key *key)
+{
+ int version;
+
+ version = le_key_version(key);
+ if (le_key_k_type(version, key) == TYPE_DIRENTRY)
+ sprintf(off_buf, "%Lu(%Lu)",
+ (unsigned long long)GET_HASH_VALUE(
+ le_key_k_offset(version, key)),
+ (unsigned long long)GET_GENERATION_NUMBER(
+ le_key_k_offset(version, key)));
+ else
+ sprintf(off_buf, "0x%Lx",
+ (unsigned long long)le_key_k_offset(version, key));
+
+ return (off_buf);
+}
+
+static char *
+cpu_type(struct cpu_key *key)
+{
+
+ if (cpu_key_k_type(key) == TYPE_STAT_DATA)
+ return ("SD");
+ if (cpu_key_k_type(key) == TYPE_DIRENTRY)
+ return ("DIR");
+ if (cpu_key_k_type(key) == TYPE_DIRECT)
+ return ("DIRECT");
+ if (cpu_key_k_type(key) == TYPE_INDIRECT)
+ return ("IND");
+
+ return ("UNKNOWN");
+}
+
+static char *
+le_type(struct key *key)
+{
+ int version;
+
+ version = le_key_version(key);
+
+ if (le_key_k_type(version, key) == TYPE_STAT_DATA)
+ return ("SD");
+ if (le_key_k_type(version, key) == TYPE_DIRENTRY)
+ return ("DIR");
+ if (le_key_k_type(version, key) == TYPE_DIRECT)
+ return ("DIRECT");
+ if (le_key_k_type(version, key) == TYPE_INDIRECT)
+ return ("IND");
+
+ return ("UNKNOWN");
+}
+
+/* %k */
+static void
+sprintf_le_key(char *buf, struct key *key)
+{
+
+ if (key)
+ sprintf(buf, "[%d %d %s %s]", le32toh(key->k_dir_id),
+ le32toh(key->k_objectid), le_offset(key), le_type(key));
+ else
+ sprintf(buf, "[NULL]");
+}
+
+/* %K */
+static void
+sprintf_cpu_key(char *buf, struct cpu_key *key)
+{
+
+ if (key)
+ sprintf(buf, "[%d %d %s %s]", key->on_disk_key.k_dir_id,
+ key->on_disk_key.k_objectid, reiserfs_cpu_offset (key),
+ cpu_type (key));
+ else
+ sprintf(buf, "[NULL]");
+}
+
+static void sprintf_de_head(char *buf, struct reiserfs_de_head *deh)
+{
+
+ if (deh)
+ sprintf(buf,
+ "[offset=%d dir_id=%d objectid=%d location=%d state=%04x]",
+ deh_offset(deh), deh_dir_id(deh),
+ deh_objectid(deh), deh_location(deh), deh_state(deh));
+ else
+ sprintf(buf, "[NULL]");
+}
+
+static void
+sprintf_item_head(char *buf, struct item_head *ih)
+{
+
+ if (ih) {
+ strcpy(buf, (ih_version(ih) == KEY_FORMAT_3_6) ?
+ "*3.6* " : "*3.5*");
+ sprintf_le_key(buf + strlen(buf), &(ih->ih_key));
+ sprintf(buf + strlen(buf), ", item_len %d, item_location %d, "
+ "free_space(entry_count) %d",
+ ih_item_len(ih), ih_location(ih), ih_free_space(ih));
+ } else
+ sprintf(buf, "[NULL]");
+}
+
+static void
+sprintf_direntry(char *buf, struct reiserfs_dir_entry *de)
+{
+ char name[20];
+
+ memcpy(name, de->de_name, de->de_namelen > 19 ? 19 : de->de_namelen);
+ name [de->de_namelen > 19 ? 19 : de->de_namelen] = 0;
+ sprintf(buf, "\"%s\" ==> [%d %d]",
+ name, de->de_dir_id, de->de_objectid);
+}
+
+static void
+sprintf_block_head(char *buf, struct buf *bp)
+{
+
+ sprintf(buf, "level=%d, nr_items=%d, free_space=%d rdkey ",
+ B_LEVEL(bp), B_NR_ITEMS(bp), B_FREE_SPACE(bp));
+}
+
+static void
+sprintf_disk_child(char *buf, struct disk_child *dc)
+{
+
+ sprintf (buf, "[dc_number=%d, dc_size=%u]",
+ dc_block_number(dc), dc_size(dc));
+}
+
+static char *
+is_there_reiserfs_struct (char *fmt, int *what, int *skip)
+{
+ char *k;
+
+ k = fmt;
+ *skip = 0;
+
+ while ((k = strchr(k, '%')) != NULL) {
+ if (k[1] == 'k' || k[1] == 'K' || k[1] == 'h' || k[1] == 't' ||
+ k[1] == 'z' || k[1] == 'b' || k[1] == 'y' || k[1] == 'a' ) {
+ *what = k[1];
+ break;
+ }
+ (*skip)++;
+ k++;
+ }
+
+ return (k);
+}
+
+static void
+prepare_error_buf(const char *fmt, va_list args)
+{
+ char *fmt1, *k, *p;
+ int i, j, what, skip;
+
+ fmt1 = fmt_buf;
+ p = error_buf;
+ strcpy (fmt1, fmt);
+
+ while ((k = is_there_reiserfs_struct(fmt1, &what, &skip)) != NULL) {
+ *k = 0;
+
+ p += vsprintf (p, fmt1, args);
+
+ for (i = 0; i < skip; i ++)
+ j = va_arg(args, int);
+
+ switch (what) {
+ case 'k':
+ sprintf_le_key(p, va_arg(args, struct key *));
+ break;
+ case 'K':
+ sprintf_cpu_key(p, va_arg(args, struct cpu_key *));
+ break;
+ case 'h':
+ sprintf_item_head(p, va_arg(args, struct item_head *));
+ break;
+ case 't':
+ sprintf_direntry(p,
+ va_arg(args, struct reiserfs_dir_entry *));
+ break;
+ case 'y':
+ sprintf_disk_child(p,
+ va_arg(args, struct disk_child *));
+ break;
+ case 'z':
+ sprintf_block_head(p,
+ va_arg(args, struct buffer_head *));
+ break;
+ case 'a':
+ sprintf_de_head(p,
+ va_arg(args, struct reiserfs_de_head *));
+ break;
+ }
+
+ p += strlen(p);
+ fmt1 = k + 2;
+ }
+
+ vsprintf(p, fmt1, args);
+}
+
+/*
+ * In addition to usual conversion specifiers this accepts reiserfs
+ * specific conversion specifiers:
+ * %k to print little endian key,
+ * %K to print cpu key,
+ * %h to print item_head,
+ * %t to print directory entry,
+ * %z to print block head (arg must be struct buf *)
+ */
+
+#define do_reiserfs_warning(fmt) \
+{ \
+ va_list args; \
+ va_start(args, fmt); \
+ prepare_error_buf(fmt, args); \
+ va_end(args); \
+}
+
+void
+__reiserfs_log(int level, const char * fmt, ...)
+{
+
+ do_reiserfs_warning(fmt);
+ log(level, "ReiserFS/%s: %s\n", __FUNCTION__, error_buf);
+}
+
+#endif
+
+char *
+reiserfs_hashname(int code)
+{
+
+ if (code == YURA_HASH)
+ return ("rupasov");
+ if (code == TEA_HASH)
+ return ("tea");
+ if (code == R5_HASH)
+ return ("r5");
+
+ return ("unknown");
+}
+
+void
+reiserfs_dump_buffer(caddr_t buf, off_t len)
+{
+ int i, j;
+
+ log(LOG_DEBUG, "reiserfs: dumping a buffer of %jd bytes\n",
+ (intmax_t)len);
+ for (i = 0; i < len; i += 16) {
+ log(LOG_DEBUG, "%08x: ", i);
+ for (j = 0; j < 16; j += 2) {
+ if (i + j >= len)
+ log(LOG_DEBUG, " ");
+ else
+ log(LOG_DEBUG, "%02x%02x ",
+ buf[i + j] & 0xff,
+ buf[i + j + 1] & 0xff);
+ }
+ for (j = 0; j < 16; ++j) {
+ if (i + j >= len)
+ break;
+ log(LOG_DEBUG, "%c",
+ isprint(buf[i + j]) ? buf[i + j] : '.');
+ }
+ log(LOG_DEBUG, "\n");
+ }
+}
diff --git a/sys/gnu/fs/reiserfs/reiserfs_stree.c b/sys/gnu/fs/reiserfs/reiserfs_stree.c
new file mode 100644
index 000000000000..5d5e4c412bc1
--- /dev/null
+++ b/sys/gnu/fs/reiserfs/reiserfs_stree.c
@@ -0,0 +1,760 @@
+/*-
+ * Copyright 2000 Hans Reiser
+ * See README for licensing and copyright details
+ *
+ * Ported to FreeBSD by Jean-Sébastien Pédron <jspedron@club-internet.fr>
+ *
+ * $FreeBSD$
+ */
+
+#include <gnu/fs/reiserfs/reiserfs_fs.h>
+
+/* Minimal possible key. It is never in the tree. */
+const struct key MIN_KEY = {
+ 0,
+ 0,
+ { {0, 0}, }
+};
+
+/* Maximal possible key. It is never in the tree. */
+const struct key MAX_KEY = {
+ 0xffffffff,
+ 0xffffffff,
+ { {0xffffffff, 0xffffffff }, }
+};
+
+/* Does the buffer contain a disk block which is in the tree. */
+inline int
+B_IS_IN_TREE(const struct buf *p_s_bp)
+{
+
+ return (B_LEVEL(p_s_bp) != FREE_LEVEL);
+}
+
+/* To gets item head in le form */
+inline void
+copy_item_head(struct item_head *p_v_to, const struct item_head *p_v_from)
+{
+
+ memcpy(p_v_to, p_v_from, IH_SIZE);
+}
+
+/*
+ * k1 is pointer to on-disk structure which is stored in little-endian
+ * form. k2 is pointer to cpu variable. For key of items of the same
+ * object this returns 0.
+ * Returns: -1 if key1 < key2, 0 if key1 == key2 or 1 if key1 > key2
+ */
+/*inline*/ int
+comp_short_keys(const struct key *le_key, const struct cpu_key *cpu_key)
+{
+ const uint32_t *p_s_le_u32, *p_s_cpu_u32;
+ int n_key_length = REISERFS_SHORT_KEY_LEN;
+
+ p_s_le_u32 = (const uint32_t *)le_key;
+ p_s_cpu_u32 = (const uint32_t *)&cpu_key->on_disk_key;
+ for(; n_key_length--; ++p_s_le_u32, ++p_s_cpu_u32) {
+ if (le32toh(*p_s_le_u32) < *p_s_cpu_u32)
+ return (-1);
+ if (le32toh(*p_s_le_u32) > *p_s_cpu_u32)
+ return (1);
+ }
+
+ return (0);
+}
+
+/*
+ * k1 is pointer to on-disk structure which is stored in little-endian
+ * form. k2 is pointer to cpu variable. Compare keys using all 4 key
+ * fields.
+ * Returns: -1 if key1 < key2, 0 if key1 = key2 or 1 if key1 > key2
+ */
+/*inline*/ int
+comp_keys(const struct key *le_key, const struct cpu_key *cpu_key)
+{
+ int retval;
+
+ retval = comp_short_keys(le_key, cpu_key);
+ if (retval)
+ return retval;
+
+ if (le_key_k_offset(le_key_version(le_key), le_key) <
+ cpu_key_k_offset(cpu_key))
+ return (-1);
+ if (le_key_k_offset(le_key_version(le_key), le_key) >
+ cpu_key_k_offset(cpu_key))
+ return (1);
+
+ if (cpu_key->key_length == 3)
+ return (0);
+
+ /* This part is needed only when tail conversion is in progress */
+ if (le_key_k_type(le_key_version(le_key), le_key) <
+ cpu_key_k_type(cpu_key))
+ return (-1);
+
+ if (le_key_k_type(le_key_version(le_key), le_key) >
+ cpu_key_k_type(cpu_key))
+ return (1);
+
+ return (0);
+}
+
+/* Release all buffers in the path. */
+void
+pathrelse(struct path *p_s_search_path)
+{
+ struct buf *bp;
+ int n_path_offset = p_s_search_path->path_length;
+
+ while (n_path_offset > ILLEGAL_PATH_ELEMENT_OFFSET) {
+ bp = PATH_OFFSET_PBUFFER(p_s_search_path, n_path_offset--);
+ free(bp->b_data, M_REISERFSPATH);
+ free(bp, M_REISERFSPATH);
+ }
+
+ p_s_search_path->path_length = ILLEGAL_PATH_ELEMENT_OFFSET;
+}
+
+/*
+ * This does not say which one is bigger, it only returns 1 if keys
+ * are not equal, 0 otherwise
+ */
+inline int
+comp_le_keys(const struct key *k1, const struct key *k2)
+{
+
+ return (memcmp(k1, k2, sizeof(struct key)));
+}
+
+/*
+ * Binary search toolkit function. Search for an item in the array by
+ * the item key.
+ * Returns: 1 if found, 0 if not found;
+ * *p_n_pos = number of the searched element if found, else the
+ * number of the first element that is larger than p_v_key.
+ */
+/*
+ * For those not familiar with binary search: n_lbound is the leftmost
+ * item that it could be, n_rbound the rightmost item that it could be.
+ * We examine the item halfway between n_lbound and n_rbound, and that
+ * tells us either that we can increase n_lbound, or decrease n_rbound,
+ * or that we have found it, or if n_lbound <= n_rbound that there are
+ * no possible items, and we have not found it. With each examination we
+ * cut the number of possible items it could be by one more than half
+ * rounded down, or we find it.
+ */
+inline int
+bin_search(const void *p_v_key, /* Key to search for. */
+ const void *p_v_base, /* First item in the array. */
+ int p_n_num, /* Number of items in the array. */
+ int p_n_width, /* Item size in the array. searched. Lest the
+ reader be confused, note that this is crafted
+ as a general function, and when it is applied
+ specifically to the array of item headers in
+ a node, p_n_width is actually the item header
+ size not the item size. */
+ int *p_n_pos) /* Number of the searched for element. */
+{
+ int n_rbound, n_lbound, n_j;
+
+ for (n_j = ((n_rbound = p_n_num - 1) + (n_lbound = 0)) / 2;
+ n_lbound <= n_rbound; n_j = (n_rbound + n_lbound) / 2) {
+ switch (COMP_KEYS((const struct key *)
+ ((const char *)p_v_base + n_j * p_n_width),
+ (const struct cpu_key *)p_v_key)) {
+ case -1:
+ n_lbound = n_j + 1;
+ continue;
+ case 1:
+ n_rbound = n_j - 1;
+ continue;
+ case 0:
+ *p_n_pos = n_j;
+ return (ITEM_FOUND); /* Key found in the array. */
+ }
+ }
+
+ /*
+ * bin_search did not find given key, it returns position of key,
+ * that is minimal and greater than the given one.
+ */
+ *p_n_pos = n_lbound;
+ return (ITEM_NOT_FOUND);
+}
+
+/*
+ * Get delimiting key of the buffer by looking for it in the buffers in
+ * the path, starting from the bottom of the path, and going upwards. We
+ * must check the path's validity at each step. If the key is not in the
+ * path, there is no delimiting key in the tree (buffer is first or last
+ * buffer in tree), and in this case we return a special key, either
+ * MIN_KEY or MAX_KEY.
+ */
+inline const struct key *
+get_lkey(const struct path *p_s_chk_path,
+ const struct reiserfs_sb_info *p_s_sbi)
+{
+ struct buf *p_s_parent;
+ int n_position, n_path_offset = p_s_chk_path->path_length;
+
+ /* While not higher in path than first element. */
+ while (n_path_offset-- > FIRST_PATH_ELEMENT_OFFSET) {
+ /* Parent at the path is not in the tree now. */
+ if (!B_IS_IN_TREE(p_s_parent =
+ PATH_OFFSET_PBUFFER(p_s_chk_path, n_path_offset)))
+ return (&MAX_KEY);
+
+ /* Check whether position in the parent is correct. */
+ if ((n_position = PATH_OFFSET_POSITION(p_s_chk_path,
+ n_path_offset)) > B_NR_ITEMS(p_s_parent))
+ return (&MAX_KEY);
+
+ /*
+ * Check whether parent at the path really points to
+ * the child.
+ */
+ if (B_N_CHILD_NUM(p_s_parent, n_position) !=
+ (PATH_OFFSET_PBUFFER(p_s_chk_path,
+ n_path_offset + 1)->b_blkno
+ / btodb(p_s_sbi->s_blocksize)))
+ return (&MAX_KEY);
+
+ /*
+ * Return delimiting key if position in the parent is not
+ * equal to zero.
+ */
+ if (n_position)
+ return (B_N_PDELIM_KEY(p_s_parent, n_position - 1));
+ }
+
+ /* Return MIN_KEY if we are in the root of the buffer tree. */
+ if ((PATH_OFFSET_PBUFFER(p_s_chk_path,
+ FIRST_PATH_ELEMENT_OFFSET)->b_blkno
+ / btodb(p_s_sbi->s_blocksize)) == SB_ROOT_BLOCK(p_s_sbi))
+ return (&MIN_KEY);
+
+ return (&MAX_KEY);
+}
+
+/* Get delimiting key of the buffer at the path and its right neighbor. */
+inline const struct key *
+get_rkey(const struct path *p_s_chk_path,
+ const struct reiserfs_sb_info *p_s_sbi)
+{
+ struct buf *p_s_parent;
+ int n_position, n_path_offset = p_s_chk_path->path_length;
+
+ while (n_path_offset-- > FIRST_PATH_ELEMENT_OFFSET) {
+ /* Parent at the path is not in the tree now. */
+ if (!B_IS_IN_TREE(p_s_parent =
+ PATH_OFFSET_PBUFFER(p_s_chk_path, n_path_offset)))
+ return (&MIN_KEY);
+
+ /* Check whether position in the parent is correct. */
+ if ((n_position = PATH_OFFSET_POSITION(p_s_chk_path,
+ n_path_offset)) >
+ B_NR_ITEMS(p_s_parent))
+ return (&MIN_KEY);
+
+ /*
+ * Check whether parent at the path really points to the
+ * child.
+ */
+ if (B_N_CHILD_NUM(p_s_parent, n_position) !=
+ (PATH_OFFSET_PBUFFER(p_s_chk_path,
+ n_path_offset + 1)->b_blkno
+ / btodb(p_s_sbi->s_blocksize)))
+ return (&MIN_KEY);
+
+ /*
+ * Return delimiting key if position in the parent is not
+ * the last one.
+ */
+ if (n_position != B_NR_ITEMS(p_s_parent))
+ return (B_N_PDELIM_KEY(p_s_parent, n_position));
+ }
+
+ /* Return MAX_KEY if we are in the root of the buffer tree. */
+ if ((PATH_OFFSET_PBUFFER(p_s_chk_path,
+ FIRST_PATH_ELEMENT_OFFSET)->b_blkno
+ / btodb(p_s_sbi->s_blocksize)) == SB_ROOT_BLOCK(p_s_sbi))
+ return (&MAX_KEY);
+
+ return (&MIN_KEY);
+}
+
+int
+reiserfs_check_path(struct path *p)
+{
+
+ if (p->path_length != ILLEGAL_PATH_ELEMENT_OFFSET)
+ reiserfs_log(LOG_WARNING, "path not properly relsed\n");
+ return (0);
+}
+
+/*
+ * Check whether a key is contained in the tree rooted from a buffer at
+ * a path. This works by looking at the left and right delimiting keys
+ * for the buffer in the last path_element in the path. These delimiting
+ * keys are stored at least one level above that buffer in the tree.
+ * If the buffer is the first or last node in the tree order then one
+ * of the delimiting keys may be absent, and in this case get_lkey and
+ * get_rkey return a special key which is MIN_KEY or MAX_KEY.
+ */
+static inline int
+key_in_buffer(
+ struct path *p_s_chk_path, /* Path which should be checked. */
+ const struct cpu_key *p_s_key, /* Key which should be checked. */
+ struct reiserfs_sb_info *p_s_sbi) /* Super block pointer. */
+{
+
+ if (COMP_KEYS(get_lkey(p_s_chk_path, p_s_sbi), p_s_key) == 1)
+ /* left delimiting key is bigger, that the key we look for */
+ return (0);
+
+ if (COMP_KEYS(get_rkey(p_s_chk_path, p_s_sbi), p_s_key) != 1)
+ /* p_s_key must be less than right delimitiing key */
+ return (0);
+
+ return (1);
+}
+
+#if 0
+/* XXX Il ne semble pas y avoir de compteur de référence dans struct buf */
+inline void
+decrement_bcount(struct buf *p_s_bp)
+{
+
+ if (p_s_bp) {
+ if (atomic_read(&(p_s_bp->b_count))) {
+ put_bh(p_s_bp);
+ return;
+ }
+ }
+}
+#endif
+
+/* Decrement b_count field of the all buffers in the path. */
+void
+decrement_counters_in_path(struct path *p_s_search_path)
+{
+
+ pathrelse(p_s_search_path);
+#if 0
+ int n_path_offset = p_s_search_path->path_length;
+
+ while (n_path_offset > ILLEGAL_PATH_ELEMENT_OFFSET) {
+ struct buf *bp;
+
+ bp = PATH_OFFSET_PBUFFER(p_s_search_path, n_path_offset--);
+ decrement_bcount(bp);
+ }
+
+ p_s_search_path->path_length = ILLEGAL_PATH_ELEMENT_OFFSET;
+#endif
+}
+
+static int
+is_leaf(char *buf, int blocksize, struct buf *bp)
+{
+ struct item_head *ih;
+ struct block_head *blkh;
+ int used_space, prev_location, i, nr;
+
+ blkh = (struct block_head *)buf;
+ if (blkh_level(blkh) != DISK_LEAF_NODE_LEVEL) {
+ reiserfs_log(LOG_WARNING, "this should be caught earlier");
+ return (0);
+ }
+
+ nr = blkh_nr_item(blkh);
+ if (nr < 1 || nr >
+ ((blocksize - BLKH_SIZE) / (IH_SIZE + MIN_ITEM_LEN))) {
+ /* Item number is too big or too small */
+ reiserfs_log(LOG_WARNING, "nr_item seems wrong\n");
+ return (0);
+ }
+
+ ih = (struct item_head *)(buf + BLKH_SIZE) + nr - 1;
+ used_space = BLKH_SIZE + IH_SIZE * nr + (blocksize - ih_location(ih));
+ if (used_space != blocksize - blkh_free_space(blkh)) {
+ /*
+ * Free space does not match to calculated amount of
+ * use space
+ */
+ reiserfs_log(LOG_WARNING, "free space seems wrong\n");
+ return (0);
+ }
+
+ /* FIXME: it is_leaf will hit performance too much - we may have
+ * return 1 here */
+
+ /* Check tables of item heads */
+ ih = (struct item_head *)(buf + BLKH_SIZE);
+ prev_location = blocksize;
+ for (i = 0; i < nr; i++, ih++) {
+ if (le_ih_k_type(ih) == TYPE_ANY) {
+ reiserfs_log(LOG_WARNING,
+ "wrong item type for item\n");
+ return (0);
+ }
+ if (ih_location(ih) >= blocksize ||
+ ih_location(ih) < IH_SIZE * nr) {
+ reiserfs_log(LOG_WARNING,
+ "item location seems wrong\n");
+ return (0);
+ }
+ if (ih_item_len(ih) < 1 ||
+ ih_item_len(ih) > MAX_ITEM_LEN(blocksize)) {
+ reiserfs_log(LOG_WARNING, "item length seems wrong\n");
+ return (0);
+ }
+ if (prev_location - ih_location(ih) != ih_item_len(ih)) {
+ reiserfs_log(LOG_WARNING,
+ "item location seems wrong (second one)\n");
+ return (0);
+ }
+ prev_location = ih_location(ih);
+ }
+
+ /* One may imagine much more checks */
+ return 1;
+}
+
+/* Returns 1 if buf looks like an internal node, 0 otherwise */
+static int
+is_internal(char *buf, int blocksize, struct buf *bp)
+{
+ int nr, used_space;
+ struct block_head *blkh;
+
+ blkh = (struct block_head *)buf;
+ nr = blkh_level(blkh);
+ if (nr <= DISK_LEAF_NODE_LEVEL || nr > MAX_HEIGHT) {
+ /* This level is not possible for internal nodes */
+ reiserfs_log(LOG_WARNING, "this should be caught earlier\n");
+ return (0);
+ }
+
+ nr = blkh_nr_item(blkh);
+ if (nr > (blocksize - BLKH_SIZE - DC_SIZE) / (KEY_SIZE + DC_SIZE)) {
+ /*
+ * For internal which is not root we might check min
+ * number of keys
+ */
+ reiserfs_log(LOG_WARNING, "number of key seems wrong\n");
+ return (0);
+ }
+
+ used_space = BLKH_SIZE + KEY_SIZE * nr + DC_SIZE * (nr + 1);
+ if (used_space != blocksize - blkh_free_space(blkh)) {
+ reiserfs_log(LOG_WARNING,
+ "is_internal: free space seems wrong\n");
+ return (0);
+ }
+
+ /* One may imagine much more checks */
+ return (1);
+}
+
+/*
+ * Make sure that bh contains formatted node of reiserfs tree of
+ * 'level'-th level
+ */
+static int
+is_tree_node(struct buf *bp, int level)
+{
+ if (B_LEVEL(bp) != level) {
+ reiserfs_log(LOG_WARNING,
+ "node level (%d) doesn't match to the "
+ "expected one (%d)\n", B_LEVEL (bp), level);
+ return (0);
+ }
+
+ if (level == DISK_LEAF_NODE_LEVEL)
+ return (is_leaf(bp->b_data, bp->b_bcount, bp));
+
+ return (is_internal(bp->b_data, bp->b_bcount, bp));
+}
+
+int
+search_by_key(struct reiserfs_sb_info *p_s_sbi,
+ const struct cpu_key * p_s_key, /* Key to search. */
+ struct path * p_s_search_path, /* This structure was allocated and
+ initialized by the calling function.
+ It is filled up by this function. */
+ int n_stop_level) /* How far down the tree to search. To
+ stop at leaf level - set to
+ DISK_LEAF_NODE_LEVEL */
+{
+ int error;
+ int n_node_level, n_retval;
+ int n_block_number, expected_level, fs_gen;
+ struct path_element *p_s_last_element;
+ struct buf *p_s_bp, *tmp_bp;
+
+ /*
+ * As we add each node to a path we increase its count. This means that
+ * we must be careful to release all nodes in a path before we either
+ * discard the path struct or re-use the path struct, as we do here.
+ */
+ decrement_counters_in_path(p_s_search_path);
+
+ /*
+ * With each iteration of this loop we search through the items in the
+ * current node, and calculate the next current node(next path element)
+ * for the next iteration of this loop...
+ */
+ n_block_number = SB_ROOT_BLOCK(p_s_sbi);
+ expected_level = -1;
+
+ reiserfs_log(LOG_DEBUG, "root block: #%d\n", n_block_number);
+
+ while (1) {
+ /* Prep path to have another element added to it. */
+ reiserfs_log(LOG_DEBUG, "path element #%d\n",
+ p_s_search_path->path_length);
+ p_s_last_element = PATH_OFFSET_PELEMENT(p_s_search_path,
+ ++p_s_search_path->path_length);
+ fs_gen = get_generation(p_s_sbi);
+
+ /*
+ * Read the next tree node, and set the last element in the
+ * path to have a pointer to it.
+ */
+ reiserfs_log(LOG_DEBUG, "reading block #%d\n",
+ n_block_number);
+ if ((error = bread(p_s_sbi->s_devvp,
+ n_block_number * btodb(p_s_sbi->s_blocksize),
+ p_s_sbi->s_blocksize, NOCRED, &tmp_bp)) != 0) {
+ reiserfs_log(LOG_DEBUG, "error reading block\n");
+ p_s_search_path->path_length--;
+ pathrelse(p_s_search_path);
+ return (IO_ERROR);
+ }
+ reiserfs_log(LOG_DEBUG, "blkno = %ju, lblkno = %ju\n",
+ (intmax_t)tmp_bp->b_blkno, (intmax_t)tmp_bp->b_lblkno);
+
+ /*
+ * As i didn't found a way to handle the lock correctly,
+ * i copy the data into a fake buffer
+ */
+ reiserfs_log(LOG_DEBUG, "allocating p_s_bp\n");
+ p_s_bp = malloc(sizeof *p_s_bp, M_REISERFSPATH, M_WAITOK);
+ if (!p_s_bp) {
+ reiserfs_log(LOG_DEBUG, "error allocating memory\n");
+ p_s_search_path->path_length--;
+ pathrelse(p_s_search_path);
+ brelse(tmp_bp);
+ return (IO_ERROR);
+ }
+ reiserfs_log(LOG_DEBUG, "copying struct buf\n");
+ bcopy(tmp_bp, p_s_bp, sizeof(struct buf));
+
+ reiserfs_log(LOG_DEBUG, "allocating p_s_bp->b_data\n");
+ p_s_bp->b_data = malloc(p_s_sbi->s_blocksize,
+ M_REISERFSPATH, M_WAITOK);
+ if (!p_s_bp->b_data) {
+ reiserfs_log(LOG_DEBUG, "error allocating memory\n");
+ p_s_search_path->path_length--;
+ pathrelse(p_s_search_path);
+ free(p_s_bp, M_REISERFSPATH);
+ brelse(tmp_bp);
+ return (IO_ERROR);
+ }
+ reiserfs_log(LOG_DEBUG, "copying buffer data\n");
+ bcopy(tmp_bp->b_data, p_s_bp->b_data, p_s_sbi->s_blocksize);
+ brelse(tmp_bp);
+ tmp_bp = NULL;
+
+ reiserfs_log(LOG_DEBUG, "...done\n");
+ p_s_last_element->pe_buffer = p_s_bp;
+
+ if (expected_level == -1)
+ expected_level = SB_TREE_HEIGHT(p_s_sbi);
+ expected_level--;
+ reiserfs_log(LOG_DEBUG, "expected level: %d (%d)\n",
+ expected_level, SB_TREE_HEIGHT(p_s_sbi));
+
+ /* XXX */
+ /*
+ * It is possible that schedule occurred. We must check
+ * whether the key to search is still in the tree rooted
+ * from the current buffer. If not then repeat search
+ * from the root.
+ */
+ if (fs_changed(fs_gen, p_s_sbi) &&
+ (!B_IS_IN_TREE(p_s_bp) ||
+ B_LEVEL(p_s_bp) != expected_level ||
+ !key_in_buffer(p_s_search_path, p_s_key, p_s_sbi))) {
+ reiserfs_log(LOG_DEBUG,
+ "the key isn't in the tree anymore\n");
+ decrement_counters_in_path(p_s_search_path);
+
+ /*
+ * Get the root block number so that we can repeat
+ * the search starting from the root.
+ */
+ n_block_number = SB_ROOT_BLOCK(p_s_sbi);
+ expected_level = -1;
+
+ /* Repeat search from the root */
+ continue;
+ }
+
+ /*
+ * Make sure, that the node contents look like a node of
+ * certain level
+ */
+ if (!is_tree_node(p_s_bp, expected_level)) {
+ reiserfs_log(LOG_WARNING,
+ "invalid format found in block %ju. Fsck?",
+ (intmax_t)p_s_bp->b_blkno);
+ pathrelse (p_s_search_path);
+ return (IO_ERROR);
+ }
+
+ /* Ok, we have acquired next formatted node in the tree */
+ n_node_level = B_LEVEL(p_s_bp);
+ reiserfs_log(LOG_DEBUG, "block info:\n");
+ reiserfs_log(LOG_DEBUG, " node level: %d\n",
+ n_node_level);
+ reiserfs_log(LOG_DEBUG, " nb of items: %d\n",
+ B_NR_ITEMS(p_s_bp));
+ reiserfs_log(LOG_DEBUG, " free space: %d bytes\n",
+ B_FREE_SPACE(p_s_bp));
+ reiserfs_log(LOG_DEBUG, "bin_search with :\n"
+ " p_s_key = (objectid=%d, dirid=%d)\n"
+ " B_NR_ITEMS(p_s_bp) = %d\n"
+ " p_s_last_element->pe_position = %d (path_length = %d)\n",
+ p_s_key->on_disk_key.k_objectid,
+ p_s_key->on_disk_key.k_dir_id,
+ B_NR_ITEMS(p_s_bp),
+ p_s_last_element->pe_position,
+ p_s_search_path->path_length);
+ n_retval = bin_search(p_s_key, B_N_PITEM_HEAD(p_s_bp, 0),
+ B_NR_ITEMS(p_s_bp),
+ (n_node_level == DISK_LEAF_NODE_LEVEL) ? IH_SIZE : KEY_SIZE,
+ &(p_s_last_element->pe_position));
+ reiserfs_log(LOG_DEBUG, "bin_search result: %d\n",
+ n_retval);
+ if (n_node_level == n_stop_level) {
+ reiserfs_log(LOG_DEBUG, "stop level reached (%s)\n",
+ n_retval == ITEM_FOUND ? "found" : "not found");
+ return (n_retval);
+ }
+
+ /* We are not in the stop level */
+ if (n_retval == ITEM_FOUND)
+ /*
+ * Item has been found, so we choose the pointer
+ * which is to the right of the found one
+ */
+ p_s_last_element->pe_position++;
+
+ /*
+ * If item was not found we choose the position which is
+ * to the left of the found item. This requires no code,
+ * bin_search did it already.
+ */
+
+ /*
+ * So we have chosen a position in the current node which
+ * is an internal node. Now we calculate child block number
+ * by position in the node.
+ */
+ n_block_number = B_N_CHILD_NUM(p_s_bp,
+ p_s_last_element->pe_position);
+ }
+
+ reiserfs_log(LOG_DEBUG, "done\n");
+ return (0);
+}
+
+/*
+ * Form the path to an item and position in this item which contains
+ * file byte defined by p_s_key. If there is no such item corresponding
+ * to the key, we point the path to the item with maximal key less than
+ * p_s_key, and *p_n_pos_in_item is set to one past the last entry/byte
+ * in the item. If searching for entry in a directory item, and it is
+ * not found, *p_n_pos_in_item is set to one entry more than the entry
+ * with maximal key which is less than the sought key.
+ *
+ * Note that if there is no entry in this same node which is one more,
+ * then we point to an imaginary entry. For direct items, the position
+ * is in units of bytes, for indirect items the position is in units
+ * of blocknr entries, for directory items the position is in units of
+ * directory entries.
+ */
+
+/* The function is NOT SCHEDULE-SAFE! */
+int
+search_for_position_by_key(struct reiserfs_sb_info *p_s_sbi,
+ const struct cpu_key *p_cpu_key, /* Key to search (cpu variable) */
+ struct path *p_s_search_path) /* Filled up by this function. */
+{
+ int retval, n_blk_size;
+ off_t item_offset, offset;
+ struct item_head *p_le_ih; /* Pointer to on-disk structure */
+ struct reiserfs_dir_entry de;
+
+ /* If searching for directory entry. */
+ if (is_direntry_cpu_key(p_cpu_key))
+ return (search_by_entry_key(p_s_sbi, p_cpu_key,
+ p_s_search_path, &de));
+
+ /* If not searching for directory entry. */
+
+ /* If item is found. */
+ retval = search_item(p_s_sbi, p_cpu_key, p_s_search_path);
+ if (retval == IO_ERROR)
+ return (retval);
+ if (retval == ITEM_FOUND) {
+ if (ih_item_len(B_N_PITEM_HEAD(
+ PATH_PLAST_BUFFER(p_s_search_path),
+ PATH_LAST_POSITION(p_s_search_path))) == 0) {
+ reiserfs_log(LOG_WARNING, "item length equals zero\n");
+ }
+
+ pos_in_item(p_s_search_path) = 0;
+ return (POSITION_FOUND);
+ }
+
+ if (PATH_LAST_POSITION(p_s_search_path) == 0) {
+ reiserfs_log(LOG_WARNING, "position equals zero\n");
+ }
+
+ /* Item is not found. Set path to the previous item. */
+ p_le_ih = B_N_PITEM_HEAD(PATH_PLAST_BUFFER(p_s_search_path),
+ --PATH_LAST_POSITION(p_s_search_path));
+ n_blk_size = p_s_sbi->s_blocksize;
+
+ if (comp_short_keys(&(p_le_ih->ih_key), p_cpu_key)) {
+ return (FILE_NOT_FOUND);
+ }
+
+ item_offset = le_ih_k_offset(p_le_ih);
+ offset = cpu_key_k_offset(p_cpu_key);
+
+ /* Needed byte is contained in the item pointed to by the path.*/
+ if (item_offset <= offset &&
+ item_offset + op_bytes_number(p_le_ih, n_blk_size) > offset) {
+ pos_in_item(p_s_search_path) = offset - item_offset;
+ if (is_indirect_le_ih(p_le_ih)) {
+ pos_in_item(p_s_search_path) /= n_blk_size;
+ }
+ return (POSITION_FOUND);
+ }
+
+ /* Needed byte is not contained in the item pointed to by the
+ * path. Set pos_in_item out of the item. */
+ if (is_indirect_le_ih(p_le_ih))
+ pos_in_item(p_s_search_path) =
+ ih_item_len(p_le_ih) / UNFM_P_SIZE;
+ else
+ pos_in_item(p_s_search_path) =
+ ih_item_len(p_le_ih);
+
+ return (POSITION_NOT_FOUND);
+}
diff --git a/sys/gnu/fs/reiserfs/reiserfs_vfsops.c b/sys/gnu/fs/reiserfs/reiserfs_vfsops.c
new file mode 100644
index 000000000000..4bb425ac85ae
--- /dev/null
+++ b/sys/gnu/fs/reiserfs/reiserfs_vfsops.c
@@ -0,0 +1,1186 @@
+/*-
+ * Copyright 2000 Hans Reiser
+ * See README for licensing and copyright details
+ *
+ * Ported to FreeBSD by Jean-Sébastien Pédron <jspedron@club-internet.fr>
+ *
+ * $FreeBSD$
+ */
+
+#include <gnu/fs/reiserfs/reiserfs_fs.h>
+
+const char reiserfs_3_5_magic_string[] = REISERFS_SUPER_MAGIC_STRING;
+const char reiserfs_3_6_magic_string[] = REISER2FS_SUPER_MAGIC_STRING;
+const char reiserfs_jr_magic_string[] = REISER2FS_JR_SUPER_MAGIC_STRING;
+
+/*
+ * Default recommended I/O size is 128k. There might be broken
+ * applications that are confused by this. Use nolargeio mount option to
+ * get usual i/o size = PAGE_SIZE.
+ */
+int reiserfs_default_io_size = 128 * 1024;
+
+static vfs_cmount_t reiserfs_cmount;
+static vfs_fhtovp_t reiserfs_fhtovp;
+static vfs_mount_t reiserfs_mount;
+static vfs_root_t reiserfs_root;
+static vfs_statfs_t reiserfs_statfs;
+static vfs_unmount_t reiserfs_unmount;
+static vfs_vptofh_t reiserfs_vptofh;
+
+static int reiserfs_mountfs(struct vnode *devvp, struct mount *mp,
+ struct thread *td);
+static void load_bitmap_info_data(struct reiserfs_sb_info *sbi,
+ struct reiserfs_bitmap_info *bi);
+static int read_bitmaps(struct reiserfs_mount *rmp);
+static int read_old_bitmaps(struct reiserfs_mount *rmp);
+static int read_super_block(struct reiserfs_mount *rmp, int offset);
+static hashf_t hash_function(struct reiserfs_mount *rmp);
+
+static int get_root_node(struct reiserfs_mount *rmp,
+ struct reiserfs_node **root);
+uint32_t find_hash_out(struct reiserfs_mount *rmp);
+
+MALLOC_DEFINE(M_REISERFSMNT, "ReiserFS mount", "ReiserFS mount structure");
+MALLOC_DEFINE(M_REISERFSPATH, "ReiserFS path", "ReiserFS path structure");
+MALLOC_DEFINE(M_REISERFSNODE, "ReiserFS node", "ReiserFS vnode private part");
+
+/* -------------------------------------------------------------------
+ * VFS operations
+ * -------------------------------------------------------------------*/
+
+static int
+reiserfs_cmount(struct mntarg *ma, void *data, int flags, struct thread *td)
+{
+ struct reiserfs_args args;
+ int error;
+
+ error = copyin(data, &args, sizeof(args));
+ if (error)
+ return (error);
+
+ ma = mount_argsu(ma, "from", args.fspec, MAXPATHLEN);
+ ma = mount_arg(ma, "export", &args.export, sizeof args.export);
+
+ error = kernel_mount(ma, flags);
+
+ return (error);
+}
+
+/*
+ * Mount system call
+ */
+static int
+reiserfs_mount(struct mount *mp, struct thread *td)
+{
+ size_t size;
+ int error, len;
+ mode_t accessmode;
+ char *path, *fspec;
+ struct vnode *devvp;
+ struct vfsoptlist *opts;
+ struct export_args *export;
+ struct reiserfs_mount *rmp;
+ struct reiserfs_sb_info *sbi;
+ struct nameidata nd, *ndp = &nd;
+
+ if (!(mp->mnt_flag & MNT_RDONLY))
+ return EROFS;
+
+ /* Get the new options passed to mount */
+ opts = mp->mnt_optnew;
+
+ /* `fspath' contains the mount point (eg. /mnt/linux); REQUIRED */
+ vfs_getopt(opts, "fspath", (void **)&path, NULL);
+ reiserfs_log(LOG_INFO, "mount point is `%s'\n", path);
+
+ /* `from' contains the device name (eg. /dev/ad0s1); REQUIRED */
+ fspec = NULL;
+ error = vfs_getopt(opts, "from", (void **)&fspec, &len);
+ if (!error && fspec[len - 1] != '\0')
+ return (EINVAL);
+ reiserfs_log(LOG_INFO, "device is `%s'\n", fspec);
+
+ /* Handle MNT_UPDATE (mp->mnt_flag) */
+ if (mp->mnt_flag & MNT_UPDATE) {
+ /* For now, only NFS export is supported. */
+ error = vfs_getopt(opts, "export", (void **)&export, &len);
+ if (error == 0 && len == sizeof(*export) && export->ex_flags)
+ return (vfs_export(mp, export));
+ }
+
+ /* Not an update, or updating the name: look up the name
+ * and verify that it refers to a sensible disk device. */
+ if (fspec == NULL)
+ return (EINVAL);
+
+ NDINIT(ndp, LOOKUP, FOLLOW, UIO_SYSSPACE, fspec, td);
+ if ((error = namei(ndp)) != 0)
+ return (error);
+ NDFREE(ndp, NDF_ONLY_PNBUF);
+ devvp = ndp->ni_vp;
+
+ if (!vn_isdisk(devvp, &error)) {
+ vrele(devvp);
+ return (error);
+ }
+
+ /* If mount by non-root, then verify that user has necessary
+ * permissions on the device. */
+ if (suser(td)) {
+ accessmode = VREAD;
+ if ((mp->mnt_flag & MNT_RDONLY) == 0)
+ accessmode |= VWRITE;
+ vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td);
+ if ((error = VOP_ACCESS(devvp,
+ accessmode, td->td_ucred, td)) != 0) {
+ vput(devvp);
+ return (error);
+ }
+ VOP_UNLOCK(devvp, 0, td);
+ }
+
+ if ((mp->mnt_flag & MNT_UPDATE) == 0) {
+ error = reiserfs_mountfs(devvp, mp, td);
+ } else {
+ /* TODO Handle MNT_UPDATE */
+ error = (EOPNOTSUPP);
+ }
+
+ if (error) {
+ vrele(devvp);
+ return (error);
+ }
+
+ rmp = VFSTOREISERFS(mp);
+ sbi = rmp->rm_reiserfs;
+
+ /*
+ * Note that this strncpy() is ok because of a check at the start
+ * of reiserfs_mount().
+ */
+ reiserfs_log(LOG_DEBUG, "prepare statfs data\n");
+ (void)copystr(fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size);
+ bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
+ (void)reiserfs_statfs(mp, &mp->mnt_stat, td);
+
+ reiserfs_log(LOG_DEBUG, "done\n");
+ return (0);
+}
+
+/*
+ * Unmount system call
+ */
+static int
+reiserfs_unmount(struct mount *mp, int mntflags, struct thread *td)
+{
+ int error, flags = 0;
+ struct reiserfs_mount *rmp;
+ struct reiserfs_sb_info *sbi;
+
+ reiserfs_log(LOG_DEBUG, "get private data\n");
+ rmp = VFSTOREISERFS(mp);
+ sbi = rmp->rm_reiserfs;
+
+ /* Flangs handling */
+ reiserfs_log(LOG_DEBUG, "handle mntflags\n");
+ if (mntflags & MNT_FORCE)
+ flags |= FORCECLOSE;
+
+ /* Flush files -> vflush */
+ reiserfs_log(LOG_DEBUG, "flush vnodes\n");
+ if ((error = vflush(mp, 0, flags, td)))
+ return (error);
+
+ /* XXX Super block update */
+
+ if (sbi) {
+ if (SB_AP_BITMAP(sbi)) {
+ int i;
+ reiserfs_log(LOG_DEBUG,
+ "release bitmap buffers (total: %d)\n",
+ SB_BMAP_NR(sbi));
+ for (i = 0; i < SB_BMAP_NR(sbi); i++) {
+ if (SB_AP_BITMAP(sbi)[i].bp_data) {
+ free(SB_AP_BITMAP(sbi)[i].bp_data,
+ M_REISERFSMNT);
+ SB_AP_BITMAP(sbi)[i].bp_data = NULL;
+ }
+ }
+
+ reiserfs_log(LOG_DEBUG, "free bitmaps structure\n");
+ free(SB_AP_BITMAP(sbi), M_REISERFSMNT);
+ SB_AP_BITMAP(sbi) = NULL;
+ }
+
+ if (sbi->s_rs) {
+ reiserfs_log(LOG_DEBUG, "free super block data\n");
+ free(sbi->s_rs, M_REISERFSMNT);
+ sbi->s_rs = NULL;
+ }
+ }
+
+ reiserfs_log(LOG_DEBUG, "close device\n");
+#if defined(si_mountpoint)
+ rmp->rm_devvp->v_rdev->si_mountpoint = NULL;
+#endif
+
+ DROP_GIANT();
+ g_topology_lock();
+ g_wither_geom_close(rmp->rm_cp->geom, ENXIO);
+ g_topology_unlock();
+ PICKUP_GIANT();
+ vrele(rmp->rm_devvp);
+
+ if (sbi) {
+ reiserfs_log(LOG_DEBUG, "free sbi\n");
+ free(sbi, M_REISERFSMNT);
+ sbi = rmp->rm_reiserfs = NULL;
+ }
+ if (rmp) {
+ reiserfs_log(LOG_DEBUG, "free rmp\n");
+ free(rmp, M_REISERFSMNT);
+ rmp = NULL;
+ }
+
+ mp->mnt_data = (qaddr_t)0;
+ mp->mnt_flag &= ~MNT_LOCAL;
+
+ reiserfs_log(LOG_DEBUG, "done\n");
+ return (error);
+}
+
+/*
+ * Return the root of a filesystem.
+ */
+static int
+reiserfs_root(struct mount *mp, int flags, struct vnode **vpp,
+ struct thread *td)
+{
+ int error;
+ struct vnode *vp;
+ struct cpu_key rootkey;
+
+ rootkey.on_disk_key.k_dir_id = REISERFS_ROOT_PARENT_OBJECTID;
+ rootkey.on_disk_key.k_objectid = REISERFS_ROOT_OBJECTID;
+
+ error = reiserfs_iget(mp, &rootkey, &vp, td);
+
+ if (error == 0)
+ *vpp = vp;
+ return (error);
+}
+
+/*
+ * The statfs syscall
+ */
+static int
+reiserfs_statfs(struct mount *mp, struct statfs *sbp, struct thread *td)
+{
+ struct reiserfs_mount *rmp;
+ struct reiserfs_sb_info *sbi;
+ struct reiserfs_super_block *rs;
+
+ reiserfs_log(LOG_DEBUG, "get private data\n");
+ rmp = VFSTOREISERFS(mp);
+ sbi = rmp->rm_reiserfs;
+ rs = sbi->s_rs;
+
+ reiserfs_log(LOG_DEBUG, "fill statfs structure\n");
+ sbp->f_bsize = sbi->s_blocksize;
+ sbp->f_iosize = sbp->f_bsize;
+ sbp->f_blocks = sb_block_count(rs) - sb_bmap_nr(rs) - 1;
+ sbp->f_bfree = sb_free_blocks(rs);
+ sbp->f_bavail = sbp->f_bfree;
+ sbp->f_files = 0;
+ sbp->f_ffree = 0;
+ reiserfs_log(LOG_DEBUG, " block size = %ju\n",
+ (intmax_t)sbp->f_bsize);
+ reiserfs_log(LOG_DEBUG, " IO size = %ju\n",
+ (intmax_t)sbp->f_iosize);
+ reiserfs_log(LOG_DEBUG, " block count = %ju\n",
+ (intmax_t)sbp->f_blocks);
+ reiserfs_log(LOG_DEBUG, " free blocks = %ju\n",
+ (intmax_t)sbp->f_bfree);
+ reiserfs_log(LOG_DEBUG, " avail blocks = %ju\n",
+ (intmax_t)sbp->f_bavail);
+ reiserfs_log(LOG_DEBUG, "...done\n");
+
+ if (sbp != &mp->mnt_stat) {
+ reiserfs_log(LOG_DEBUG, "copying monut point info\n");
+ sbp->f_type = mp->mnt_vfc->vfc_typenum;
+ bcopy((caddr_t)mp->mnt_stat.f_mntonname,
+ (caddr_t)&sbp->f_mntonname[0], MNAMELEN);
+ bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
+ (caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
+ reiserfs_log(LOG_DEBUG, " mount from: %s\n",
+ sbp->f_mntfromname);
+ reiserfs_log(LOG_DEBUG, " mount on: %s\n",
+ sbp->f_mntonname);
+ reiserfs_log(LOG_DEBUG, "...done\n");
+ }
+
+ return (0);
+}
+
+/*
+ * File handle to vnode
+ *
+ * Have to be really careful about stale file handles:
+ * - check that the inode key is valid
+ * - call ffs_vget() to get the locked inode
+ * - check for an unallocated inode (i_mode == 0)
+ * - check that the given client host has export rights and return
+ * those rights via. exflagsp and credanonp
+ */
+static int
+reiserfs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
+{
+ int error;
+ struct rfid *rfhp;
+ struct vnode *nvp;
+ struct cpu_key key;
+ struct reiserfs_node *ip;
+ struct reiserfs_sb_info *sbi;
+ struct thread *td = curthread;
+
+ rfhp = (struct rfid *)fhp;
+ sbi = VFSTOREISERFS(mp)->rm_reiserfs;
+
+ /* Check that the key is valid */
+ if (rfhp->rfid_dirid < REISERFS_ROOT_PARENT_OBJECTID &&
+ rfhp->rfid_objectid < REISERFS_ROOT_OBJECTID)
+ return (ESTALE);
+
+ reiserfs_log(LOG_DEBUG,
+ "file handle key is (dirid=%d, objectid=%d)\n",
+ rfhp->rfid_dirid, rfhp->rfid_objectid);
+ key.on_disk_key.k_dir_id = rfhp->rfid_dirid;
+ key.on_disk_key.k_objectid = rfhp->rfid_objectid;
+
+ reiserfs_log(LOG_DEBUG, "read this inode\n");
+ error = reiserfs_iget(mp, &key, &nvp, td);
+ if (error) {
+ *vpp = NULLVP;
+ return (error);
+ }
+
+ reiserfs_log(LOG_DEBUG, "check validity\n");
+ ip = VTOI(nvp);
+ if (ip->i_mode == 0 || ip->i_generation != rfhp->rfid_gen) {
+ vput(nvp);
+ *vpp = NULLVP;
+ return (ESTALE);
+ }
+
+ reiserfs_log(LOG_DEBUG, "return it\n");
+ *vpp = nvp;
+ return (0);
+}
+
+/*
+ * Vnode pointer to File handle
+ */
+static int
+reiserfs_vptofh(struct vnode *vp, struct fid *fhp)
+{
+ struct rfid *rfhp;
+ struct reiserfs_node *ip;
+
+ ip = VTOI(vp);
+ reiserfs_log(LOG_DEBUG,
+ "fill *fhp with inode (dirid=%d, objectid=%d)\n",
+ ip->i_ino, ip->i_number);
+
+ rfhp = (struct rfid *)fhp;
+ rfhp->rfid_len = sizeof(struct rfid);
+ rfhp->rfid_dirid = ip->i_ino;
+ rfhp->rfid_objectid = ip->i_number;
+ rfhp->rfid_gen = ip->i_generation;
+
+ reiserfs_log(LOG_DEBUG, "return it\n");
+ return (0);
+}
+
+/* -------------------------------------------------------------------
+ * Functions for the journal
+ * -------------------------------------------------------------------*/
+
+int
+is_reiserfs_3_5(struct reiserfs_super_block *rs)
+{
+
+ return (!strncmp(rs->s_v1.s_magic, reiserfs_3_5_magic_string,
+ strlen(reiserfs_3_5_magic_string)));
+}
+
+int
+is_reiserfs_3_6(struct reiserfs_super_block *rs)
+{
+
+ return (!strncmp(rs->s_v1.s_magic, reiserfs_3_6_magic_string,
+ strlen(reiserfs_3_6_magic_string)));
+}
+
+int
+is_reiserfs_jr(struct reiserfs_super_block *rs)
+{
+
+ return (!strncmp(rs->s_v1.s_magic, reiserfs_jr_magic_string,
+ strlen(reiserfs_jr_magic_string)));
+}
+
+static int
+is_any_reiserfs_magic_string(struct reiserfs_super_block *rs)
+{
+
+ return ((is_reiserfs_3_5(rs) || is_reiserfs_3_6(rs) ||
+ is_reiserfs_jr(rs)));
+}
+
+/* -------------------------------------------------------------------
+ * Internal functions
+ * -------------------------------------------------------------------*/
+
+/*
+ * Common code for mount and mountroot
+ */
+static int
+reiserfs_mountfs(struct vnode *devvp, struct mount *mp, struct thread *td)
+{
+ int error, old_format = 0;
+ struct reiserfs_mount *rmp;
+ struct reiserfs_sb_info *sbi;
+ struct reiserfs_super_block *rs;
+ struct cdev *dev = devvp->v_rdev;
+
+#if (__FreeBSD_version >= 600000)
+ struct g_consumer *cp;
+ struct bufobj *bo;
+#endif
+
+ //ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
+
+#if (__FreeBSD_version < 600000)
+ /*
+ * Disallow multiple mounts of the same device.
+ * Disallow mounting of a device that is currently in use
+ * (except for root, which might share swap device for miniroot).
+ * Flush out any old buffers remaining from a previous use.
+ */
+ if ((error = vfs_mountedon(devvp)) != 0)
+ return (error);
+ if (vcount(devvp) > 1)
+ return (EBUSY);
+
+ vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td);
+ error = vinvalbuf(devvp, V_SAVE, td->td_ucred, td, 0, 0);
+ if (error) {
+ VOP_UNLOCK(devvp, 0, td);
+ return (error);
+ }
+
+ /*
+ * Open the device in read-only, 'cause we don't support write
+ * for now
+ */
+ error = VOP_OPEN(devvp, FREAD, FSCRED, td, -1);
+ VOP_UNLOCK(devvp, 0, td);
+ if (error)
+ return (error);
+#else
+ DROP_GIANT();
+ g_topology_lock();
+ error = g_vfs_open(devvp, &cp, "reiserfs", /* read-only */ 0);
+ g_topology_unlock();
+ PICKUP_GIANT();
+ VOP_UNLOCK(devvp, 0, td);
+ if (error)
+ return (error);
+
+ bo = &devvp->v_bufobj;
+ bo->bo_private = cp;
+ bo->bo_ops = g_vfs_bufops;
+#endif
+
+ if (devvp->v_rdev->si_iosize_max != 0)
+ mp->mnt_iosize_max = devvp->v_rdev->si_iosize_max;
+ if (mp->mnt_iosize_max > MAXPHYS)
+ mp->mnt_iosize_max = MAXPHYS;
+
+ rmp = NULL;
+ sbi = NULL;
+
+ /* rmp contains any information about this specific mount */
+ rmp = malloc(sizeof *rmp, M_REISERFSMNT, M_WAITOK | M_ZERO);
+ if (!rmp) {
+ error = (ENOMEM);
+ goto out;
+ }
+ sbi = malloc(sizeof *sbi, M_REISERFSMNT, M_WAITOK | M_ZERO);
+ if (!sbi) {
+ error = (ENOMEM);
+ goto out;
+ }
+ rmp->rm_reiserfs = sbi;
+ rmp->rm_mountp = mp;
+ rmp->rm_devvp = devvp;
+ rmp->rm_dev = dev;
+#if (__FreeBSD_version >= 600000)
+ rmp->rm_bo = &devvp->v_bufobj;
+ rmp->rm_cp = cp;
+#endif
+
+ /* Set default values for options: non-aggressive tails */
+ REISERFS_SB(sbi)->s_mount_opt = (1 << REISERFS_SMALLTAIL);
+ REISERFS_SB(sbi)->s_rd_only = 1;
+ REISERFS_SB(sbi)->s_devvp = devvp;
+
+ /* Read the super block */
+ if ((error = read_super_block(rmp, REISERFS_OLD_DISK_OFFSET)) == 0) {
+ /* The read process succeeded, it's an old format */
+ old_format = 1;
+ } else if ((error = read_super_block(rmp, REISERFS_DISK_OFFSET)) != 0) {
+ reiserfs_log(LOG_ERR, "can not find a ReiserFS filesystem\n");
+ goto out;
+ }
+
+ rs = SB_DISK_SUPER_BLOCK(sbi);
+
+ /*
+ * Let's do basic sanity check to verify that underlying device is
+ * not smaller than the filesystem. If the check fails then abort and
+ * scream, because bad stuff will happen otherwise.
+ */
+#if 0
+ if (s->s_bdev && s->s_bdev->bd_inode &&
+ i_size_read(s->s_bdev->bd_inode) <
+ sb_block_count(rs) * sb_blocksize(rs)) {
+ reiserfs_log(LOG_ERR,
+ "reiserfs: filesystem cannot be mounted because it is "
+ "bigger than the device.\n");
+ reiserfs_log(LOG_ERR, "reiserfs: you may need to run fsck "
+ "rr may be you forgot to reboot after fdisk when it "
+ "told you to.\n");
+ goto out;
+ }
+#endif
+
+ /*
+ * XXX This is from the original Linux code, but why affecting 2 values
+ * to the same variable?
+ */
+ sbi->s_mount_state = SB_REISERFS_STATE(sbi);
+ sbi->s_mount_state = REISERFS_VALID_FS;
+
+ if ((error = (old_format ?
+ read_old_bitmaps(rmp) : read_bitmaps(rmp)))) {
+ reiserfs_log(LOG_ERR, "unable to read bitmap\n");
+ goto out;
+ }
+
+ /* Make data=ordered the default */
+ if (!reiserfs_data_log(sbi) && !reiserfs_data_ordered(sbi) &&
+ !reiserfs_data_writeback(sbi)) {
+ REISERFS_SB(sbi)->s_mount_opt |= (1 << REISERFS_DATA_ORDERED);
+ }
+
+ if (reiserfs_data_log(sbi)) {
+ reiserfs_log(LOG_INFO, "using journaled data mode\n");
+ } else if (reiserfs_data_ordered(sbi)) {
+ reiserfs_log(LOG_INFO, "using ordered data mode\n");
+ } else {
+ reiserfs_log(LOG_INFO, "using writeback data mode\n");
+ }
+
+ /* TODO Not yet supported */
+#if 0
+ if(journal_init(sbi, jdev_name, old_format, commit_max_age)) {
+ reiserfs_log(LOG_ERR, "unable to initialize journal space\n");
+ goto out;
+ } else {
+ jinit_done = 1 ; /* once this is set, journal_release must
+ be called if we error out of the mount */
+ }
+
+ if (reread_meta_blocks(sbi)) {
+ reiserfs_log(LOG_ERR,
+ "unable to reread meta blocks after journal init\n");
+ goto out;
+ }
+#endif
+
+ /* Define and initialize hash function */
+ sbi->s_hash_function = hash_function(rmp);
+
+ if (sbi->s_hash_function == NULL) {
+ reiserfs_log(LOG_ERR, "couldn't determined hash function\n");
+ error = (EINVAL);
+ goto out;
+ }
+
+ if (is_reiserfs_3_5(rs) ||
+ (is_reiserfs_jr(rs) && SB_VERSION(sbi) == REISERFS_VERSION_1))
+ bit_set(&(sbi->s_properties), REISERFS_3_5);
+ else
+ bit_set(&(sbi->s_properties), REISERFS_3_6);
+
+ mp->mnt_data = (qaddr_t)rmp;
+ mp->mnt_stat.f_fsid.val[0] = dev2udev(dev);
+ mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
+ mp->mnt_flag |= MNT_LOCAL;
+#if defined(si_mountpoint)
+ devvp->v_rdev->si_mountpoint = mp;
+#endif
+
+ return (0);
+
+out:
+ reiserfs_log(LOG_INFO, "*** error during mount ***\n");
+ if (sbi) {
+ if (SB_AP_BITMAP(sbi)) {
+ int i;
+ for (i = 0; i < SB_BMAP_NR(sbi); i++) {
+ if (!SB_AP_BITMAP(sbi)[i].bp_data)
+ break;
+ free(SB_AP_BITMAP(sbi)[i].bp_data, M_REISERFSMNT);
+ }
+ free(SB_AP_BITMAP(sbi), M_REISERFSMNT);
+ }
+
+ if (sbi->s_rs) {
+ free(sbi->s_rs, M_REISERFSMNT);
+ sbi->s_rs = NULL;
+ }
+ }
+
+#if (__FreeBSD_version < 600000)
+ (void)VOP_CLOSE(devvp, FREAD, NOCRED, td);
+#else
+ if (cp != NULL) {
+ DROP_GIANT();
+ g_topology_lock();
+ g_wither_geom_close(cp->geom, ENXIO);
+ g_topology_unlock();
+ PICKUP_GIANT();
+ }
+#endif
+
+ if (sbi)
+ free(sbi, M_REISERFSMNT);
+ if (rmp)
+ free(rmp, M_REISERFSMNT);
+ return (error);
+}
+
+/*
+ * Read the super block
+ */
+static int
+read_super_block(struct reiserfs_mount *rmp, int offset)
+{
+ struct buf *bp;
+ int error, bits;
+ struct reiserfs_super_block *rs;
+ struct reiserfs_sb_info *sbi;
+ uint16_t fs_blocksize;
+
+ if (offset == REISERFS_OLD_DISK_OFFSET) {
+ reiserfs_log(LOG_DEBUG,
+ "reiserfs/super: read old format super block\n");
+ } else {
+ reiserfs_log(LOG_DEBUG,
+ "reiserfs/super: read new format super block\n");
+ }
+
+ /* Read the super block */
+ if ((error = bread(rmp->rm_devvp, offset * btodb(REISERFS_BSIZE),
+ REISERFS_BSIZE, NOCRED, &bp)) != 0) {
+ reiserfs_log(LOG_ERR, "can't read device\n");
+ return (error);
+ }
+
+ /* Get it from the buffer data */
+ rs = (struct reiserfs_super_block *)bp->b_data;
+ if (!is_any_reiserfs_magic_string(rs)) {
+ brelse(bp);
+ return (EINVAL);
+ }
+
+ fs_blocksize = sb_blocksize(rs);
+ brelse(bp);
+ bp = NULL;
+
+ if (fs_blocksize <= 0) {
+ reiserfs_log(LOG_ERR, "unexpected null block size");
+ return (EINVAL);
+ }
+
+ /* Read the super block (for double check)
+ * We can't read the same blkno with a different size: it causes
+ * panic() if INVARIANTS is set. So we keep REISERFS_BSIZE */
+ if ((error = bread(rmp->rm_devvp,
+ offset * REISERFS_BSIZE / fs_blocksize * btodb(fs_blocksize),
+ REISERFS_BSIZE, NOCRED, &bp)) != 0) {
+ reiserfs_log(LOG_ERR, "can't reread the super block\n");
+ return (error);
+ }
+
+ rs = (struct reiserfs_super_block *)bp->b_data;
+ if (sb_blocksize(rs) != fs_blocksize) {
+ reiserfs_log(LOG_ERR, "unexpected block size "
+ "(found=%u, expected=%u)\n",
+ sb_blocksize(rs), fs_blocksize);
+ brelse(bp);
+ return (EINVAL);
+ }
+
+ reiserfs_log(LOG_DEBUG, "magic: `%s'\n", rs->s_v1.s_magic);
+ reiserfs_log(LOG_DEBUG, "label: `%s'\n", rs->s_label);
+ reiserfs_log(LOG_DEBUG, "block size: %6d\n", sb_blocksize(rs));
+ reiserfs_log(LOG_DEBUG, "block count: %6u\n",
+ rs->s_v1.s_block_count);
+ reiserfs_log(LOG_DEBUG, "bitmaps number: %6u\n",
+ rs->s_v1.s_bmap_nr);
+
+ if (rs->s_v1.s_root_block == -1) {
+ log(LOG_ERR,
+ "reiserfs: Unfinished reiserfsck --rebuild-tree run "
+ "detected. Please\n"
+ "run reiserfsck --rebuild-tree and wait for a "
+ "completion. If that\n"
+ "fails, get newer reiserfsprogs package");
+ brelse(bp);
+ return (EINVAL);
+ }
+
+ sbi = rmp->rm_reiserfs;
+ sbi->s_blocksize = fs_blocksize;
+
+ for (bits = 9, fs_blocksize >>= 9; fs_blocksize >>= 1; bits++)
+ ;
+ sbi->s_blocksize_bits = bits;
+
+ /* Copy the buffer and release it */
+ sbi->s_rs = malloc(sizeof *rs, M_REISERFSMNT, M_WAITOK | M_ZERO);
+ if (!sbi->s_rs) {
+ reiserfs_log(LOG_ERR, "can not read the super block\n");
+ brelse(bp);
+ return (ENOMEM);
+ }
+ bcopy(rs, sbi->s_rs, sizeof(struct reiserfs_super_block));
+ brelse(bp);
+
+ if (is_reiserfs_jr(rs)) {
+ if (sb_version(rs) == REISERFS_VERSION_2)
+ reiserfs_log(LOG_INFO, "found reiserfs format \"3.6\""
+ " with non-standard journal");
+ else if (sb_version(rs) == REISERFS_VERSION_1)
+ reiserfs_log(LOG_INFO, "found reiserfs format \"3.5\""
+ " with non-standard journal");
+ else {
+ reiserfs_log(LOG_ERR, "found unknown "
+ "format \"%u\" of reiserfs with non-standard magic",
+ sb_version(rs));
+ return (EINVAL);
+ }
+ } else {
+ /*
+ * s_version of standard format may contain incorrect
+ * information, so we just look at the magic string
+ */
+ reiserfs_log(LOG_INFO,
+ "found reiserfs format \"%s\" with standard journal\n",
+ is_reiserfs_3_5(rs) ? "3.5" : "3.6");
+ }
+
+ return (0);
+}
+
+/*
+ * load_bitmap_info_data - Sets up the reiserfs_bitmap_info structure
+ * from disk.
+ * @sbi - superblock info for this filesystem
+ * @bi - the bitmap info to be loaded. Requires that bi->bp is valid.
+ *
+ * This routine counts how many free bits there are, finding the first
+ * zero as a side effect. Could also be implemented as a loop of
+ * test_bit() calls, or a loop of find_first_zero_bit() calls. This
+ * implementation is similar to find_first_zero_bit(), but doesn't
+ * return after it finds the first bit. Should only be called on fs
+ * mount, but should be fairly efficient anyways.
+ *
+ * bi->first_zero_hint is considered unset if it == 0, since the bitmap
+ * itself will invariably occupt block 0 represented in the bitmap. The
+ * only exception to this is when free_count also == 0, since there will
+ * be no free blocks at all.
+ */
+static void
+load_bitmap_info_data(struct reiserfs_sb_info *sbi,
+ struct reiserfs_bitmap_info *bi)
+{
+ unsigned long *cur;
+
+ cur = (unsigned long *)bi->bp_data;
+ while ((char *)cur < (bi->bp_data + sbi->s_blocksize)) {
+ /*
+ * No need to scan if all 0's or all 1's.
+ * Since we're only counting 0's, we can simply ignore
+ * all 1's
+ */
+ if (*cur == 0) {
+ if (bi->first_zero_hint == 0) {
+ bi->first_zero_hint =
+ ((char *)cur - bi->bp_data) << 3;
+ }
+ bi->free_count += sizeof(unsigned long) * 8;
+ } else if (*cur != ~0L) {
+ int b;
+
+ for (b = 0; b < sizeof(unsigned long) * 8; b++) {
+ if (!reiserfs_test_le_bit(b, cur)) {
+ bi->free_count++;
+ if (bi->first_zero_hint == 0)
+ bi->first_zero_hint =
+ (((char *)cur -
+ bi->bp_data) << 3) + b;
+ }
+ }
+ }
+ cur++;
+ }
+}
+
+/*
+ * Read the bitmaps
+ */
+static int
+read_bitmaps(struct reiserfs_mount *rmp)
+{
+ int i, bmap_nr;
+ struct buf *bp = NULL;
+ struct reiserfs_sb_info *sbi = rmp->rm_reiserfs;
+
+ /* Allocate memory for the table of bitmaps */
+ SB_AP_BITMAP(sbi) =
+ malloc(sizeof(struct reiserfs_bitmap_info) * SB_BMAP_NR(sbi),
+ M_REISERFSMNT, M_WAITOK | M_ZERO);
+ if (!SB_AP_BITMAP(sbi))
+ return (ENOMEM);
+
+ /* Read all the bitmaps */
+ for (i = 0,
+ bmap_nr = (REISERFS_DISK_OFFSET_IN_BYTES / sbi->s_blocksize + 1) *
+ btodb(sbi->s_blocksize);
+ i < SB_BMAP_NR(sbi); i++, bmap_nr = sbi->s_blocksize * 8 * i) {
+ SB_AP_BITMAP(sbi)[i].bp_data = malloc(sbi->s_blocksize,
+ M_REISERFSMNT, M_WAITOK | M_ZERO);
+ if (!SB_AP_BITMAP(sbi)[i].bp_data)
+ return (ENOMEM);
+ bread(rmp->rm_devvp, bmap_nr, sbi->s_blocksize, NOCRED, &bp);
+ bcopy(bp->b_data, SB_AP_BITMAP(sbi)[i].bp_data,
+ sbi->s_blocksize);
+ brelse(bp);
+ bp = NULL;
+
+ /*if (!buffer_uptodate(SB_AP_BITMAP(s)[i].bh))
+ ll_rw_block(READ, 1, &SB_AP_BITMAP(s)[i].bh);*/
+ }
+
+ for (i = 0; i < SB_BMAP_NR(sbi); i++) {
+ /*if (!buffer_uptodate(SB_AP_BITMAP(s)[i].bh)) {
+ reiserfs_warning(s,"sh-2029: reiserfs read_bitmaps: "
+ "bitmap block (#%lu) reading failed",
+ SB_AP_BITMAP(s)[i].bh->b_blocknr);
+ for (i = 0; i < SB_BMAP_NR(s); i++)
+ brelse(SB_AP_BITMAP(s)[i].bh);
+ vfree(SB_AP_BITMAP(s));
+ SB_AP_BITMAP(s) = NULL;
+ return 1;
+ }*/
+ load_bitmap_info_data(sbi, SB_AP_BITMAP(sbi) + i);
+ reiserfs_log(LOG_DEBUG,
+ "%d free blocks (starting at block %ld)\n",
+ SB_AP_BITMAP(sbi)[i].free_count,
+ (long)SB_AP_BITMAP(sbi)[i].first_zero_hint);
+ }
+
+ return (0);
+}
+
+// TODO Not supported
+static int
+read_old_bitmaps(struct reiserfs_mount *rmp)
+{
+
+ return (EOPNOTSUPP);
+#if 0
+ int i;
+ struct reiserfs_sb_info *sbi = rmp->rm_reiserfs;
+ struct reiserfs_super_block *rs = SB_DISK_SUPER_BLOCK(sbi);
+
+ /* First of bitmap blocks */
+ int bmp1 = (REISERFS_OLD_DISK_OFFSET / sbi->s_blocksize) *
+ btodb(sbi->s_blocksize);
+
+ /* Read true bitmap */
+ SB_AP_BITMAP(sbi) =
+ malloc(sizeof (struct reiserfs_buffer_info *) * sb_bmap_nr(rs),
+ M_REISERFSMNT, M_WAITOK | M_ZERO);
+ if (!SB_AP_BITMAP(sbi))
+ return 1;
+
+ for (i = 0; i < sb_bmap_nr(rs); i ++) {
+ SB_AP_BITMAP(sbi)[i].bp = getblk(rmp->rm_devvp,
+ (bmp1 + i) * btodb(sbi->s_blocksize), sbi->s_blocksize, 0, 0, 0);
+ if (!SB_AP_BITMAP(sbi)[i].bp)
+ return 1;
+ load_bitmap_info_data(sbi, SB_AP_BITMAP(sbi) + i);
+ }
+
+ return 0;
+#endif
+}
+
+/* -------------------------------------------------------------------
+ * Hash detection stuff
+ * -------------------------------------------------------------------*/
+
+static int
+get_root_node(struct reiserfs_mount *rmp, struct reiserfs_node **root)
+{
+ struct reiserfs_node *ip;
+ struct reiserfs_iget_args args;
+
+ /* Allocate the node structure */
+ reiserfs_log(LOG_DEBUG, "malloc(struct reiserfs_node)\n");
+ MALLOC(ip, struct reiserfs_node *, sizeof(struct reiserfs_node),
+ M_REISERFSNODE, M_WAITOK | M_ZERO);
+
+ /* Fill the structure */
+ reiserfs_log(LOG_DEBUG, "filling *ip\n");
+ ip->i_dev = rmp->rm_dev;
+ ip->i_number = REISERFS_ROOT_OBJECTID;
+ ip->i_ino = REISERFS_ROOT_PARENT_OBJECTID;
+ ip->i_reiserfs = rmp->rm_reiserfs;
+
+ /* Read the inode */
+ args.objectid = ip->i_number;
+ args.dirid = ip->i_ino;
+ reiserfs_log(LOG_DEBUG, "call reiserfs_read_locked_inode("
+ "objectid=%d,dirid=%d)\n", args.objectid, args.dirid);
+ reiserfs_read_locked_inode(ip, &args);
+
+ ip->i_devvp = rmp->rm_devvp;
+ //XXX VREF(ip->i_devvp); Is it necessary ?
+
+ *root = ip;
+ return (0);
+}
+
+/*
+ * If root directory is empty - we set default - Yura's - hash and warn
+ * about it.
+ * FIXME: we look for only one name in a directory. If tea and yura both
+ * have the same value - we ask user to send report to the mailing list
+ */
+uint32_t find_hash_out(struct reiserfs_mount *rmp)
+{
+ int retval;
+ struct cpu_key key;
+ INITIALIZE_PATH(path);
+ struct reiserfs_node *ip;
+ struct reiserfs_sb_info *sbi;
+ struct reiserfs_dir_entry de;
+ uint32_t hash = DEFAULT_HASH;
+
+ get_root_node(rmp, &ip);
+ if (!ip)
+ return (UNSET_HASH);
+
+ sbi = rmp->rm_reiserfs;
+
+ do {
+ uint32_t teahash, r5hash, yurahash;
+
+ reiserfs_log(LOG_DEBUG, "make_cpu_key\n");
+ make_cpu_key(&key, ip, ~0, TYPE_DIRENTRY, 3);
+ reiserfs_log(LOG_DEBUG, "search_by_entry_key for "
+ "key(objectid=%d,dirid=%d)\n",
+ key.on_disk_key.k_objectid, key.on_disk_key.k_dir_id);
+ retval = search_by_entry_key(sbi, &key, &path, &de);
+ if (retval == IO_ERROR) {
+ pathrelse(&path);
+ return (UNSET_HASH);
+ }
+ if (retval == NAME_NOT_FOUND)
+ de.de_entry_num--;
+
+ reiserfs_log(LOG_DEBUG, "name found\n");
+
+ set_de_name_and_namelen(&de);
+
+ if (deh_offset(&(de.de_deh[de.de_entry_num])) == DOT_DOT_OFFSET) {
+ /* Allow override in this case */
+ if (reiserfs_rupasov_hash(sbi)) {
+ hash = YURA_HASH;
+ }
+ reiserfs_log(LOG_DEBUG,
+ "FS seems to be empty, autodetect "
+ "is using the default hash");
+ break;
+ }
+
+ r5hash = GET_HASH_VALUE(r5_hash(de.de_name, de.de_namelen));
+ teahash = GET_HASH_VALUE(keyed_hash(de.de_name,
+ de.de_namelen));
+ yurahash = GET_HASH_VALUE(yura_hash(de.de_name, de.de_namelen));
+ if (((teahash == r5hash) &&
+ (GET_HASH_VALUE(
+ deh_offset(&(de.de_deh[de.de_entry_num]))) == r5hash)) ||
+ ((teahash == yurahash) &&
+ (yurahash ==
+ GET_HASH_VALUE(
+ deh_offset(&(de.de_deh[de.de_entry_num]))))) ||
+ ((r5hash == yurahash) &&
+ (yurahash ==
+ GET_HASH_VALUE(
+ deh_offset(&(de.de_deh[de.de_entry_num])))))) {
+ reiserfs_log(LOG_ERR,
+ "unable to automatically detect hash "
+ "function. Please mount with -o "
+ "hash={tea,rupasov,r5}");
+ hash = UNSET_HASH;
+ break;
+ }
+
+ if (GET_HASH_VALUE(
+ deh_offset(&(de.de_deh[de.de_entry_num]))) == yurahash) {
+ reiserfs_log(LOG_DEBUG, "detected YURA hash\n");
+ hash = YURA_HASH;
+ } else if (GET_HASH_VALUE(
+ deh_offset(&(de.de_deh[de.de_entry_num]))) == teahash) {
+ reiserfs_log(LOG_DEBUG, "detected TEA hash\n");
+ hash = TEA_HASH;
+ } else if (GET_HASH_VALUE(
+ deh_offset(&(de.de_deh[de.de_entry_num]))) == r5hash) {
+ reiserfs_log(LOG_DEBUG, "detected R5 hash\n");
+ hash = R5_HASH;
+ } else {
+ reiserfs_log(LOG_WARNING, "unrecognised hash function");
+ hash = UNSET_HASH;
+ }
+ } while (0);
+
+ pathrelse(&path);
+ return (hash);
+}
+
+/* Finds out which hash names are sorted with */
+static int
+what_hash(struct reiserfs_mount *rmp)
+{
+ uint32_t code;
+ struct reiserfs_sb_info *sbi = rmp->rm_reiserfs;
+
+ find_hash_out(rmp);
+ code = sb_hash_function_code(SB_DISK_SUPER_BLOCK(sbi));
+
+ /*
+ * reiserfs_hash_detect() == true if any of the hash mount options
+ * were used. We must check them to make sure the user isn't using a
+ * bad hash value
+ */
+ if (code == UNSET_HASH || reiserfs_hash_detect(sbi))
+ code = find_hash_out(rmp);
+
+ if (code != UNSET_HASH && reiserfs_hash_detect(sbi)) {
+ /*
+ * Detection has found the hash, and we must check against
+ * the mount options
+ */
+ if (reiserfs_rupasov_hash(sbi) && code != YURA_HASH) {
+ reiserfs_log(LOG_ERR, "error, %s hash detected, "
+ "unable to force rupasov hash",
+ reiserfs_hashname(code));
+ code = UNSET_HASH;
+ } else if (reiserfs_tea_hash(sbi) && code != TEA_HASH) {
+ reiserfs_log(LOG_ERR, "error, %s hash detected, "
+ "unable to force tea hash",
+ reiserfs_hashname(code));
+ code = UNSET_HASH;
+ } else if (reiserfs_r5_hash(sbi) && code != R5_HASH) {
+ reiserfs_log(LOG_ERR, "error, %s hash detected, "
+ "unable to force r5 hash",
+ reiserfs_hashname(code));
+ code = UNSET_HASH;
+ }
+ } else {
+ /*
+ * Find_hash_out was not called or could not determine
+ * the hash
+ */
+ if (reiserfs_rupasov_hash(sbi)) {
+ code = YURA_HASH;
+ } else if (reiserfs_tea_hash(sbi)) {
+ code = TEA_HASH;
+ } else if (reiserfs_r5_hash(sbi)) {
+ code = R5_HASH;
+ }
+ }
+
+ /* TODO Not supported yet */
+#if 0
+ /* If we are mounted RW, and we have a new valid hash code, update
+ * the super */
+ if (code != UNSET_HASH &&
+ !(s->s_flags & MS_RDONLY) &&
+ code != sb_hash_function_code(SB_DISK_SUPER_BLOCK(s))) {
+ set_sb_hash_function_code(SB_DISK_SUPER_BLOCK(s), code);
+ }
+#endif
+
+ return (code);
+}
+
+/* Return pointer to appropriate function */
+static hashf_t
+hash_function(struct reiserfs_mount *rmp)
+{
+
+ switch (what_hash(rmp)) {
+ case TEA_HASH:
+ reiserfs_log(LOG_INFO, "using tea hash to sort names\n");
+ return (keyed_hash);
+ case YURA_HASH:
+ reiserfs_log(LOG_INFO, "using rupasov hash to sort names\n");
+ return (yura_hash);
+ case R5_HASH:
+ reiserfs_log(LOG_INFO, "using r5 hash to sort names\n");
+ return (r5_hash);
+ }
+
+ return (NULL);
+}
+
+/* -------------------------------------------------------------------
+ * VFS registration
+ * -------------------------------------------------------------------*/
+
+static struct vfsops reiser_vfsops = {
+ .vfs_cmount = reiserfs_cmount,
+ .vfs_mount = reiserfs_mount,
+ .vfs_unmount = reiserfs_unmount,
+ //.vfs_checkexp = reiserfs_checkexp,
+ //.vfs_extattrctl = reiserfs_extattrctl,
+ .vfs_fhtovp = reiserfs_fhtovp,
+ //.vfs_quotactl = reiserfs_quotactl,
+ .vfs_root = reiserfs_root,
+ //.vfs_start = reiserfs_start,
+ .vfs_statfs = reiserfs_statfs,
+ //.vfs_sync = reiserfs_sync,
+ //.vfs_vget = reiserfs_vget,
+ .vfs_vptofh = reiserfs_vptofh,
+};
+
+VFS_SET(reiser_vfsops, reiserfs, VFCF_READONLY);
diff --git a/sys/gnu/fs/reiserfs/reiserfs_vnops.c b/sys/gnu/fs/reiserfs/reiserfs_vnops.c
new file mode 100644
index 000000000000..9b0ba7d2e509
--- /dev/null
+++ b/sys/gnu/fs/reiserfs/reiserfs_vnops.c
@@ -0,0 +1,353 @@
+/*-
+ * Copyright 2000 Hans Reiser
+ * See README for licensing and copyright details
+ *
+ * Ported to FreeBSD by Jean-Sébastien Pédron <jspedron@club-internet.fr>
+ *
+ * $FreeBSD$
+ */
+
+#include <gnu/fs/reiserfs/reiserfs_fs.h>
+
+static vop_access_t reiserfs_access;
+static vop_bmap_t reiserfs_bmap;
+static vop_getattr_t reiserfs_getattr;
+static vop_open_t reiserfs_open;
+static vop_pathconf_t reiserfs_pathconf;
+static vop_readlink_t reiserfs_readlink;
+static vop_strategy_t reiserfs_strategy;
+
+/* Global vfs data structures for ReiserFS */
+struct vop_vector reiserfs_vnodeops = {
+ .vop_default = &default_vnodeops,
+
+ .vop_access = reiserfs_access,
+ .vop_bmap = reiserfs_bmap,
+ .vop_cachedlookup = reiserfs_lookup,
+ .vop_getattr = reiserfs_getattr,
+ .vop_inactive = reiserfs_inactive,
+ .vop_lookup = vfs_cache_lookup,
+ .vop_open = reiserfs_open,
+ .vop_reclaim = reiserfs_reclaim,
+ .vop_read = reiserfs_read,
+ .vop_readdir = reiserfs_readdir,
+ .vop_readlink = reiserfs_readlink,
+ .vop_pathconf = reiserfs_pathconf,
+ .vop_strategy = reiserfs_strategy,
+};
+
+struct vop_vector reiserfs_specops = {
+ .vop_default = &default_vnodeops,
+
+ .vop_access = reiserfs_access,
+ .vop_getattr = reiserfs_getattr,
+ .vop_inactive = reiserfs_inactive,
+ .vop_reclaim = reiserfs_reclaim,
+};
+
+/* -------------------------------------------------------------------
+ * vnode operations
+ * -------------------------------------------------------------------*/
+
+static int
+reiserfs_access(struct vop_access_args *ap)
+{
+ int error;
+ struct vnode *vp = ap->a_vp;
+ struct reiserfs_node *ip = VTOI(vp);
+ mode_t mode = ap->a_mode;
+
+ /*
+ * Disallow write attempts on read-only file systems; unless the file
+ * is a socket, fifo, or a block or character device resident on the
+ * file system.
+ */
+ if (mode & VWRITE) {
+ switch (vp->v_type) {
+ case VDIR:
+ case VLNK:
+ case VREG:
+ if (vp->v_mount->mnt_flag & MNT_RDONLY) {
+ reiserfs_log(LOG_DEBUG,
+ "no write access (read-only fs)\n");
+ return (EROFS);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* If immutable bit set, nobody gets to write it. */
+ if ((mode & VWRITE) && (ip->i_flags & (IMMUTABLE | SF_SNAPSHOT))) {
+ reiserfs_log(LOG_DEBUG, "no write access (immutable)\n");
+ return (EPERM);
+ }
+
+ error = vaccess(vp->v_type, ip->i_mode, ip->i_uid, ip->i_gid,
+ ap->a_mode, ap->a_cred, NULL);
+ return (error);
+}
+
+static int
+reiserfs_getattr(struct vop_getattr_args *ap)
+{
+ struct vnode *vp = ap->a_vp;
+ struct vattr *vap = ap->a_vap;
+ struct reiserfs_node *ip = VTOI(vp);
+
+ vap->va_fsid = dev2udev(ip->i_dev);
+ vap->va_fileid = ip->i_number;
+ vap->va_mode = ip->i_mode & ~S_IFMT;
+ vap->va_nlink = ip->i_nlink;
+ vap->va_uid = ip->i_uid;
+ vap->va_gid = ip->i_gid;
+ //XXX vap->va_rdev = ip->i_rdev;
+ vap->va_size = ip->i_size;
+ vap->va_atime = ip->i_atime;
+ vap->va_mtime = ip->i_mtime;
+ vap->va_ctime = ip->i_ctime;
+ vap->va_flags = ip->i_flags;
+ vap->va_gen = ip->i_generation;
+ vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize;
+ vap->va_bytes = dbtob((u_quad_t)ip->i_blocks);
+ vap->va_type = vp->v_type;
+ //XXX vap->va_filerev = ip->i_modrev;
+
+ return (0);
+}
+
+/* Return POSIX pathconf information applicable to ReiserFS filesystems */
+static int
+reiserfs_pathconf(struct vop_pathconf_args *ap)
+{
+ switch (ap->a_name) {
+ case _PC_LINK_MAX:
+ *ap->a_retval = REISERFS_LINK_MAX;
+ return (0);
+ case _PC_NAME_MAX:
+ *ap->a_retval =
+ REISERFS_MAX_NAME(VTOI(ap->a_vp)->i_reiserfs->s_blocksize);
+ return (0);
+ case _PC_PATH_MAX:
+ *ap->a_retval = PATH_MAX;
+ return (0);
+ case _PC_PIPE_BUF:
+ *ap->a_retval = PIPE_BUF;
+ return (0);
+ case _PC_CHOWN_RESTRICTED:
+ *ap->a_retval = 1;
+ return (0);
+ case _PC_NO_TRUNC:
+ *ap->a_retval = 1;
+ return (0);
+ default:
+ return (EINVAL);
+ }
+}
+
+static int
+reiserfs_open(struct vop_open_args *ap)
+{
+ /* Files marked append-only must be opened for appending. */
+ if ((VTOI(ap->a_vp)->i_flags & APPEND) &&
+ (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE)
+ return (EPERM);
+
+ vnode_create_vobject(ap->a_vp, VTOI(ap->a_vp)->i_size, ap->a_td);
+
+ return (0);
+}
+
+/* Return target name of a symbolic link */
+static int
+reiserfs_readlink(struct vop_readlink_args *ap)
+{
+ struct vnode *vp = ap->a_vp;
+
+ reiserfs_log(LOG_DEBUG, "redirect to VOP_READ()\n");
+ return (VOP_READ(vp, ap->a_uio, 0, ap->a_cred));
+}
+
+/* Bmap converts the logical block number of a file to its physical
+ * block number on the disk. */
+static int
+reiserfs_bmap(ap)
+ struct vop_bmap_args /* {
+ struct vnode *a_vp;
+ daddr_t a_bn;
+ struct bufobj **a_bop;
+ daddr_t *a_bnp;
+ int *a_runp;
+ int *a_runb;
+ } */ *ap;
+{
+ daddr_t blkno;
+ struct buf *bp;
+ struct cpu_key key;
+ struct item_head *ih;
+
+ struct vnode *vp = ap->a_vp;
+ struct reiserfs_node *ip = VTOI(vp);
+ struct reiserfs_sb_info *sbi = ip->i_reiserfs;
+ INITIALIZE_PATH(path);
+
+ /* Prepare the key to look for the 'block'-th block of file
+ * (XXX we suppose that statfs.f_iosize == sbi->s_blocksize) */
+ make_cpu_key(&key, ip, (off_t)ap->a_bn * sbi->s_blocksize + 1,
+ TYPE_ANY, 3);
+
+ /* Search item */
+ if (search_for_position_by_key(sbi, &key, &path) != POSITION_FOUND) {
+ reiserfs_log(LOG_DEBUG, "position not found\n");
+ pathrelse(&path);
+ return (ENOENT);
+ }
+
+ bp = get_last_bp(&path);
+ ih = get_ih(&path);
+
+ if (is_indirect_le_ih(ih)) {
+ /* Indirect item can be read by the underlying layer, instead of
+ * VOP_STRATEGY. */
+ int i;
+ uint32_t *ind_item = (uint32_t *)B_I_PITEM(bp, ih);
+ reiserfs_log(LOG_DEBUG, "found an INDIRECT item\n");
+ blkno = get_block_num(ind_item, path.pos_in_item);
+
+ /* Read-ahead */
+ if (ap->a_runb) {
+ uint32_t count = 0;
+ for (i = path.pos_in_item - 1; i >= 0; --i) {
+ if ((blkno - get_block_num(ind_item, i)) !=
+ count + 1)
+ break;
+ ++count;
+ }
+
+ /*
+ * This count isn't expressed in DEV_BSIZE base but
+ * in fs' own block base
+ * (see sys/vm/vnode_pager.c:vnode_pager_addr())
+ */
+ *ap->a_runb = count;
+ reiserfs_log(LOG_DEBUG,
+ " read-ahead: %d blocks before\n", *ap->a_runb);
+ }
+ if (ap->a_runp) {
+ uint32_t count = 0;
+ /*
+ * ih is an uint32_t array, that's why we use
+ * its length (in bytes) divided by 4 to know
+ * the number of items
+ */
+ for (i = path.pos_in_item + 1;
+ i < ih_item_len(ih) / 4; ++i) {
+ if ((get_block_num(ind_item, i) - blkno) !=
+ count + 1)
+ break;
+ ++count;
+ }
+
+ /*
+ * This count isn't expressed in DEV_BSIZE base but
+ * in fs' own block base
+ * (see sys/vm/vnode_pager.c:vnode_pager_addr()) */
+ *ap->a_runp = count;
+ reiserfs_log(LOG_DEBUG,
+ " read-ahead: %d blocks after\n", *ap->a_runp);
+ }
+
+ /* Indirect items can be read using the device VOP_STRATEGY */
+ if (ap->a_bop)
+ *ap->a_bop = &VTOI(ap->a_vp)->i_devvp->v_bufobj;
+
+ /* Convert the block number into DEV_BSIZE base */
+ blkno *= btodb(sbi->s_blocksize);
+ } else {
+ /*
+ * Direct item are not DEV_BSIZE aligned, VOP_STRATEGY will
+ * have to handle this case specifically
+ */
+ reiserfs_log(LOG_DEBUG, "found a DIRECT item\n");
+ blkno = ap->a_bn;
+
+ if (ap->a_runp)
+ *ap->a_runp = 0;
+ if (ap->a_runb)
+ *ap->a_runb = 0;
+
+ /* Direct item must be read by reiserfs_strategy */
+ if (ap->a_bop)
+ *ap->a_bop = &vp->v_bufobj;
+ }
+
+ if (ap->a_bnp)
+ *ap->a_bnp = blkno;
+
+ pathrelse(&path);
+
+ if (ap->a_bnp) {
+ reiserfs_log(LOG_DEBUG, "logical block: %ju (%ju),"
+ " physical block: %ju (%ju)\n",
+ (intmax_t)ap->a_bn,
+ (intmax_t)(ap->a_bn / btodb(sbi->s_blocksize)),
+ (intmax_t)*ap->a_bnp,
+ (intmax_t)(*ap->a_bnp / btodb(sbi->s_blocksize)));
+ }
+
+ return (0);
+}
+
+/* Does simply the same as reiserfs_read. It's called when reiserfs_bmap find
+ * an direct item. */
+static int
+reiserfs_strategy(struct vop_strategy_args /* {
+ struct vnode *a_vp;
+ struct buf *a_bp;
+ } */ *ap)
+{
+ int error;
+ struct uio auio;
+ struct iovec aiov;
+ struct reiserfs_node *ip;
+ struct buf *bp = ap->a_bp;
+ struct vnode *vp = ap->a_vp;
+
+ reiserfs_log(LOG_DEBUG, "logical block: %ju,"
+ " physical block: %ju\n", (intmax_t)bp->b_lblkno,
+ (intmax_t)bp->b_blkno);
+
+ ip = VTOI(vp);
+
+ if (bp->b_iocmd == BIO_READ) {
+ /* Prepare the uio structure */
+ reiserfs_log(LOG_DEBUG, "prepare uio structure\n");
+ aiov.iov_base = bp->b_data;
+ aiov.iov_len = MIN(bp->b_bcount, ip->i_size);
+ reiserfs_log(LOG_DEBUG, " vector length: %ju\n",
+ (intmax_t)aiov.iov_len);
+
+ auio.uio_iov = &aiov;
+ auio.uio_iovcnt = 1;
+ auio.uio_offset = 0;
+ auio.uio_rw = UIO_READ;
+ auio.uio_segflg = UIO_SYSSPACE;
+ auio.uio_td = curthread;
+ auio.uio_resid = bp->b_bcount;
+ reiserfs_log(LOG_DEBUG, " buffer length: %u\n",
+ auio.uio_resid);
+
+ reiserfs_log(LOG_DEBUG, "reading block #%ju\n",
+ (intmax_t)bp->b_blkno);
+ error = reiserfs_get_block(ip, bp->b_blkno, 0, &auio);
+ } else {
+ /* No write support yet */
+ error = (EOPNOTSUPP);
+ bp->b_error = error;
+ bp->b_ioflags |= BIO_ERROR;
+ }
+
+ bufdone(bp);
+ return (error);
+}