Import of ReiserFS filesystem support (currently limited to read-only on

i386). Source code is under the GNU GPL license.

Approved by:	mux (mentor)
This commit is contained in:
Jean-Sébastien Pédron 2005-05-24 12:24:45 +00:00
parent d92e260a4a
commit 60a698826d
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=146564
13 changed files with 6347 additions and 0 deletions

163
sys/gnu/reiserfs/README Normal file
View File

@ -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....

File diff suppressed because it is too large Load Diff

View File

@ -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 */

View File

@ -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 */

View File

@ -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/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);
}

View File

@ -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/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
}
}

View File

@ -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/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) */
};

View File

@ -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 */

View File

@ -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/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) */
}

View File

@ -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/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");
}
}

View File

@ -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/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);
}

File diff suppressed because it is too large Load Diff

View File

@ -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/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);
}