add idl4k kernel firmware version 1.13.0.105

This commit is contained in:
Jaroslav Kysela
2015-03-26 17:22:37 +01:00
parent 5194d2792e
commit e9070cdc77
31064 changed files with 12769984 additions and 0 deletions

View File

@@ -0,0 +1,86 @@
config REISERFS_FS
tristate "Reiserfs support"
select CRC32
help
Stores not just filenames but the files themselves in a balanced
tree. Uses journalling.
Balanced trees are more efficient than traditional file system
architectural foundations.
In general, ReiserFS is as fast as ext2, but is very efficient with
large directories and small files. Additional patches are needed
for NFS and quotas, please see <http://www.namesys.com/> for links.
It is more easily extended to have features currently found in
database and keyword search systems than block allocation based file
systems are. The next version will be so extended, and will support
plugins consistent with our motto ``It takes more than a license to
make source code open.''
Read <http://www.namesys.com/> to learn more about reiserfs.
Sponsored by Threshold Networks, Emusic.com, and Bigstorage.com.
If you like it, you can pay us to add new features to it that you
need, buy a support contract, or pay us to port it to another OS.
config REISERFS_CHECK
bool "Enable reiserfs debug mode"
depends on REISERFS_FS
help
If you set this to Y, then ReiserFS will perform every check it can
possibly imagine of its internal consistency throughout its
operation. It will also go substantially slower. More than once we
have forgotten that this was on, and then gone despondent over the
latest benchmarks.:-) Use of this option allows our team to go all
out in checking for consistency when debugging without fear of its
effect on end users. If you are on the verge of sending in a bug
report, say Y and you might get a useful error message. Almost
everyone should say N.
config REISERFS_PROC_INFO
bool "Stats in /proc/fs/reiserfs"
depends on REISERFS_FS && PROC_FS
help
Create under /proc/fs/reiserfs a hierarchy of files, displaying
various ReiserFS statistics and internal data at the expense of
making your kernel or module slightly larger (+8 KB). This also
increases the amount of kernel memory required for each mount.
Almost everyone but ReiserFS developers and people fine-tuning
reiserfs or tracing problems should say N.
config REISERFS_FS_XATTR
bool "ReiserFS extended attributes"
depends on REISERFS_FS
help
Extended attributes are name:value pairs associated with inodes by
the kernel or by users (see the attr(5) manual page, or visit
<http://acl.bestbits.at/> for details).
If unsure, say N.
config REISERFS_FS_POSIX_ACL
bool "ReiserFS POSIX Access Control Lists"
depends on REISERFS_FS_XATTR
select FS_POSIX_ACL
help
Posix Access Control Lists (ACLs) support permissions for users and
groups beyond the owner/group/world scheme.
To learn more about Access Control Lists, visit the Posix ACLs for
Linux website <http://acl.bestbits.at/>.
If you don't know what Access Control Lists are, say N
config REISERFS_FS_SECURITY
bool "ReiserFS Security Labels"
depends on REISERFS_FS_XATTR
help
Security labels support alternative access control models
implemented by security modules like SELinux. This option
enables an extended attribute handler for file security
labels in the ReiserFS filesystem.
If you are not using a security module that requires using
extended attributes for file security labels, say N.

View File

@@ -0,0 +1,36 @@
#
# Makefile for the linux reiser-filesystem routines.
#
obj-$(CONFIG_REISERFS_FS) += reiserfs.o
reiserfs-objs := bitmap.o do_balan.o namei.o inode.o file.o dir.o fix_node.o \
super.o prints.o objectid.o lbalance.o ibalance.o stree.o \
hashes.o tail_conversion.o journal.o resize.o \
item_ops.o ioctl.o procfs.o xattr.o
ifeq ($(CONFIG_REISERFS_FS_XATTR),y)
reiserfs-objs += xattr_user.o xattr_trusted.o
endif
ifeq ($(CONFIG_REISERFS_FS_SECURITY),y)
reiserfs-objs += xattr_security.o
endif
ifeq ($(CONFIG_REISERFS_FS_POSIX_ACL),y)
reiserfs-objs += xattr_acl.o
endif
# gcc -O2 (the kernel default) is overaggressive on ppc32 when many inline
# functions are used. This causes the compiler to advance the stack
# pointer out of the available stack space, corrupting kernel space,
# and causing a panic. Since this behavior only affects ppc32, this ifeq
# will work around it. If any other architecture displays this behavior,
# add it here.
ifeq ($(CONFIG_PPC32),y)
EXTRA_CFLAGS := $(call cc-ifversion, -lt, 0400, -O1)
endif
TAGS:
etags *.c

161
kernel/fs/reiserfs/README Normal file
View File

@@ -0,0 +1,161 @@
[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....

1293
kernel/fs/reiserfs/bitmap.c Normal file

File diff suppressed because it is too large Load Diff

302
kernel/fs/reiserfs/dir.c Normal file
View File

@@ -0,0 +1,302 @@
/*
* Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
*/
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/reiserfs_fs.h>
#include <linux/stat.h>
#include <linux/buffer_head.h>
#include <asm/uaccess.h>
extern const struct reiserfs_key MIN_KEY;
static int reiserfs_readdir(struct file *, void *, filldir_t);
static int reiserfs_dir_fsync(struct file *filp, struct dentry *dentry,
int datasync);
const struct file_operations reiserfs_dir_operations = {
.read = generic_read_dir,
.readdir = reiserfs_readdir,
.fsync = reiserfs_dir_fsync,
.ioctl = reiserfs_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = reiserfs_compat_ioctl,
#endif
};
static int reiserfs_dir_fsync(struct file *filp, struct dentry *dentry,
int datasync)
{
struct inode *inode = dentry->d_inode;
int err;
reiserfs_write_lock(inode->i_sb);
err = reiserfs_commit_for_inode(inode);
reiserfs_write_unlock(inode->i_sb);
if (err < 0)
return err;
return 0;
}
#define store_ih(where,what) copy_item_head (where, what)
static inline bool is_privroot_deh(struct dentry *dir,
struct reiserfs_de_head *deh)
{
struct dentry *privroot = REISERFS_SB(dir->d_sb)->priv_root;
return (dir == dir->d_parent && privroot->d_inode &&
deh->deh_objectid == INODE_PKEY(privroot->d_inode)->k_objectid);
}
int reiserfs_readdir_dentry(struct dentry *dentry, void *dirent,
filldir_t filldir, loff_t *pos)
{
struct inode *inode = dentry->d_inode;
struct cpu_key pos_key; /* key of current position in the directory (key of directory entry) */
INITIALIZE_PATH(path_to_entry);
struct buffer_head *bh;
int item_num, entry_num;
const struct reiserfs_key *rkey;
struct item_head *ih, tmp_ih;
int search_res;
char *local_buf;
loff_t next_pos;
char small_buf[32]; /* avoid kmalloc if we can */
struct reiserfs_dir_entry de;
int ret = 0;
reiserfs_write_lock(inode->i_sb);
reiserfs_check_lock_depth(inode->i_sb, "readdir");
/* form key for search the next directory entry using f_pos field of
file structure */
make_cpu_key(&pos_key, inode, *pos ?: DOT_OFFSET, TYPE_DIRENTRY, 3);
next_pos = cpu_key_k_offset(&pos_key);
path_to_entry.reada = PATH_READA;
while (1) {
research:
/* search the directory item, containing entry with specified key */
search_res =
search_by_entry_key(inode->i_sb, &pos_key, &path_to_entry,
&de);
if (search_res == IO_ERROR) {
// FIXME: we could just skip part of directory which could
// not be read
ret = -EIO;
goto out;
}
entry_num = de.de_entry_num;
bh = de.de_bh;
item_num = de.de_item_num;
ih = de.de_ih;
store_ih(&tmp_ih, ih);
/* we must have found item, that is item of this directory, */
RFALSE(COMP_SHORT_KEYS(&(ih->ih_key), &pos_key),
"vs-9000: found item %h does not match to dir we readdir %K",
ih, &pos_key);
RFALSE(item_num > B_NR_ITEMS(bh) - 1,
"vs-9005 item_num == %d, item amount == %d",
item_num, B_NR_ITEMS(bh));
/* and entry must be not more than number of entries in the item */
RFALSE(I_ENTRY_COUNT(ih) < entry_num,
"vs-9010: entry number is too big %d (%d)",
entry_num, I_ENTRY_COUNT(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(bh, ih) + entry_num;
for (; entry_num < I_ENTRY_COUNT(ih);
entry_num++, deh++) {
int d_reclen;
char *d_name;
off_t d_off;
ino_t d_ino;
if (!de_visible(deh))
/* it is hidden entry */
continue;
d_reclen = entry_length(bh, ih, entry_num);
d_name = B_I_DEH_ENTRY_FILE_NAME(bh, ih, deh);
if (d_reclen <= 0 ||
d_name + d_reclen > bh->b_data + bh->b_size) {
/* There is corrupted data in entry,
* We'd better stop here */
pathrelse(&path_to_entry);
ret = -EIO;
goto out;
}
if (!d_name[d_reclen - 1])
d_reclen = strlen(d_name);
if (d_reclen >
REISERFS_MAX_NAME(inode->i_sb->
s_blocksize)) {
/* too big to send back to VFS */
continue;
}
/* Ignore the .reiserfs_priv entry */
if (is_privroot_deh(dentry, deh))
continue;
d_off = deh_offset(deh);
*pos = d_off;
d_ino = deh_objectid(deh);
if (d_reclen <= 32) {
local_buf = small_buf;
} else {
local_buf = kmalloc(d_reclen,
GFP_NOFS);
if (!local_buf) {
pathrelse(&path_to_entry);
ret = -ENOMEM;
goto out;
}
if (item_moved(&tmp_ih, &path_to_entry)) {
kfree(local_buf);
goto research;
}
}
// Note, that we copy name to user space via temporary
// buffer (local_buf) because filldir will block if
// user space buffer is swapped out. At that time
// entry can move to somewhere else
memcpy(local_buf, d_name, d_reclen);
if (filldir
(dirent, local_buf, d_reclen, d_off, d_ino,
DT_UNKNOWN) < 0) {
if (local_buf != small_buf) {
kfree(local_buf);
}
goto end;
}
if (local_buf != small_buf) {
kfree(local_buf);
}
// next entry should be looked for with such offset
next_pos = deh_offset(deh) + 1;
if (item_moved(&tmp_ih, &path_to_entry)) {
goto research;
}
} /* for */
}
if (item_num != B_NR_ITEMS(bh) - 1)
// end of directory has been reached
goto end;
/* item we went through is last item of node. Using right
delimiting key check is it directory end */
rkey = get_rkey(&path_to_entry, inode->i_sb);
if (!comp_le_keys(rkey, &MIN_KEY)) {
/* set pos_key to key, that is the smallest and greater
that key of the last entry in the item */
set_cpu_key_k_offset(&pos_key, next_pos);
continue;
}
if (COMP_SHORT_KEYS(rkey, &pos_key)) {
// end of directory has been reached
goto end;
}
/* directory continues in the right neighboring block */
set_cpu_key_k_offset(&pos_key,
le_key_k_offset(KEY_FORMAT_3_5, rkey));
} /* while */
end:
*pos = next_pos;
pathrelse(&path_to_entry);
reiserfs_check_path(&path_to_entry);
out:
reiserfs_write_unlock(inode->i_sb);
return ret;
}
static int reiserfs_readdir(struct file *file, void *dirent, filldir_t filldir)
{
struct dentry *dentry = file->f_path.dentry;
return reiserfs_readdir_dentry(dentry, dirent, filldir, &file->f_pos);
}
/* compose directory item containing "." and ".." entries (entries are
not aligned to 4 byte boundary) */
/* the last four params are LE */
void make_empty_dir_item_v1(char *body, __le32 dirid, __le32 objid,
__le32 par_dirid, __le32 par_objid)
{
struct reiserfs_de_head *deh;
memset(body, 0, EMPTY_DIR_SIZE_V1);
deh = (struct reiserfs_de_head *)body;
/* direntry header of "." */
put_deh_offset(&(deh[0]), DOT_OFFSET);
/* these two are from make_le_item_head, and are are LE */
deh[0].deh_dir_id = dirid;
deh[0].deh_objectid = objid;
deh[0].deh_state = 0; /* Endian safe if 0 */
put_deh_location(&(deh[0]), EMPTY_DIR_SIZE_V1 - strlen("."));
mark_de_visible(&(deh[0]));
/* direntry header of ".." */
put_deh_offset(&(deh[1]), DOT_DOT_OFFSET);
/* key of ".." for the root directory */
/* these two are from the inode, and are are LE */
deh[1].deh_dir_id = par_dirid;
deh[1].deh_objectid = par_objid;
deh[1].deh_state = 0; /* Endian safe if 0 */
put_deh_location(&(deh[1]), deh_location(&(deh[0])) - strlen(".."));
mark_de_visible(&(deh[1]));
/* copy ".." and "." */
memcpy(body + deh_location(&(deh[0])), ".", 1);
memcpy(body + deh_location(&(deh[1])), "..", 2);
}
/* compose directory item containing "." and ".." entries */
void make_empty_dir_item(char *body, __le32 dirid, __le32 objid,
__le32 par_dirid, __le32 par_objid)
{
struct reiserfs_de_head *deh;
memset(body, 0, EMPTY_DIR_SIZE);
deh = (struct reiserfs_de_head *)body;
/* direntry header of "." */
put_deh_offset(&(deh[0]), DOT_OFFSET);
/* these two are from make_le_item_head, and are are LE */
deh[0].deh_dir_id = dirid;
deh[0].deh_objectid = objid;
deh[0].deh_state = 0; /* Endian safe if 0 */
put_deh_location(&(deh[0]), EMPTY_DIR_SIZE - ROUND_UP(strlen(".")));
mark_de_visible(&(deh[0]));
/* direntry header of ".." */
put_deh_offset(&(deh[1]), DOT_DOT_OFFSET);
/* key of ".." for the root directory */
/* these two are from the inode, and are are LE */
deh[1].deh_dir_id = par_dirid;
deh[1].deh_objectid = par_objid;
deh[1].deh_state = 0; /* Endian safe if 0 */
put_deh_location(&(deh[1]),
deh_location(&(deh[0])) - ROUND_UP(strlen("..")));
mark_de_visible(&(deh[1]));
/* copy ".." and "." */
memcpy(body + deh_location(&(deh[0])), ".", 1);
memcpy(body + deh_location(&(deh[1])), "..", 2);
}

File diff suppressed because it is too large Load Diff

310
kernel/fs/reiserfs/file.c Normal file
View File

@@ -0,0 +1,310 @@
/*
* Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
*/
#include <linux/time.h>
#include <linux/reiserfs_fs.h>
#include <linux/reiserfs_acl.h>
#include <linux/reiserfs_xattr.h>
#include <asm/uaccess.h>
#include <linux/pagemap.h>
#include <linux/swap.h>
#include <linux/writeback.h>
#include <linux/blkdev.h>
#include <linux/buffer_head.h>
#include <linux/quotaops.h>
/*
** We pack the tails of files on file close, not at the time they are written.
** This implies an unnecessary copy of the tail and an unnecessary indirect item
** insertion/balancing, for files that are written in one write.
** It avoids unnecessary tail packings (balances) for files that are written in
** multiple writes and are small enough to have tails.
**
** file_release is called by the VFS layer when the file is closed. If
** this is the last open file descriptor, and the file
** small enough to have a tail, and the tail is currently in an
** unformatted node, the tail is converted back into a direct item.
**
** We use reiserfs_truncate_file to pack the tail, since it already has
** all the conditions coded.
*/
static int reiserfs_file_release(struct inode *inode, struct file *filp)
{
struct reiserfs_transaction_handle th;
int err;
int jbegin_failure = 0;
BUG_ON(!S_ISREG(inode->i_mode));
/* fast out for when nothing needs to be done */
if ((atomic_read(&inode->i_count) > 1 ||
!(REISERFS_I(inode)->i_flags & i_pack_on_close_mask) ||
!tail_has_to_be_packed(inode)) &&
REISERFS_I(inode)->i_prealloc_count <= 0) {
return 0;
}
mutex_lock(&inode->i_mutex);
mutex_lock(&(REISERFS_I(inode)->i_mmap));
if (REISERFS_I(inode)->i_flags & i_ever_mapped)
REISERFS_I(inode)->i_flags &= ~i_pack_on_close_mask;
reiserfs_write_lock(inode->i_sb);
/* freeing preallocation only involves relogging blocks that
* are already in the current transaction. preallocation gets
* freed at the end of each transaction, so it is impossible for
* us to log any additional blocks (including quota blocks)
*/
err = journal_begin(&th, inode->i_sb, 1);
if (err) {
/* uh oh, we can't allow the inode to go away while there
* is still preallocation blocks pending. Try to join the
* aborted transaction
*/
jbegin_failure = err;
err = journal_join_abort(&th, inode->i_sb, 1);
if (err) {
/* hmpf, our choices here aren't good. We can pin the inode
* which will disallow unmount from every happening, we can
* do nothing, which will corrupt random memory on unmount,
* or we can forcibly remove the file from the preallocation
* list, which will leak blocks on disk. Lets pin the inode
* and let the admin know what is going on.
*/
igrab(inode);
reiserfs_warning(inode->i_sb, "clm-9001",
"pinning inode %lu because the "
"preallocation can't be freed",
inode->i_ino);
goto out;
}
}
reiserfs_update_inode_transaction(inode);
#ifdef REISERFS_PREALLOCATE
reiserfs_discard_prealloc(&th, inode);
#endif
err = journal_end(&th, inode->i_sb, 1);
/* copy back the error code from journal_begin */
if (!err)
err = jbegin_failure;
if (!err && atomic_read(&inode->i_count) <= 1 &&
(REISERFS_I(inode)->i_flags & i_pack_on_close_mask) &&
tail_has_to_be_packed(inode)) {
/* if regular file is released by last holder and it has been
appended (we append by unformatted node only) or its direct
item(s) had to be converted, then it may have to be
indirect2direct converted */
err = reiserfs_truncate_file(inode, 0);
}
out:
mutex_unlock(&(REISERFS_I(inode)->i_mmap));
mutex_unlock(&inode->i_mutex);
reiserfs_write_unlock(inode->i_sb);
return err;
}
static int reiserfs_file_mmap(struct file *file, struct vm_area_struct *vma)
{
struct inode *inode;
inode = file->f_path.dentry->d_inode;
mutex_lock(&(REISERFS_I(inode)->i_mmap));
REISERFS_I(inode)->i_flags |= i_ever_mapped;
mutex_unlock(&(REISERFS_I(inode)->i_mmap));
return generic_file_mmap(file, vma);
}
static void reiserfs_vfs_truncate_file(struct inode *inode)
{
reiserfs_truncate_file(inode, 1);
}
/* Sync a reiserfs file. */
/*
* FIXME: sync_mapping_buffers() never has anything to sync. Can
* be removed...
*/
static int reiserfs_sync_file(struct file *filp,
struct dentry *dentry, int datasync)
{
struct inode *inode = dentry->d_inode;
int err;
int barrier_done;
BUG_ON(!S_ISREG(inode->i_mode));
err = sync_mapping_buffers(inode->i_mapping);
reiserfs_write_lock(inode->i_sb);
barrier_done = reiserfs_commit_for_inode(inode);
reiserfs_write_unlock(inode->i_sb);
if (barrier_done != 1 && reiserfs_barrier_flush(inode->i_sb))
blkdev_issue_flush(inode->i_sb->s_bdev, NULL);
if (barrier_done < 0)
return barrier_done;
return (err < 0) ? -EIO : 0;
}
/* taken fs/buffer.c:__block_commit_write */
int reiserfs_commit_page(struct inode *inode, struct page *page,
unsigned from, unsigned to)
{
unsigned block_start, block_end;
int partial = 0;
unsigned blocksize;
struct buffer_head *bh, *head;
unsigned long i_size_index = inode->i_size >> PAGE_CACHE_SHIFT;
int new;
int logit = reiserfs_file_data_log(inode);
struct super_block *s = inode->i_sb;
int bh_per_page = PAGE_CACHE_SIZE / s->s_blocksize;
struct reiserfs_transaction_handle th;
int ret = 0;
th.t_trans_id = 0;
blocksize = 1 << inode->i_blkbits;
if (logit) {
reiserfs_write_lock(s);
ret = journal_begin(&th, s, bh_per_page + 1);
if (ret)
goto drop_write_lock;
reiserfs_update_inode_transaction(inode);
}
for (bh = head = page_buffers(page), block_start = 0;
bh != head || !block_start;
block_start = block_end, bh = bh->b_this_page) {
new = buffer_new(bh);
clear_buffer_new(bh);
block_end = block_start + blocksize;
if (block_end <= from || block_start >= to) {
if (!buffer_uptodate(bh))
partial = 1;
} else {
set_buffer_uptodate(bh);
if (logit) {
reiserfs_prepare_for_journal(s, bh, 1);
journal_mark_dirty(&th, s, bh);
} else if (!buffer_dirty(bh)) {
mark_buffer_dirty(bh);
/* do data=ordered on any page past the end
* of file and any buffer marked BH_New.
*/
if (reiserfs_data_ordered(inode->i_sb) &&
(new || page->index >= i_size_index)) {
reiserfs_add_ordered_list(inode, bh);
}
}
}
}
if (logit) {
ret = journal_end(&th, s, bh_per_page + 1);
drop_write_lock:
reiserfs_write_unlock(s);
}
/*
* If this is a partial write which happened to make all buffers
* uptodate then we can optimize away a bogus readpage() for
* the next read(). Here we 'discover' whether the page went
* uptodate as a result of this (potentially partial) write.
*/
if (!partial)
SetPageUptodate(page);
return ret;
}
/* Write @count bytes at position @ppos in a file indicated by @file
from the buffer @buf.
generic_file_write() is only appropriate for filesystems that are not seeking to optimize performance and want
something simple that works. It is not for serious use by general purpose filesystems, excepting the one that it was
written for (ext2/3). This is for several reasons:
* It has no understanding of any filesystem specific optimizations.
* It enters the filesystem repeatedly for each page that is written.
* It depends on reiserfs_get_block() function which if implemented by reiserfs performs costly search_by_key
* operation for each page it is supplied with. By contrast reiserfs_file_write() feeds as much as possible at a time
* to reiserfs which allows for fewer tree traversals.
* Each indirect pointer insertion takes a lot of cpu, because it involves memory moves inside of blocks.
* Asking the block allocation code for blocks one at a time is slightly less efficient.
All of these reasons for not using only generic file write were understood back when reiserfs was first miscoded to
use it, but we were in a hurry to make code freeze, and so it couldn't be revised then. This new code should make
things right finally.
Future Features: providing search_by_key with hints.
*/
static ssize_t reiserfs_file_write(struct file *file, /* the file we are going to write into */
const char __user * buf, /* pointer to user supplied data
(in userspace) */
size_t count, /* amount of bytes to write */
loff_t * ppos /* pointer to position in file that we start writing at. Should be updated to
* new current position before returning. */
)
{
struct inode *inode = file->f_path.dentry->d_inode; // Inode of the file that we are writing to.
/* To simplify coding at this time, we store
locked pages in array for now */
struct reiserfs_transaction_handle th;
th.t_trans_id = 0;
/* If a filesystem is converted from 3.5 to 3.6, we'll have v3.5 items
* lying around (most of the disk, in fact). Despite the filesystem
* now being a v3.6 format, the old items still can't support large
* file sizes. Catch this case here, as the rest of the VFS layer is
* oblivious to the different limitations between old and new items.
* reiserfs_setattr catches this for truncates. This chunk is lifted
* from generic_write_checks. */
if (get_inode_item_key_version (inode) == KEY_FORMAT_3_5 &&
*ppos + count > MAX_NON_LFS) {
if (*ppos >= MAX_NON_LFS) {
return -EFBIG;
}
if (count > MAX_NON_LFS - (unsigned long)*ppos)
count = MAX_NON_LFS - (unsigned long)*ppos;
}
return do_sync_write(file, buf, count, ppos);
}
const struct file_operations reiserfs_file_operations = {
.read = do_sync_read,
.write = reiserfs_file_write,
.ioctl = reiserfs_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = reiserfs_compat_ioctl,
#endif
.mmap = reiserfs_file_mmap,
.open = generic_file_open,
.release = reiserfs_file_release,
.fsync = reiserfs_sync_file,
.aio_read = generic_file_aio_read,
.aio_write = generic_file_aio_write,
.splice_read = generic_file_splice_read,
.splice_write = generic_file_splice_write,
.llseek = generic_file_llseek,
};
const struct inode_operations reiserfs_file_inode_operations = {
.truncate = reiserfs_vfs_truncate_file,
.setattr = reiserfs_setattr,
.setxattr = reiserfs_setxattr,
.getxattr = reiserfs_getxattr,
.listxattr = reiserfs_listxattr,
.removexattr = reiserfs_removexattr,
.permission = reiserfs_permission,
};

File diff suppressed because it is too large Load Diff

182
kernel/fs/reiserfs/hashes.c Normal file
View File

@@ -0,0 +1,182 @@
/*
* 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 reiserfs/README. -Hans
* Yura's function is added (04/07/2000)
*/
//
// keyed_hash
// yura_hash
// r5_hash
//
#include <linux/kernel.h>
#include <linux/reiserfs_fs.h>
#include <asm/types.h>
#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 { \
u32 sum = 0; \
int n = rounds; \
u32 b0, b1; \
\
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)
u32 keyed_hash(const signed char *msg, int len)
{
u32 k[] = { 0x9464a485, 0x542e1a94, 0x3e846bff, 0xb75bcfc3 };
u32 h0 = k[0], h1 = k[1];
u32 a, b, c, d;
u32 pad;
int i;
// assert(len >= 0 && len < 256);
pad = (u32) len | ((u32) len << 8);
pad |= pad << 16;
while (len >= 16) {
a = (u32) msg[0] |
(u32) msg[1] << 8 | (u32) msg[2] << 16 | (u32) msg[3] << 24;
b = (u32) msg[4] |
(u32) msg[5] << 8 | (u32) msg[6] << 16 | (u32) msg[7] << 24;
c = (u32) msg[8] |
(u32) msg[9] << 8 |
(u32) msg[10] << 16 | (u32) msg[11] << 24;
d = (u32) msg[12] |
(u32) msg[13] << 8 |
(u32) msg[14] << 16 | (u32) msg[15] << 24;
TEACORE(PARTROUNDS);
len -= 16;
msg += 16;
}
if (len >= 12) {
a = (u32) msg[0] |
(u32) msg[1] << 8 | (u32) msg[2] << 16 | (u32) msg[3] << 24;
b = (u32) msg[4] |
(u32) msg[5] << 8 | (u32) msg[6] << 16 | (u32) msg[7] << 24;
c = (u32) msg[8] |
(u32) msg[9] << 8 |
(u32) msg[10] << 16 | (u32) msg[11] << 24;
d = pad;
for (i = 12; i < len; i++) {
d <<= 8;
d |= msg[i];
}
} else if (len >= 8) {
a = (u32) msg[0] |
(u32) msg[1] << 8 | (u32) msg[2] << 16 | (u32) msg[3] << 24;
b = (u32) msg[4] |
(u32) msg[5] << 8 | (u32) msg[6] << 16 | (u32) msg[7] << 24;
c = d = pad;
for (i = 8; i < len; i++) {
c <<= 8;
c |= msg[i];
}
} else if (len >= 4) {
a = (u32) msg[0] |
(u32) msg[1] << 8 | (u32) msg[2] << 16 | (u32) 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 reiserfs/README */
u32 yura_hash(const signed char *msg, int len)
{
int j, pow;
u32 a, c;
int i;
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;
}
u32 r5_hash(const signed char *msg, int len)
{
u32 a = 0;
while (*msg) {
a += *msg << 4;
a += *msg >> 4;
a *= 11;
msg++;
}
return a;
}

File diff suppressed because it is too large Load Diff

3167
kernel/fs/reiserfs/inode.c Normal file

File diff suppressed because it is too large Load Diff

219
kernel/fs/reiserfs/ioctl.c Normal file
View File

@@ -0,0 +1,219 @@
/*
* Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
*/
#include <linux/capability.h>
#include <linux/fs.h>
#include <linux/mount.h>
#include <linux/reiserfs_fs.h>
#include <linux/time.h>
#include <asm/uaccess.h>
#include <linux/pagemap.h>
#include <linux/smp_lock.h>
#include <linux/compat.h>
/*
** reiserfs_ioctl - handler for ioctl for inode
** supported commands:
** 1) REISERFS_IOC_UNPACK - try to unpack tail from direct item into indirect
** and prevent packing file (argument arg has to be non-zero)
** 2) REISERFS_IOC_[GS]ETFLAGS, REISERFS_IOC_[GS]ETVERSION
** 3) That's all for a while ...
*/
int reiserfs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
unsigned long arg)
{
unsigned int flags;
int err = 0;
switch (cmd) {
case REISERFS_IOC_UNPACK:
if (S_ISREG(inode->i_mode)) {
if (arg)
return reiserfs_unpack(inode, filp);
else
return 0;
} else
return -ENOTTY;
/* following two cases are taken from fs/ext2/ioctl.c by Remy
Card (card@masi.ibp.fr) */
case REISERFS_IOC_GETFLAGS:
if (!reiserfs_attrs(inode->i_sb))
return -ENOTTY;
flags = REISERFS_I(inode)->i_attrs;
i_attrs_to_sd_attrs(inode, (__u16 *) & flags);
return put_user(flags, (int __user *)arg);
case REISERFS_IOC_SETFLAGS:{
if (!reiserfs_attrs(inode->i_sb))
return -ENOTTY;
err = mnt_want_write(filp->f_path.mnt);
if (err)
return err;
if (!is_owner_or_cap(inode)) {
err = -EPERM;
goto setflags_out;
}
if (get_user(flags, (int __user *)arg)) {
err = -EFAULT;
goto setflags_out;
}
/*
* Is it quota file? Do not allow user to mess with it
*/
if (IS_NOQUOTA(inode)) {
err = -EPERM;
goto setflags_out;
}
if (((flags ^ REISERFS_I(inode)->
i_attrs) & (REISERFS_IMMUTABLE_FL |
REISERFS_APPEND_FL))
&& !capable(CAP_LINUX_IMMUTABLE)) {
err = -EPERM;
goto setflags_out;
}
if ((flags & REISERFS_NOTAIL_FL) &&
S_ISREG(inode->i_mode)) {
int result;
result = reiserfs_unpack(inode, filp);
if (result) {
err = result;
goto setflags_out;
}
}
sd_attrs_to_i_attrs(flags, inode);
REISERFS_I(inode)->i_attrs = flags;
inode->i_ctime = CURRENT_TIME_SEC;
mark_inode_dirty(inode);
setflags_out:
mnt_drop_write(filp->f_path.mnt);
return err;
}
case REISERFS_IOC_GETVERSION:
return put_user(inode->i_generation, (int __user *)arg);
case REISERFS_IOC_SETVERSION:
if (!is_owner_or_cap(inode))
return -EPERM;
err = mnt_want_write(filp->f_path.mnt);
if (err)
return err;
if (get_user(inode->i_generation, (int __user *)arg)) {
err = -EFAULT;
goto setversion_out;
}
inode->i_ctime = CURRENT_TIME_SEC;
mark_inode_dirty(inode);
setversion_out:
mnt_drop_write(filp->f_path.mnt);
return err;
default:
return -ENOTTY;
}
}
#ifdef CONFIG_COMPAT
long reiserfs_compat_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
struct inode *inode = file->f_path.dentry->d_inode;
int ret;
/* These are just misnamed, they actually get/put from/to user an int */
switch (cmd) {
case REISERFS_IOC32_UNPACK:
cmd = REISERFS_IOC_UNPACK;
break;
case REISERFS_IOC32_GETFLAGS:
cmd = REISERFS_IOC_GETFLAGS;
break;
case REISERFS_IOC32_SETFLAGS:
cmd = REISERFS_IOC_SETFLAGS;
break;
case REISERFS_IOC32_GETVERSION:
cmd = REISERFS_IOC_GETVERSION;
break;
case REISERFS_IOC32_SETVERSION:
cmd = REISERFS_IOC_SETVERSION;
break;
default:
return -ENOIOCTLCMD;
}
lock_kernel();
ret = reiserfs_ioctl(inode, file, cmd, (unsigned long) compat_ptr(arg));
unlock_kernel();
return ret;
}
#endif
int reiserfs_commit_write(struct file *f, struct page *page,
unsigned from, unsigned to);
int reiserfs_prepare_write(struct file *f, struct page *page,
unsigned from, unsigned to);
/*
** reiserfs_unpack
** Function try to convert tail from direct item into indirect.
** It set up nopack attribute in the REISERFS_I(inode)->nopack
*/
int reiserfs_unpack(struct inode *inode, struct file *filp)
{
int retval = 0;
int index;
struct page *page;
struct address_space *mapping;
unsigned long write_from;
unsigned long blocksize = inode->i_sb->s_blocksize;
if (inode->i_size == 0) {
REISERFS_I(inode)->i_flags |= i_nopack_mask;
return 0;
}
/* ioctl already done */
if (REISERFS_I(inode)->i_flags & i_nopack_mask) {
return 0;
}
/* we need to make sure nobody is changing the file size beneath
** us
*/
mutex_lock(&inode->i_mutex);
reiserfs_write_lock(inode->i_sb);
write_from = inode->i_size & (blocksize - 1);
/* if we are on a block boundary, we are already unpacked. */
if (write_from == 0) {
REISERFS_I(inode)->i_flags |= i_nopack_mask;
goto out;
}
/* we unpack by finding the page with the tail, and calling
** reiserfs_prepare_write on that page. This will force a
** reiserfs_get_block to unpack the tail for us.
*/
index = inode->i_size >> PAGE_CACHE_SHIFT;
mapping = inode->i_mapping;
page = grab_cache_page(mapping, index);
retval = -ENOMEM;
if (!page) {
goto out;
}
retval = reiserfs_prepare_write(NULL, page, write_from, write_from);
if (retval)
goto out_unlock;
/* conversion can change page contents, must flush */
flush_dcache_page(page);
retval = reiserfs_commit_write(NULL, page, write_from, write_from);
REISERFS_I(inode)->i_flags |= i_nopack_mask;
out_unlock:
unlock_page(page);
page_cache_release(page);
out:
mutex_unlock(&inode->i_mutex);
reiserfs_write_unlock(inode->i_sb);
return retval;
}

View File

@@ -0,0 +1,756 @@
/*
* Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
*/
#include <linux/time.h>
#include <linux/reiserfs_fs.h>
// this contains item handlers for old item types: sd, direct,
// indirect, directory
/* and where are the comments? how about saying where we can find an
explanation of each item handler method? -Hans */
//////////////////////////////////////////////////////////////////////////////
// stat data functions
//
static int sd_bytes_number(struct item_head *ih, int block_size)
{
return 0;
}
static void sd_decrement_key(struct cpu_key *key)
{
key->on_disk_key.k_objectid--;
set_cpu_key_k_type(key, TYPE_ANY);
set_cpu_key_k_offset(key, (loff_t)(~0ULL >> 1));
}
static int sd_is_left_mergeable(struct reiserfs_key *key, unsigned long bsize)
{
return 0;
}
static char *print_time(time_t t)
{
static char timebuf[256];
sprintf(timebuf, "%ld", t);
return timebuf;
}
static void sd_print_item(struct item_head *ih, char *item)
{
printk("\tmode | size | nlinks | first direct | mtime\n");
if (stat_data_v1(ih)) {
struct stat_data_v1 *sd = (struct stat_data_v1 *)item;
printk("\t0%-6o | %6u | %2u | %d | %s\n", sd_v1_mode(sd),
sd_v1_size(sd), sd_v1_nlink(sd),
sd_v1_first_direct_byte(sd),
print_time(sd_v1_mtime(sd)));
} else {
struct stat_data *sd = (struct stat_data *)item;
printk("\t0%-6o | %6Lu | %2u | %d | %s\n", sd_v2_mode(sd),
(unsigned long long)sd_v2_size(sd), sd_v2_nlink(sd),
sd_v2_rdev(sd), print_time(sd_v2_mtime(sd)));
}
}
static void sd_check_item(struct item_head *ih, char *item)
{
// FIXME: type something here!
}
static int sd_create_vi(struct virtual_node *vn,
struct virtual_item *vi,
int is_affected, int insert_size)
{
vi->vi_index = TYPE_STAT_DATA;
//vi->vi_type |= VI_TYPE_STAT_DATA;// not needed?
return 0;
}
static int sd_check_left(struct virtual_item *vi, int free,
int start_skip, int end_skip)
{
BUG_ON(start_skip || end_skip);
return -1;
}
static int sd_check_right(struct virtual_item *vi, int free)
{
return -1;
}
static int sd_part_size(struct virtual_item *vi, int first, int count)
{
BUG_ON(count);
return 0;
}
static int sd_unit_num(struct virtual_item *vi)
{
return vi->vi_item_len - IH_SIZE;
}
static void sd_print_vi(struct virtual_item *vi)
{
reiserfs_warning(NULL, "reiserfs-16100",
"STATDATA, index %d, type 0x%x, %h",
vi->vi_index, vi->vi_type, vi->vi_ih);
}
static 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);
}
// FIXME: this should probably switch to indirect as well
static void direct_decrement_key(struct cpu_key *key)
{
cpu_key_k_offset_dec(key);
if (cpu_key_k_offset(key) == 0)
set_cpu_key_k_type(key, TYPE_STAT_DATA);
}
static int direct_is_left_mergeable(struct reiserfs_key *key,
unsigned long bsize)
{
int version = le_key_version(key);
return ((le_key_k_offset(version, key) & (bsize - 1)) != 1);
}
static void direct_print_item(struct item_head *ih, char *item)
{
int j = 0;
// return;
printk("\"");
while (j < ih_item_len(ih))
printk("%c", item[j++]);
printk("\"\n");
}
static void direct_check_item(struct item_head *ih, char *item)
{
// FIXME: type something here!
}
static int direct_create_vi(struct virtual_node *vn,
struct virtual_item *vi,
int is_affected, int insert_size)
{
vi->vi_index = TYPE_DIRECT;
//vi->vi_type |= VI_TYPE_DIRECT;
return 0;
}
static int direct_check_left(struct virtual_item *vi, int free,
int start_skip, int end_skip)
{
int bytes;
bytes = free - free % 8;
return bytes ? : -1;
}
static int direct_check_right(struct virtual_item *vi, int free)
{
return direct_check_left(vi, free, 0, 0);
}
static int direct_part_size(struct virtual_item *vi, int first, int count)
{
return count;
}
static int direct_unit_num(struct virtual_item *vi)
{
return vi->vi_item_len - IH_SIZE;
}
static void direct_print_vi(struct virtual_item *vi)
{
reiserfs_warning(NULL, "reiserfs-16101",
"DIRECT, index %d, type 0x%x, %h",
vi->vi_index, vi->vi_type, vi->vi_ih);
}
static 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; //- get_ih_free_space (ih);
}
// decrease offset, if it becomes 0, change type to stat data
static void indirect_decrement_key(struct cpu_key *key)
{
cpu_key_k_offset_dec(key);
if (cpu_key_k_offset(key) == 0)
set_cpu_key_k_type(key, TYPE_STAT_DATA);
}
// if it is not first item of the body, then it is mergeable
static int indirect_is_left_mergeable(struct reiserfs_key *key,
unsigned long bsize)
{
int version = le_key_version(key);
return (le_key_k_offset(version, key) != 1);
}
// printing of indirect item
static void start_new_sequence(__u32 * start, int *len, __u32 new)
{
*start = new;
*len = 1;
}
static int sequence_finished(__u32 start, int *len, __u32 new)
{
if (start == INT_MAX)
return 1;
if (start == 0 && new == 0) {
(*len)++;
return 0;
}
if (start != 0 && (start + *len) == new) {
(*len)++;
return 0;
}
return 1;
}
static void print_sequence(__u32 start, int len)
{
if (start == INT_MAX)
return;
if (len == 1)
printk(" %d", start);
else
printk(" %d(%d)", start, len);
}
static void indirect_print_item(struct item_head *ih, char *item)
{
int j;
__le32 *unp;
__u32 prev = INT_MAX;
int num = 0;
unp = (__le32 *) item;
if (ih_item_len(ih) % UNFM_P_SIZE)
reiserfs_warning(NULL, "reiserfs-16102", "invalid item len");
printk("%d pointers\n[ ", (int)I_UNFM_NUM(ih));
for (j = 0; j < I_UNFM_NUM(ih); j++) {
if (sequence_finished(prev, &num, get_block_num(unp, j))) {
print_sequence(prev, num);
start_new_sequence(&prev, &num, get_block_num(unp, j));
}
}
print_sequence(prev, num);
printk("]\n");
}
static void indirect_check_item(struct item_head *ih, char *item)
{
// FIXME: type something here!
}
static int indirect_create_vi(struct virtual_node *vn,
struct virtual_item *vi,
int is_affected, int insert_size)
{
vi->vi_index = TYPE_INDIRECT;
//vi->vi_type |= VI_TYPE_INDIRECT;
return 0;
}
static int indirect_check_left(struct virtual_item *vi, int free,
int start_skip, int end_skip)
{
int bytes;
bytes = free - free % UNFM_P_SIZE;
return bytes ? : -1;
}
static int indirect_check_right(struct virtual_item *vi, int free)
{
return indirect_check_left(vi, free, 0, 0);
}
// return size in bytes of 'units' units. If first == 0 - calculate from the head (left), otherwise - from tail (right)
static int indirect_part_size(struct virtual_item *vi, int first, int units)
{
// unit of indirect item is byte (yet)
return units;
}
static int indirect_unit_num(struct virtual_item *vi)
{
// unit of indirect item is byte (yet)
return vi->vi_item_len - IH_SIZE;
}
static void indirect_print_vi(struct virtual_item *vi)
{
reiserfs_warning(NULL, "reiserfs-16103",
"INDIRECT, index %d, type 0x%x, %h",
vi->vi_index, vi->vi_type, vi->vi_ih);
}
static 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_warning(NULL, "vs-16090",
"bytes number is asked for direntry");
return 0;
}
static void direntry_decrement_key(struct cpu_key *key)
{
cpu_key_k_offset_dec(key);
if (cpu_key_k_offset(key) == 0)
set_cpu_key_k_type(key, TYPE_STAT_DATA);
}
static int direntry_is_left_mergeable(struct reiserfs_key *key,
unsigned long bsize)
{
if (le32_to_cpu(key->u.k_offset_v1.k_offset) == DOT_OFFSET)
return 0;
return 1;
}
static void direntry_print_item(struct item_head *ih, char *item)
{
int i;
int namelen;
struct reiserfs_de_head *deh;
char *name;
static char namebuf[80];
printk("\n # %-15s%-30s%-15s%-15s%-15s\n", "Name",
"Key of pointed object", "Hash", "Gen number", "Status");
deh = (struct reiserfs_de_head *)item;
for (i = 0; i < I_ENTRY_COUNT(ih); i++, deh++) {
namelen =
(i ? (deh_location(deh - 1)) : ih_item_len(ih)) -
deh_location(deh);
name = item + deh_location(deh);
if (name[namelen - 1] == 0)
namelen = strlen(name);
namebuf[0] = '"';
if (namelen > sizeof(namebuf) - 3) {
strncpy(namebuf + 1, name, sizeof(namebuf) - 3);
namebuf[sizeof(namebuf) - 2] = '"';
namebuf[sizeof(namebuf) - 1] = 0;
} else {
memcpy(namebuf + 1, name, namelen);
namebuf[namelen + 1] = '"';
namebuf[namelen + 2] = 0;
}
printk("%d: %-15s%-15d%-15d%-15Ld%-15Ld(%s)\n",
i, namebuf,
deh_dir_id(deh), deh_objectid(deh),
GET_HASH_VALUE(deh_offset(deh)),
GET_GENERATION_NUMBER((deh_offset(deh))),
(de_hidden(deh)) ? "HIDDEN" : "VISIBLE");
}
}
static void direntry_check_item(struct item_head *ih, char *item)
{
int i;
struct reiserfs_de_head *deh;
// FIXME: type something here!
deh = (struct reiserfs_de_head *)item;
for (i = 0; i < I_ENTRY_COUNT(ih); i++, deh++) {
;
}
}
#define DIRENTRY_VI_FIRST_DIRENTRY_ITEM 1
/*
* function returns old entry number in directory item in real node
* using new entry number in virtual item in virtual node */
static inline int old_entry_num(int is_affected, int virtual_entry_num,
int pos_in_item, int mode)
{
if (mode == M_INSERT || mode == M_DELETE)
return virtual_entry_num;
if (!is_affected)
/* cut or paste is applied to another item */
return virtual_entry_num;
if (virtual_entry_num < pos_in_item)
return virtual_entry_num;
if (mode == M_CUT)
return virtual_entry_num + 1;
RFALSE(mode != M_PASTE || virtual_entry_num == 0,
"vs-8015: old_entry_num: mode must be M_PASTE (mode = \'%c\'",
mode);
return virtual_entry_num - 1;
}
/* Create an array of sizes of directory entries for virtual
item. Return space used by an item. FIXME: no control over
consuming of space used by this item handler */
static int direntry_create_vi(struct virtual_node *vn,
struct virtual_item *vi,
int is_affected, int insert_size)
{
struct direntry_uarea *dir_u = vi->vi_uarea;
int i, j;
int size = sizeof(struct direntry_uarea);
struct reiserfs_de_head *deh;
vi->vi_index = TYPE_DIRENTRY;
BUG_ON(!(vi->vi_ih) || !vi->vi_item);
dir_u->flags = 0;
if (le_ih_k_offset(vi->vi_ih) == DOT_OFFSET)
dir_u->flags |= DIRENTRY_VI_FIRST_DIRENTRY_ITEM;
deh = (struct reiserfs_de_head *)(vi->vi_item);
/* virtual directory item have this amount of entry after */
dir_u->entry_count = ih_entry_count(vi->vi_ih) +
((is_affected) ? ((vn->vn_mode == M_CUT) ? -1 :
(vn->vn_mode == M_PASTE ? 1 : 0)) : 0);
for (i = 0; i < dir_u->entry_count; i++) {
j = old_entry_num(is_affected, i, vn->vn_pos_in_item,
vn->vn_mode);
dir_u->entry_sizes[i] =
(j ? deh_location(&(deh[j - 1])) : ih_item_len(vi->vi_ih)) -
deh_location(&(deh[j])) + DEH_SIZE;
}
size += (dir_u->entry_count * sizeof(short));
/* set size of pasted entry */
if (is_affected && vn->vn_mode == M_PASTE)
dir_u->entry_sizes[vn->vn_pos_in_item] = insert_size;
#ifdef CONFIG_REISERFS_CHECK
/* compare total size of entries with item length */
{
int k, l;
l = 0;
for (k = 0; k < dir_u->entry_count; k++)
l += dir_u->entry_sizes[k];
if (l + IH_SIZE != vi->vi_item_len +
((is_affected
&& (vn->vn_mode == M_PASTE
|| vn->vn_mode == M_CUT)) ? insert_size : 0)) {
reiserfs_panic(NULL, "vs-8025", "(mode==%c, "
"insert_size==%d), invalid length of "
"directory item",
vn->vn_mode, insert_size);
}
}
#endif
return size;
}
//
// return number of entries which may fit into specified amount of
// free space, or -1 if free space is not enough even for 1 entry
//
static int direntry_check_left(struct virtual_item *vi, int free,
int start_skip, int end_skip)
{
int i;
int entries = 0;
struct direntry_uarea *dir_u = vi->vi_uarea;
for (i = start_skip; i < dir_u->entry_count - end_skip; i++) {
if (dir_u->entry_sizes[i] > free)
/* i-th entry doesn't fit into the remaining free space */
break;
free -= dir_u->entry_sizes[i];
entries++;
}
if (entries == dir_u->entry_count) {
reiserfs_panic(NULL, "item_ops-1",
"free space %d, entry_count %d", free,
dir_u->entry_count);
}
/* "." and ".." can not be separated from each other */
if (start_skip == 0 && (dir_u->flags & DIRENTRY_VI_FIRST_DIRENTRY_ITEM)
&& entries < 2)
entries = 0;
return entries ? : -1;
}
static int direntry_check_right(struct virtual_item *vi, int free)
{
int i;
int entries = 0;
struct direntry_uarea *dir_u = vi->vi_uarea;
for (i = dir_u->entry_count - 1; i >= 0; i--) {
if (dir_u->entry_sizes[i] > free)
/* i-th entry doesn't fit into the remaining free space */
break;
free -= dir_u->entry_sizes[i];
entries++;
}
BUG_ON(entries == dir_u->entry_count);
/* "." and ".." can not be separated from each other */
if ((dir_u->flags & DIRENTRY_VI_FIRST_DIRENTRY_ITEM)
&& entries > dir_u->entry_count - 2)
entries = dir_u->entry_count - 2;
return entries ? : -1;
}
/* sum of entry sizes between from-th and to-th entries including both edges */
static int direntry_part_size(struct virtual_item *vi, int first, int count)
{
int i, retval;
int from, to;
struct direntry_uarea *dir_u = vi->vi_uarea;
retval = 0;
if (first == 0)
from = 0;
else
from = dir_u->entry_count - count;
to = from + count - 1;
for (i = from; i <= to; i++)
retval += dir_u->entry_sizes[i];
return retval;
}
static int direntry_unit_num(struct virtual_item *vi)
{
struct direntry_uarea *dir_u = vi->vi_uarea;
return dir_u->entry_count;
}
static void direntry_print_vi(struct virtual_item *vi)
{
int i;
struct direntry_uarea *dir_u = vi->vi_uarea;
reiserfs_warning(NULL, "reiserfs-16104",
"DIRENTRY, index %d, type 0x%x, %h, flags 0x%x",
vi->vi_index, vi->vi_type, vi->vi_ih, dir_u->flags);
printk("%d entries: ", dir_u->entry_count);
for (i = 0; i < dir_u->entry_count; i++)
printk("%d ", dir_u->entry_sizes[i]);
printk("\n");
}
static 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_warning(NULL, "green-16001",
"Invalid item type observed, run fsck ASAP");
return 0;
}
static void errcatch_decrement_key(struct cpu_key *key)
{
reiserfs_warning(NULL, "green-16002",
"Invalid item type observed, run fsck ASAP");
}
static int errcatch_is_left_mergeable(struct reiserfs_key *key,
unsigned long bsize)
{
reiserfs_warning(NULL, "green-16003",
"Invalid item type observed, run fsck ASAP");
return 0;
}
static void errcatch_print_item(struct item_head *ih, char *item)
{
reiserfs_warning(NULL, "green-16004",
"Invalid item type observed, run fsck ASAP");
}
static void errcatch_check_item(struct item_head *ih, char *item)
{
reiserfs_warning(NULL, "green-16005",
"Invalid item type observed, run fsck ASAP");
}
static int errcatch_create_vi(struct virtual_node *vn,
struct virtual_item *vi,
int is_affected, int insert_size)
{
reiserfs_warning(NULL, "green-16006",
"Invalid item type observed, run fsck ASAP");
return 0; // We might return -1 here as well, but it won't help as create_virtual_node() from where
// this operation is called from is of return type void.
}
static int errcatch_check_left(struct virtual_item *vi, int free,
int start_skip, int end_skip)
{
reiserfs_warning(NULL, "green-16007",
"Invalid item type observed, run fsck ASAP");
return -1;
}
static int errcatch_check_right(struct virtual_item *vi, int free)
{
reiserfs_warning(NULL, "green-16008",
"Invalid item type observed, run fsck ASAP");
return -1;
}
static int errcatch_part_size(struct virtual_item *vi, int first, int count)
{
reiserfs_warning(NULL, "green-16009",
"Invalid item type observed, run fsck ASAP");
return 0;
}
static int errcatch_unit_num(struct virtual_item *vi)
{
reiserfs_warning(NULL, "green-16010",
"Invalid item type observed, run fsck ASAP");
return 0;
}
static void errcatch_print_vi(struct virtual_item *vi)
{
reiserfs_warning(NULL, "green-16011",
"Invalid item type observed, run fsck ASAP");
}
static 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 Item types must use disk-format assigned values.
#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) */
};

4317
kernel/fs/reiserfs/journal.c Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1548
kernel/fs/reiserfs/namei.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,203 @@
/*
* Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
*/
#include <linux/string.h>
#include <linux/random.h>
#include <linux/time.h>
#include <linux/reiserfs_fs.h>
#include <linux/reiserfs_fs_sb.h>
// find where objectid map starts
#define objectid_map(s,rs) (old_format_only (s) ? \
(__le32 *)((struct reiserfs_super_block_v1 *)(rs) + 1) :\
(__le32 *)((rs) + 1))
#ifdef CONFIG_REISERFS_CHECK
static void check_objectid_map(struct super_block *s, __le32 * map)
{
if (le32_to_cpu(map[0]) != 1)
reiserfs_panic(s, "vs-15010", "map corrupted: %lx",
(long unsigned int)le32_to_cpu(map[0]));
// FIXME: add something else here
}
#else
static void check_objectid_map(struct super_block *s, __le32 * map)
{;
}
#endif
/* When we allocate objectids we allocate the first unused objectid.
Each sequence of objectids in use (the odd sequences) is followed
by a sequence of objectids not in use (the even sequences). We
only need to record the last objectid in each of these sequences
(both the odd and even sequences) in order to fully define the
boundaries of the sequences. A consequence of allocating the first
objectid not in use is that under most conditions this scheme is
extremely compact. The exception is immediately after a sequence
of operations which deletes a large number of objects of
non-sequential objectids, and even then it will become compact
again as soon as more objects are created. Note that many
interesting optimizations of layout could result from complicating
objectid assignment, but we have deferred making them for now. */
/* get unique object identifier */
__u32 reiserfs_get_unused_objectid(struct reiserfs_transaction_handle *th)
{
struct super_block *s = th->t_super;
struct reiserfs_super_block *rs = SB_DISK_SUPER_BLOCK(s);
__le32 *map = objectid_map(s, rs);
__u32 unused_objectid;
BUG_ON(!th->t_trans_id);
check_objectid_map(s, map);
reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1);
/* comment needed -Hans */
unused_objectid = le32_to_cpu(map[1]);
if (unused_objectid == U32_MAX) {
reiserfs_warning(s, "reiserfs-15100", "no more object ids");
reiserfs_restore_prepared_buffer(s, SB_BUFFER_WITH_SB(s));
return 0;
}
/* This incrementation allocates the first unused objectid. That
is to say, the first entry on the objectid map is the first
unused objectid, and by incrementing it we use it. See below
where we check to see if we eliminated a sequence of unused
objectids.... */
map[1] = cpu_to_le32(unused_objectid + 1);
/* Now we check to see if we eliminated the last remaining member of
the first even sequence (and can eliminate the sequence by
eliminating its last objectid from oids), and can collapse the
first two odd sequences into one sequence. If so, then the net
result is to eliminate a pair of objectids from oids. We do this
by shifting the entire map to the left. */
if (sb_oid_cursize(rs) > 2 && map[1] == map[2]) {
memmove(map + 1, map + 3,
(sb_oid_cursize(rs) - 3) * sizeof(__u32));
set_sb_oid_cursize(rs, sb_oid_cursize(rs) - 2);
}
journal_mark_dirty(th, s, SB_BUFFER_WITH_SB(s));
return unused_objectid;
}
/* makes object identifier unused */
void reiserfs_release_objectid(struct reiserfs_transaction_handle *th,
__u32 objectid_to_release)
{
struct super_block *s = th->t_super;
struct reiserfs_super_block *rs = SB_DISK_SUPER_BLOCK(s);
__le32 *map = objectid_map(s, rs);
int i = 0;
BUG_ON(!th->t_trans_id);
//return;
check_objectid_map(s, map);
reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1);
journal_mark_dirty(th, s, SB_BUFFER_WITH_SB(s));
/* start at the beginning of the objectid map (i = 0) and go to
the end of it (i = disk_sb->s_oid_cursize). Linear search is
what we use, though it is possible that binary search would be
more efficient after performing lots of deletions (which is
when oids is large.) We only check even i's. */
while (i < sb_oid_cursize(rs)) {
if (objectid_to_release == le32_to_cpu(map[i])) {
/* This incrementation unallocates the objectid. */
//map[i]++;
le32_add_cpu(&map[i], 1);
/* Did we unallocate the last member of an odd sequence, and can shrink oids? */
if (map[i] == map[i + 1]) {
/* shrink objectid map */
memmove(map + i, map + i + 2,
(sb_oid_cursize(rs) - i -
2) * sizeof(__u32));
//disk_sb->s_oid_cursize -= 2;
set_sb_oid_cursize(rs, sb_oid_cursize(rs) - 2);
RFALSE(sb_oid_cursize(rs) < 2 ||
sb_oid_cursize(rs) > sb_oid_maxsize(rs),
"vs-15005: objectid map corrupted cur_size == %d (max == %d)",
sb_oid_cursize(rs), sb_oid_maxsize(rs));
}
return;
}
if (objectid_to_release > le32_to_cpu(map[i]) &&
objectid_to_release < le32_to_cpu(map[i + 1])) {
/* size of objectid map is not changed */
if (objectid_to_release + 1 == le32_to_cpu(map[i + 1])) {
//objectid_map[i+1]--;
le32_add_cpu(&map[i + 1], -1);
return;
}
/* JDM comparing two little-endian values for equality -- safe */
if (sb_oid_cursize(rs) == sb_oid_maxsize(rs)) {
/* objectid map must be expanded, but there is no space */
PROC_INFO_INC(s, leaked_oid);
return;
}
/* expand the objectid map */
memmove(map + i + 3, map + i + 1,
(sb_oid_cursize(rs) - i - 1) * sizeof(__u32));
map[i + 1] = cpu_to_le32(objectid_to_release);
map[i + 2] = cpu_to_le32(objectid_to_release + 1);
set_sb_oid_cursize(rs, sb_oid_cursize(rs) + 2);
return;
}
i += 2;
}
reiserfs_error(s, "vs-15011", "tried to free free object id (%lu)",
(long unsigned)objectid_to_release);
}
int reiserfs_convert_objectid_map_v1(struct super_block *s)
{
struct reiserfs_super_block *disk_sb = SB_DISK_SUPER_BLOCK(s);
int cur_size = sb_oid_cursize(disk_sb);
int new_size = (s->s_blocksize - SB_SIZE) / sizeof(__u32) / 2 * 2;
int old_max = sb_oid_maxsize(disk_sb);
struct reiserfs_super_block_v1 *disk_sb_v1;
__le32 *objectid_map, *new_objectid_map;
int i;
disk_sb_v1 =
(struct reiserfs_super_block_v1 *)(SB_BUFFER_WITH_SB(s)->b_data);
objectid_map = (__le32 *) (disk_sb_v1 + 1);
new_objectid_map = (__le32 *) (disk_sb + 1);
if (cur_size > new_size) {
/* mark everyone used that was listed as free at the end of the objectid
** map
*/
objectid_map[new_size - 1] = objectid_map[cur_size - 1];
set_sb_oid_cursize(disk_sb, new_size);
}
/* move the smaller objectid map past the end of the new super */
for (i = new_size - 1; i >= 0; i--) {
objectid_map[i + (old_max - new_size)] = objectid_map[i];
}
/* set the max size so we don't overflow later */
set_sb_oid_maxsize(disk_sb, new_size);
/* Zero out label and generate random UUID */
memset(disk_sb->s_label, 0, sizeof(disk_sb->s_label));
generate_random_uuid(disk_sb->s_uuid);
/* finally, zero out the unused chunk of the new super */
memset(disk_sb->s_unused, 0, sizeof(disk_sb->s_unused));
return 0;
}

772
kernel/fs/reiserfs/prints.c Normal file
View File

@@ -0,0 +1,772 @@
/*
* Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
*/
#include <linux/time.h>
#include <linux/fs.h>
#include <linux/reiserfs_fs.h>
#include <linux/string.h>
#include <linux/buffer_head.h>
#include <stdarg.h>
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 reiserfs_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 reiserfs_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 reiserfs_key *key)
{
if (key)
sprintf(buf, "[%d %d %s %s]", le32_to_cpu(key->k_dir_id),
le32_to_cpu(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 buffer_head *bh)
{
sprintf(buf, "level=%d, nr_items=%d, free_space=%d rdkey ",
B_LEVEL(bh), B_NR_ITEMS(bh), B_FREE_SPACE(bh));
}
static void sprintf_buffer_head(char *buf, struct buffer_head *bh)
{
char b[BDEVNAME_SIZE];
sprintf(buf,
"dev %s, size %zd, blocknr %llu, count %d, state 0x%lx, page %p, (%s, %s, %s)",
bdevname(bh->b_bdev, b), bh->b_size,
(unsigned long long)bh->b_blocknr, atomic_read(&(bh->b_count)),
bh->b_state, bh->b_page,
buffer_uptodate(bh) ? "UPTODATE" : "!UPTODATE",
buffer_dirty(bh) ? "DIRTY" : "CLEAN",
buffer_locked(bh) ? "LOCKED" : "UNLOCKED");
}
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)
{
char *k = fmt;
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;
}
k++;
}
return k;
}
/* debugging reiserfs we used to print out a lot of different
variables, like keys, item headers, buffer heads etc. Values of
most fields matter. So it took a long time just to write
appropriative printk. With this reiserfs_warning you can use format
specification for complex structures like you used to do with
printfs for integers, doubles and pointers. For instance, to print
out key structure you have to write just:
reiserfs_warning ("bad key %k", key);
instead of
printk ("bad key %lu %lu %lu %lu", key->k_dir_id, key->k_objectid,
key->k_offset, key->k_uniqueness);
*/
static DEFINE_SPINLOCK(error_lock);
static void prepare_error_buf(const char *fmt, va_list args)
{
char *fmt1 = fmt_buf;
char *k;
char *p = error_buf;
int what;
spin_lock(&error_lock);
strcpy(fmt1, fmt);
while ((k = is_there_reiserfs_struct(fmt1, &what)) != NULL) {
*k = 0;
p += vsprintf(p, fmt1, args);
switch (what) {
case 'k':
sprintf_le_key(p, va_arg(args, struct reiserfs_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 'b':
sprintf_buffer_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);
spin_unlock(&error_lock);
}
/* 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 buffer_head *
%b to print buffer_head
*/
#define do_reiserfs_warning(fmt)\
{\
va_list args;\
va_start( args, fmt );\
prepare_error_buf( fmt, args );\
va_end( args );\
}
void __reiserfs_warning(struct super_block *sb, const char *id,
const char *function, const char *fmt, ...)
{
do_reiserfs_warning(fmt);
if (sb)
printk(KERN_WARNING "REISERFS warning (device %s): %s%s%s: "
"%s\n", sb->s_id, id ? id : "", id ? " " : "",
function, error_buf);
else
printk(KERN_WARNING "REISERFS warning: %s%s%s: %s\n",
id ? id : "", id ? " " : "", function, error_buf);
}
/* No newline.. reiserfs_info calls can be followed by printk's */
void reiserfs_info(struct super_block *sb, const char *fmt, ...)
{
do_reiserfs_warning(fmt);
if (sb)
printk(KERN_NOTICE "REISERFS (device %s): %s",
sb->s_id, error_buf);
else
printk(KERN_NOTICE "REISERFS %s:", error_buf);
}
/* No newline.. reiserfs_printk calls can be followed by printk's */
static void reiserfs_printk(const char *fmt, ...)
{
do_reiserfs_warning(fmt);
printk(error_buf);
}
void reiserfs_debug(struct super_block *s, int level, const char *fmt, ...)
{
#ifdef CONFIG_REISERFS_CHECK
do_reiserfs_warning(fmt);
if (s)
printk(KERN_DEBUG "REISERFS debug (device %s): %s\n",
s->s_id, error_buf);
else
printk(KERN_DEBUG "REISERFS debug: %s\n", error_buf);
#endif
}
/* The format:
maintainer-errorid: [function-name:] message
where errorid is unique to the maintainer and function-name is
optional, is recommended, so that anyone can easily find the bug
with a simple grep for the short to type string
maintainer-errorid. Don't bother with reusing errorids, there are
lots of numbers out there.
Example:
reiserfs_panic(
p_sb, "reiser-29: reiserfs_new_blocknrs: "
"one of search_start or rn(%d) is equal to MAX_B_NUM,"
"which means that we are optimizing location based on the bogus location of a temp buffer (%p).",
rn, bh
);
Regular panic()s sometimes clear the screen before the message can
be read, thus the need for the while loop.
Numbering scheme for panic used by Vladimir and Anatoly( Hans completely ignores this scheme, and considers it
pointless complexity):
panics in reiserfs_fs.h have numbers from 1000 to 1999
super.c 2000 to 2999
preserve.c (unused) 3000 to 3999
bitmap.c 4000 to 4999
stree.c 5000 to 5999
prints.c 6000 to 6999
namei.c 7000 to 7999
fix_nodes.c 8000 to 8999
dir.c 9000 to 9999
lbalance.c 10000 to 10999
ibalance.c 11000 to 11999 not ready
do_balan.c 12000 to 12999
inode.c 13000 to 13999
file.c 14000 to 14999
objectid.c 15000 - 15999
buffer.c 16000 - 16999
symlink.c 17000 - 17999
. */
#ifdef CONFIG_REISERFS_CHECK
extern struct tree_balance *cur_tb;
#endif
void __reiserfs_panic(struct super_block *sb, const char *id,
const char *function, const char *fmt, ...)
{
do_reiserfs_warning(fmt);
#ifdef CONFIG_REISERFS_CHECK
dump_stack();
#endif
if (sb)
panic(KERN_WARNING "REISERFS panic (device %s): %s%s%s: %s\n",
sb->s_id, id ? id : "", id ? " " : "",
function, error_buf);
else
panic(KERN_WARNING "REISERFS panic: %s%s%s: %s\n",
id ? id : "", id ? " " : "", function, error_buf);
}
void __reiserfs_error(struct super_block *sb, const char *id,
const char *function, const char *fmt, ...)
{
do_reiserfs_warning(fmt);
BUG_ON(sb == NULL);
if (reiserfs_error_panic(sb))
__reiserfs_panic(sb, id, function, error_buf);
if (id && id[0])
printk(KERN_CRIT "REISERFS error (device %s): %s %s: %s\n",
sb->s_id, id, function, error_buf);
else
printk(KERN_CRIT "REISERFS error (device %s): %s: %s\n",
sb->s_id, function, error_buf);
if (sb->s_flags & MS_RDONLY)
return;
reiserfs_info(sb, "Remounting filesystem read-only\n");
sb->s_flags |= MS_RDONLY;
reiserfs_abort_journal(sb, -EIO);
}
void reiserfs_abort(struct super_block *sb, int errno, const char *fmt, ...)
{
do_reiserfs_warning(fmt);
if (reiserfs_error_panic(sb)) {
panic(KERN_CRIT "REISERFS panic (device %s): %s\n", sb->s_id,
error_buf);
}
if (reiserfs_is_journal_aborted(SB_JOURNAL(sb)))
return;
printk(KERN_CRIT "REISERFS abort (device %s): %s\n", sb->s_id,
error_buf);
sb->s_flags |= MS_RDONLY;
reiserfs_abort_journal(sb, errno);
}
/* this prints internal nodes (4 keys/items in line) (dc_number,
dc_size)[k_dirid, k_objectid, k_offset, k_uniqueness](dc_number,
dc_size)...*/
static int print_internal(struct buffer_head *bh, int first, int last)
{
struct reiserfs_key *key;
struct disk_child *dc;
int i;
int from, to;
if (!B_IS_KEYS_LEVEL(bh))
return 1;
check_internal(bh);
if (first == -1) {
from = 0;
to = B_NR_ITEMS(bh);
} else {
from = first;
to = last < B_NR_ITEMS(bh) ? last : B_NR_ITEMS(bh);
}
reiserfs_printk("INTERNAL NODE (%ld) contains %z\n", bh->b_blocknr, bh);
dc = B_N_CHILD(bh, from);
reiserfs_printk("PTR %d: %y ", from, dc);
for (i = from, key = B_N_PDELIM_KEY(bh, from), dc++; i < to;
i++, key++, dc++) {
reiserfs_printk("KEY %d: %k PTR %d: %y ", i, key, i + 1, dc);
if (i && i % 4 == 0)
printk("\n");
}
printk("\n");
return 0;
}
static int print_leaf(struct buffer_head *bh, int print_mode, int first,
int last)
{
struct block_head *blkh;
struct item_head *ih;
int i, nr;
int from, to;
if (!B_IS_ITEMS_LEVEL(bh))
return 1;
check_leaf(bh);
blkh = B_BLK_HEAD(bh);
ih = B_N_PITEM_HEAD(bh, 0);
nr = blkh_nr_item(blkh);
printk
("\n===================================================================\n");
reiserfs_printk("LEAF NODE (%ld) contains %z\n", bh->b_blocknr, bh);
if (!(print_mode & PRINT_LEAF_ITEMS)) {
reiserfs_printk("FIRST ITEM_KEY: %k, LAST ITEM KEY: %k\n",
&(ih->ih_key), &((ih + nr - 1)->ih_key));
return 0;
}
if (first < 0 || first > nr - 1)
from = 0;
else
from = first;
if (last < 0 || last > nr)
to = nr;
else
to = last;
ih += from;
printk
("-------------------------------------------------------------------------------\n");
printk
("|##| type | key | ilen | free_space | version | loc |\n");
for (i = from; i < to; i++, ih++) {
printk
("-------------------------------------------------------------------------------\n");
reiserfs_printk("|%2d| %h |\n", i, ih);
if (print_mode & PRINT_LEAF_ITEMS)
op_print_item(ih, B_I_PITEM(bh, ih));
}
printk
("===================================================================\n");
return 0;
}
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";
}
/* return 1 if this is not super block */
static int print_super_block(struct buffer_head *bh)
{
struct reiserfs_super_block *rs =
(struct reiserfs_super_block *)(bh->b_data);
int skipped, data_blocks;
char *version;
char b[BDEVNAME_SIZE];
if (is_reiserfs_3_5(rs)) {
version = "3.5";
} else if (is_reiserfs_3_6(rs)) {
version = "3.6";
} else if (is_reiserfs_jr(rs)) {
version = ((sb_version(rs) == REISERFS_VERSION_2) ?
"3.6" : "3.5");
} else {
return 1;
}
printk("%s\'s super block is in block %llu\n", bdevname(bh->b_bdev, b),
(unsigned long long)bh->b_blocknr);
printk("Reiserfs version %s\n", version);
printk("Block count %u\n", sb_block_count(rs));
printk("Blocksize %d\n", sb_blocksize(rs));
printk("Free blocks %u\n", sb_free_blocks(rs));
// FIXME: this would be confusing if
// someone stores reiserfs super block in some data block ;)
// skipped = (bh->b_blocknr * bh->b_size) / sb_blocksize(rs);
skipped = bh->b_blocknr;
data_blocks = sb_block_count(rs) - skipped - 1 - sb_bmap_nr(rs) -
(!is_reiserfs_jr(rs) ? sb_jp_journal_size(rs) +
1 : sb_reserved_for_journal(rs)) - sb_free_blocks(rs);
printk
("Busy blocks (skipped %d, bitmaps - %d, journal (or reserved) blocks - %d\n"
"1 super block, %d data blocks\n", skipped, sb_bmap_nr(rs),
(!is_reiserfs_jr(rs) ? (sb_jp_journal_size(rs) + 1) :
sb_reserved_for_journal(rs)), data_blocks);
printk("Root block %u\n", sb_root_block(rs));
printk("Journal block (first) %d\n", sb_jp_journal_1st_block(rs));
printk("Journal dev %d\n", sb_jp_journal_dev(rs));
printk("Journal orig size %d\n", sb_jp_journal_size(rs));
printk("FS state %d\n", sb_fs_state(rs));
printk("Hash function \"%s\"\n",
reiserfs_hashname(sb_hash_function_code(rs)));
printk("Tree height %d\n", sb_tree_height(rs));
return 0;
}
static int print_desc_block(struct buffer_head *bh)
{
struct reiserfs_journal_desc *desc;
if (memcmp(get_journal_desc_magic(bh), JOURNAL_DESC_MAGIC, 8))
return 1;
desc = (struct reiserfs_journal_desc *)(bh->b_data);
printk("Desc block %llu (j_trans_id %d, j_mount_id %d, j_len %d)",
(unsigned long long)bh->b_blocknr, get_desc_trans_id(desc),
get_desc_mount_id(desc), get_desc_trans_len(desc));
return 0;
}
void print_block(struct buffer_head *bh, ...) //int print_mode, int first, int last)
{
va_list args;
int mode, first, last;
va_start(args, bh);
if (!bh) {
printk("print_block: buffer is NULL\n");
return;
}
mode = va_arg(args, int);
first = va_arg(args, int);
last = va_arg(args, int);
if (print_leaf(bh, mode, first, last))
if (print_internal(bh, first, last))
if (print_super_block(bh))
if (print_desc_block(bh))
printk
("Block %llu contains unformatted data\n",
(unsigned long long)bh->b_blocknr);
va_end(args);
}
static char print_tb_buf[2048];
/* this stores initial state of tree balance in the print_tb_buf */
void store_print_tb(struct tree_balance *tb)
{
int h = 0;
int i;
struct buffer_head *tbSh, *tbFh;
if (!tb)
return;
sprintf(print_tb_buf, "\n"
"BALANCING %d\n"
"MODE=%c, ITEM_POS=%d POS_IN_ITEM=%d\n"
"=====================================================================\n"
"* h * S * L * R * F * FL * FR * CFL * CFR *\n",
REISERFS_SB(tb->tb_sb)->s_do_balance,
tb->tb_mode, PATH_LAST_POSITION(tb->tb_path),
tb->tb_path->pos_in_item);
for (h = 0; h < ARRAY_SIZE(tb->insert_size); h++) {
if (PATH_H_PATH_OFFSET(tb->tb_path, h) <=
tb->tb_path->path_length
&& PATH_H_PATH_OFFSET(tb->tb_path,
h) > ILLEGAL_PATH_ELEMENT_OFFSET) {
tbSh = PATH_H_PBUFFER(tb->tb_path, h);
tbFh = PATH_H_PPARENT(tb->tb_path, h);
} else {
tbSh = NULL;
tbFh = NULL;
}
sprintf(print_tb_buf + strlen(print_tb_buf),
"* %d * %3lld(%2d) * %3lld(%2d) * %3lld(%2d) * %5lld * %5lld * %5lld * %5lld * %5lld *\n",
h,
(tbSh) ? (long long)(tbSh->b_blocknr) : (-1LL),
(tbSh) ? atomic_read(&(tbSh->b_count)) : -1,
(tb->L[h]) ? (long long)(tb->L[h]->b_blocknr) : (-1LL),
(tb->L[h]) ? atomic_read(&(tb->L[h]->b_count)) : -1,
(tb->R[h]) ? (long long)(tb->R[h]->b_blocknr) : (-1LL),
(tb->R[h]) ? atomic_read(&(tb->R[h]->b_count)) : -1,
(tbFh) ? (long long)(tbFh->b_blocknr) : (-1LL),
(tb->FL[h]) ? (long long)(tb->FL[h]->
b_blocknr) : (-1LL),
(tb->FR[h]) ? (long long)(tb->FR[h]->
b_blocknr) : (-1LL),
(tb->CFL[h]) ? (long long)(tb->CFL[h]->
b_blocknr) : (-1LL),
(tb->CFR[h]) ? (long long)(tb->CFR[h]->
b_blocknr) : (-1LL));
}
sprintf(print_tb_buf + strlen(print_tb_buf),
"=====================================================================\n"
"* h * size * ln * lb * rn * rb * blkn * s0 * s1 * s1b * s2 * s2b * curb * lk * rk *\n"
"* 0 * %4d * %2d * %2d * %2d * %2d * %4d * %2d * %2d * %3d * %2d * %3d * %4d * %2d * %2d *\n",
tb->insert_size[0], tb->lnum[0], tb->lbytes, tb->rnum[0],
tb->rbytes, tb->blknum[0], tb->s0num, tb->s1num, tb->s1bytes,
tb->s2num, tb->s2bytes, tb->cur_blknum, tb->lkey[0],
tb->rkey[0]);
/* this prints balance parameters for non-leaf levels */
h = 0;
do {
h++;
sprintf(print_tb_buf + strlen(print_tb_buf),
"* %d * %4d * %2d * * %2d * * %2d *\n",
h, tb->insert_size[h], tb->lnum[h], tb->rnum[h],
tb->blknum[h]);
} while (tb->insert_size[h]);
sprintf(print_tb_buf + strlen(print_tb_buf),
"=====================================================================\n"
"FEB list: ");
/* print FEB list (list of buffers in form (bh (b_blocknr, b_count), that will be used for new nodes) */
h = 0;
for (i = 0; i < ARRAY_SIZE(tb->FEB); i++)
sprintf(print_tb_buf + strlen(print_tb_buf),
"%p (%llu %d)%s", tb->FEB[i],
tb->FEB[i] ? (unsigned long long)tb->FEB[i]->
b_blocknr : 0ULL,
tb->FEB[i] ? atomic_read(&(tb->FEB[i]->b_count)) : 0,
(i == ARRAY_SIZE(tb->FEB) - 1) ? "\n" : ", ");
sprintf(print_tb_buf + strlen(print_tb_buf),
"======================== the end ====================================\n");
}
void print_cur_tb(char *mes)
{
printk("%s\n%s", mes, print_tb_buf);
}
static void check_leaf_block_head(struct buffer_head *bh)
{
struct block_head *blkh;
int nr;
blkh = B_BLK_HEAD(bh);
nr = blkh_nr_item(blkh);
if (nr > (bh->b_size - BLKH_SIZE) / IH_SIZE)
reiserfs_panic(NULL, "vs-6010", "invalid item number %z",
bh);
if (blkh_free_space(blkh) > bh->b_size - BLKH_SIZE - IH_SIZE * nr)
reiserfs_panic(NULL, "vs-6020", "invalid free space %z",
bh);
}
static void check_internal_block_head(struct buffer_head *bh)
{
struct block_head *blkh;
blkh = B_BLK_HEAD(bh);
if (!(B_LEVEL(bh) > DISK_LEAF_NODE_LEVEL && B_LEVEL(bh) <= MAX_HEIGHT))
reiserfs_panic(NULL, "vs-6025", "invalid level %z", bh);
if (B_NR_ITEMS(bh) > (bh->b_size - BLKH_SIZE) / IH_SIZE)
reiserfs_panic(NULL, "vs-6030", "invalid item number %z", bh);
if (B_FREE_SPACE(bh) !=
bh->b_size - BLKH_SIZE - KEY_SIZE * B_NR_ITEMS(bh) -
DC_SIZE * (B_NR_ITEMS(bh) + 1))
reiserfs_panic(NULL, "vs-6040", "invalid free space %z", bh);
}
void check_leaf(struct buffer_head *bh)
{
int i;
struct item_head *ih;
if (!bh)
return;
check_leaf_block_head(bh);
for (i = 0, ih = B_N_PITEM_HEAD(bh, 0); i < B_NR_ITEMS(bh); i++, ih++)
op_check_item(ih, B_I_PITEM(bh, ih));
}
void check_internal(struct buffer_head *bh)
{
if (!bh)
return;
check_internal_block_head(bh);
}
void print_statistics(struct super_block *s)
{
/*
printk ("reiserfs_put_super: session statistics: balances %d, fix_nodes %d, \
bmap with search %d, without %d, dir2ind %d, ind2dir %d\n",
REISERFS_SB(s)->s_do_balance, REISERFS_SB(s)->s_fix_nodes,
REISERFS_SB(s)->s_bmaps, REISERFS_SB(s)->s_bmaps_without_search,
REISERFS_SB(s)->s_direct2indirect, REISERFS_SB(s)->s_indirect2direct);
*/
}

641
kernel/fs/reiserfs/procfs.c Normal file
View File

@@ -0,0 +1,641 @@
/* -*- linux-c -*- */
/* fs/reiserfs/procfs.c */
/*
* Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
*/
/* proc info support a la one created by Sizif@Botik.RU for PGC */
#include <linux/module.h>
#include <linux/time.h>
#include <linux/seq_file.h>
#include <asm/uaccess.h>
#include <linux/reiserfs_fs.h>
#include <linux/reiserfs_fs_sb.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#ifdef CONFIG_REISERFS_PROC_INFO
/*
* LOCKING:
*
* We rely on new Alexander Viro's super-block locking.
*
*/
static int show_version(struct seq_file *m, struct super_block *sb)
{
char *format;
if (REISERFS_SB(sb)->s_properties & (1 << REISERFS_3_6)) {
format = "3.6";
} else if (REISERFS_SB(sb)->s_properties & (1 << REISERFS_3_5)) {
format = "3.5";
} else {
format = "unknown";
}
seq_printf(m, "%s format\twith checks %s\n", format,
#if defined( CONFIG_REISERFS_CHECK )
"on"
#else
"off"
#endif
);
return 0;
}
int reiserfs_global_version_in_proc(char *buffer, char **start, off_t offset,
int count, int *eof, void *data)
{
*start = buffer;
*eof = 1;
return 0;
}
#define SF( x ) ( r -> x )
#define SFP( x ) SF( s_proc_info_data.x )
#define SFPL( x ) SFP( x[ level ] )
#define SFPF( x ) SFP( scan_bitmap.x )
#define SFPJ( x ) SFP( journal.x )
#define D2C( x ) le16_to_cpu( x )
#define D4C( x ) le32_to_cpu( x )
#define DF( x ) D2C( rs -> s_v1.x )
#define DFL( x ) D4C( rs -> s_v1.x )
#define objectid_map( s, rs ) (old_format_only (s) ? \
(__le32 *)((struct reiserfs_super_block_v1 *)rs + 1) : \
(__le32 *)(rs + 1))
#define MAP( i ) D4C( objectid_map( sb, rs )[ i ] )
#define DJF( x ) le32_to_cpu( rs -> x )
#define DJV( x ) le32_to_cpu( s_v1 -> x )
#define DJP( x ) le32_to_cpu( jp -> x )
#define JF( x ) ( r -> s_journal -> x )
static int show_super(struct seq_file *m, struct super_block *sb)
{
struct reiserfs_sb_info *r = REISERFS_SB(sb);
seq_printf(m, "state: \t%s\n"
"mount options: \t%s%s%s%s%s%s%s%s%s%s%s\n"
"gen. counter: \t%i\n"
"s_disk_reads: \t%i\n"
"s_disk_writes: \t%i\n"
"s_fix_nodes: \t%i\n"
"s_do_balance: \t%i\n"
"s_unneeded_left_neighbor: \t%i\n"
"s_good_search_by_key_reada: \t%i\n"
"s_bmaps: \t%i\n"
"s_bmaps_without_search: \t%i\n"
"s_direct2indirect: \t%i\n"
"s_indirect2direct: \t%i\n"
"\n"
"max_hash_collisions: \t%i\n"
"breads: \t%lu\n"
"bread_misses: \t%lu\n"
"search_by_key: \t%lu\n"
"search_by_key_fs_changed: \t%lu\n"
"search_by_key_restarted: \t%lu\n"
"insert_item_restarted: \t%lu\n"
"paste_into_item_restarted: \t%lu\n"
"cut_from_item_restarted: \t%lu\n"
"delete_solid_item_restarted: \t%lu\n"
"delete_item_restarted: \t%lu\n"
"leaked_oid: \t%lu\n"
"leaves_removable: \t%lu\n",
SF(s_mount_state) == REISERFS_VALID_FS ?
"REISERFS_VALID_FS" : "REISERFS_ERROR_FS",
reiserfs_r5_hash(sb) ? "FORCE_R5 " : "",
reiserfs_rupasov_hash(sb) ? "FORCE_RUPASOV " : "",
reiserfs_tea_hash(sb) ? "FORCE_TEA " : "",
reiserfs_hash_detect(sb) ? "DETECT_HASH " : "",
reiserfs_no_border(sb) ? "NO_BORDER " : "BORDER ",
reiserfs_no_unhashed_relocation(sb) ?
"NO_UNHASHED_RELOCATION " : "",
reiserfs_hashed_relocation(sb) ? "UNHASHED_RELOCATION " : "",
reiserfs_test4(sb) ? "TEST4 " : "",
have_large_tails(sb) ? "TAILS " : have_small_tails(sb) ?
"SMALL_TAILS " : "NO_TAILS ",
replay_only(sb) ? "REPLAY_ONLY " : "",
convert_reiserfs(sb) ? "CONV " : "",
atomic_read(&r->s_generation_counter),
SF(s_disk_reads), SF(s_disk_writes), SF(s_fix_nodes),
SF(s_do_balance), SF(s_unneeded_left_neighbor),
SF(s_good_search_by_key_reada), SF(s_bmaps),
SF(s_bmaps_without_search), SF(s_direct2indirect),
SF(s_indirect2direct), SFP(max_hash_collisions), SFP(breads),
SFP(bread_miss), SFP(search_by_key),
SFP(search_by_key_fs_changed), SFP(search_by_key_restarted),
SFP(insert_item_restarted), SFP(paste_into_item_restarted),
SFP(cut_from_item_restarted),
SFP(delete_solid_item_restarted), SFP(delete_item_restarted),
SFP(leaked_oid), SFP(leaves_removable));
return 0;
}
static int show_per_level(struct seq_file *m, struct super_block *sb)
{
struct reiserfs_sb_info *r = REISERFS_SB(sb);
int level;
seq_printf(m, "level\t"
" balances"
" [sbk: reads"
" fs_changed"
" restarted]"
" free space"
" items"
" can_remove"
" lnum"
" rnum"
" lbytes"
" rbytes"
" get_neig"
" get_neig_res" " need_l_neig" " need_r_neig" "\n");
for (level = 0; level < MAX_HEIGHT; ++level) {
seq_printf(m, "%i\t"
" %12lu"
" %12lu"
" %12lu"
" %12lu"
" %12lu"
" %12lu"
" %12lu"
" %12li"
" %12li"
" %12li"
" %12li"
" %12lu"
" %12lu"
" %12lu"
" %12lu"
"\n",
level,
SFPL(balance_at),
SFPL(sbk_read_at),
SFPL(sbk_fs_changed),
SFPL(sbk_restarted),
SFPL(free_at),
SFPL(items_at),
SFPL(can_node_be_removed),
SFPL(lnum),
SFPL(rnum),
SFPL(lbytes),
SFPL(rbytes),
SFPL(get_neighbors),
SFPL(get_neighbors_restart),
SFPL(need_l_neighbor), SFPL(need_r_neighbor)
);
}
return 0;
}
static int show_bitmap(struct seq_file *m, struct super_block *sb)
{
struct reiserfs_sb_info *r = REISERFS_SB(sb);
seq_printf(m, "free_block: %lu\n"
" scan_bitmap:"
" wait"
" bmap"
" retry"
" stolen"
" journal_hint"
"journal_nohint"
"\n"
" %14lu"
" %14lu"
" %14lu"
" %14lu"
" %14lu"
" %14lu"
" %14lu"
"\n",
SFP(free_block),
SFPF(call),
SFPF(wait),
SFPF(bmap),
SFPF(retry),
SFPF(stolen),
SFPF(in_journal_hint), SFPF(in_journal_nohint));
return 0;
}
static int show_on_disk_super(struct seq_file *m, struct super_block *sb)
{
struct reiserfs_sb_info *sb_info = REISERFS_SB(sb);
struct reiserfs_super_block *rs = sb_info->s_rs;
int hash_code = DFL(s_hash_function_code);
__u32 flags = DJF(s_flags);
seq_printf(m, "block_count: \t%i\n"
"free_blocks: \t%i\n"
"root_block: \t%i\n"
"blocksize: \t%i\n"
"oid_maxsize: \t%i\n"
"oid_cursize: \t%i\n"
"umount_state: \t%i\n"
"magic: \t%10.10s\n"
"fs_state: \t%i\n"
"hash: \t%s\n"
"tree_height: \t%i\n"
"bmap_nr: \t%i\n"
"version: \t%i\n"
"flags: \t%x[%s]\n"
"reserved_for_journal: \t%i\n",
DFL(s_block_count),
DFL(s_free_blocks),
DFL(s_root_block),
DF(s_blocksize),
DF(s_oid_maxsize),
DF(s_oid_cursize),
DF(s_umount_state),
rs->s_v1.s_magic,
DF(s_fs_state),
hash_code == TEA_HASH ? "tea" :
(hash_code == YURA_HASH) ? "rupasov" :
(hash_code == R5_HASH) ? "r5" :
(hash_code == UNSET_HASH) ? "unset" : "unknown",
DF(s_tree_height),
DF(s_bmap_nr),
DF(s_version), flags, (flags & reiserfs_attrs_cleared)
? "attrs_cleared" : "", DF(s_reserved_for_journal));
return 0;
}
static int show_oidmap(struct seq_file *m, struct super_block *sb)
{
struct reiserfs_sb_info *sb_info = REISERFS_SB(sb);
struct reiserfs_super_block *rs = sb_info->s_rs;
unsigned int mapsize = le16_to_cpu(rs->s_v1.s_oid_cursize);
unsigned long total_used = 0;
int i;
for (i = 0; i < mapsize; ++i) {
__u32 right;
right = (i == mapsize - 1) ? MAX_KEY_OBJECTID : MAP(i + 1);
seq_printf(m, "%s: [ %x .. %x )\n",
(i & 1) ? "free" : "used", MAP(i), right);
if (!(i & 1)) {
total_used += right - MAP(i);
}
}
#if defined( REISERFS_USE_OIDMAPF )
if (sb_info->oidmap.use_file && (sb_info->oidmap.mapf != NULL)) {
loff_t size = sb_info->oidmap.mapf->f_path.dentry->d_inode->i_size;
total_used += size / sizeof(reiserfs_oidinterval_d_t);
}
#endif
seq_printf(m, "total: \t%i [%i/%i] used: %lu [exact]\n",
mapsize,
mapsize, le16_to_cpu(rs->s_v1.s_oid_maxsize), total_used);
return 0;
}
static int show_journal(struct seq_file *m, struct super_block *sb)
{
struct reiserfs_sb_info *r = REISERFS_SB(sb);
struct reiserfs_super_block *rs = r->s_rs;
struct journal_params *jp = &rs->s_v1.s_journal;
char b[BDEVNAME_SIZE];
seq_printf(m, /* on-disk fields */
"jp_journal_1st_block: \t%i\n"
"jp_journal_dev: \t%s[%x]\n"
"jp_journal_size: \t%i\n"
"jp_journal_trans_max: \t%i\n"
"jp_journal_magic: \t%i\n"
"jp_journal_max_batch: \t%i\n"
"jp_journal_max_commit_age: \t%i\n"
"jp_journal_max_trans_age: \t%i\n"
/* incore fields */
"j_1st_reserved_block: \t%i\n"
"j_state: \t%li\n"
"j_trans_id: \t%u\n"
"j_mount_id: \t%lu\n"
"j_start: \t%lu\n"
"j_len: \t%lu\n"
"j_len_alloc: \t%lu\n"
"j_wcount: \t%i\n"
"j_bcount: \t%lu\n"
"j_first_unflushed_offset: \t%lu\n"
"j_last_flush_trans_id: \t%u\n"
"j_trans_start_time: \t%li\n"
"j_list_bitmap_index: \t%i\n"
"j_must_wait: \t%i\n"
"j_next_full_flush: \t%i\n"
"j_next_async_flush: \t%i\n"
"j_cnode_used: \t%i\n" "j_cnode_free: \t%i\n" "\n"
/* reiserfs_proc_info_data_t.journal fields */
"in_journal: \t%12lu\n"
"in_journal_bitmap: \t%12lu\n"
"in_journal_reusable: \t%12lu\n"
"lock_journal: \t%12lu\n"
"lock_journal_wait: \t%12lu\n"
"journal_begin: \t%12lu\n"
"journal_relock_writers: \t%12lu\n"
"journal_relock_wcount: \t%12lu\n"
"mark_dirty: \t%12lu\n"
"mark_dirty_already: \t%12lu\n"
"mark_dirty_notjournal: \t%12lu\n"
"restore_prepared: \t%12lu\n"
"prepare: \t%12lu\n"
"prepare_retry: \t%12lu\n",
DJP(jp_journal_1st_block),
bdevname(SB_JOURNAL(sb)->j_dev_bd, b),
DJP(jp_journal_dev),
DJP(jp_journal_size),
DJP(jp_journal_trans_max),
DJP(jp_journal_magic),
DJP(jp_journal_max_batch),
SB_JOURNAL(sb)->j_max_commit_age,
DJP(jp_journal_max_trans_age),
JF(j_1st_reserved_block),
JF(j_state),
JF(j_trans_id),
JF(j_mount_id),
JF(j_start),
JF(j_len),
JF(j_len_alloc),
atomic_read(&r->s_journal->j_wcount),
JF(j_bcount),
JF(j_first_unflushed_offset),
JF(j_last_flush_trans_id),
JF(j_trans_start_time),
JF(j_list_bitmap_index),
JF(j_must_wait),
JF(j_next_full_flush),
JF(j_next_async_flush),
JF(j_cnode_used),
JF(j_cnode_free),
SFPJ(in_journal),
SFPJ(in_journal_bitmap),
SFPJ(in_journal_reusable),
SFPJ(lock_journal),
SFPJ(lock_journal_wait),
SFPJ(journal_being),
SFPJ(journal_relock_writers),
SFPJ(journal_relock_wcount),
SFPJ(mark_dirty),
SFPJ(mark_dirty_already),
SFPJ(mark_dirty_notjournal),
SFPJ(restore_prepared), SFPJ(prepare), SFPJ(prepare_retry)
);
return 0;
}
/* iterator */
static int test_sb(struct super_block *sb, void *data)
{
return data == sb;
}
static int set_sb(struct super_block *sb, void *data)
{
return -ENOENT;
}
static void *r_start(struct seq_file *m, loff_t * pos)
{
struct proc_dir_entry *de = m->private;
struct super_block *s = de->parent->data;
loff_t l = *pos;
if (l)
return NULL;
if (IS_ERR(sget(&reiserfs_fs_type, test_sb, set_sb, s)))
return NULL;
up_write(&s->s_umount);
return s;
}
static void *r_next(struct seq_file *m, void *v, loff_t * pos)
{
++*pos;
if (v)
deactivate_super(v);
return NULL;
}
static void r_stop(struct seq_file *m, void *v)
{
if (v)
deactivate_super(v);
}
static int r_show(struct seq_file *m, void *v)
{
struct proc_dir_entry *de = m->private;
int (*show) (struct seq_file *, struct super_block *) = de->data;
return show(m, v);
}
static const struct seq_operations r_ops = {
.start = r_start,
.next = r_next,
.stop = r_stop,
.show = r_show,
};
static int r_open(struct inode *inode, struct file *file)
{
int ret = seq_open(file, &r_ops);
if (!ret) {
struct seq_file *m = file->private_data;
m->private = PDE(inode);
}
return ret;
}
static const struct file_operations r_file_operations = {
.open = r_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
.owner = THIS_MODULE,
};
static struct proc_dir_entry *proc_info_root = NULL;
static const char proc_info_root_name[] = "fs/reiserfs";
static void add_file(struct super_block *sb, char *name,
int (*func) (struct seq_file *, struct super_block *))
{
proc_create_data(name, 0, REISERFS_SB(sb)->procdir,
&r_file_operations, func);
}
int reiserfs_proc_info_init(struct super_block *sb)
{
char b[BDEVNAME_SIZE];
char *s;
/* Some block devices use /'s */
strlcpy(b, reiserfs_bdevname(sb), BDEVNAME_SIZE);
s = strchr(b, '/');
if (s)
*s = '!';
spin_lock_init(&__PINFO(sb).lock);
REISERFS_SB(sb)->procdir = proc_mkdir(b, proc_info_root);
if (REISERFS_SB(sb)->procdir) {
REISERFS_SB(sb)->procdir->data = sb;
add_file(sb, "version", show_version);
add_file(sb, "super", show_super);
add_file(sb, "per-level", show_per_level);
add_file(sb, "bitmap", show_bitmap);
add_file(sb, "on-disk-super", show_on_disk_super);
add_file(sb, "oidmap", show_oidmap);
add_file(sb, "journal", show_journal);
return 0;
}
reiserfs_warning(sb, "cannot create /proc/%s/%s",
proc_info_root_name, b);
return 1;
}
int reiserfs_proc_info_done(struct super_block *sb)
{
struct proc_dir_entry *de = REISERFS_SB(sb)->procdir;
char b[BDEVNAME_SIZE];
char *s;
/* Some block devices use /'s */
strlcpy(b, reiserfs_bdevname(sb), BDEVNAME_SIZE);
s = strchr(b, '/');
if (s)
*s = '!';
if (de) {
remove_proc_entry("journal", de);
remove_proc_entry("oidmap", de);
remove_proc_entry("on-disk-super", de);
remove_proc_entry("bitmap", de);
remove_proc_entry("per-level", de);
remove_proc_entry("super", de);
remove_proc_entry("version", de);
}
spin_lock(&__PINFO(sb).lock);
__PINFO(sb).exiting = 1;
spin_unlock(&__PINFO(sb).lock);
if (proc_info_root) {
remove_proc_entry(b, proc_info_root);
REISERFS_SB(sb)->procdir = NULL;
}
return 0;
}
struct proc_dir_entry *reiserfs_proc_register_global(char *name,
read_proc_t * func)
{
return (proc_info_root) ? create_proc_read_entry(name, 0,
proc_info_root,
func, NULL) : NULL;
}
void reiserfs_proc_unregister_global(const char *name)
{
remove_proc_entry(name, proc_info_root);
}
int reiserfs_proc_info_global_init(void)
{
if (proc_info_root == NULL) {
proc_info_root = proc_mkdir(proc_info_root_name, NULL);
if (!proc_info_root) {
reiserfs_warning(NULL, "cannot create /proc/%s",
proc_info_root_name);
return 1;
}
}
return 0;
}
int reiserfs_proc_info_global_done(void)
{
if (proc_info_root != NULL) {
proc_info_root = NULL;
remove_proc_entry(proc_info_root_name, NULL);
}
return 0;
}
/* REISERFS_PROC_INFO */
#else
int reiserfs_proc_info_init(struct super_block *sb)
{
return 0;
}
int reiserfs_proc_info_done(struct super_block *sb)
{
return 0;
}
struct proc_dir_entry *reiserfs_proc_register_global(char *name,
read_proc_t * func)
{
return NULL;
}
void reiserfs_proc_unregister_global(const char *name)
{;
}
int reiserfs_proc_info_global_init(void)
{
return 0;
}
int reiserfs_proc_info_global_done(void)
{
return 0;
}
int reiserfs_global_version_in_proc(char *buffer, char **start,
off_t offset,
int count, int *eof, void *data)
{
return 0;
}
/* REISERFS_PROC_INFO */
#endif
/*
* Revision 1.1.8.2 2001/07/15 17:08:42 god
* . use get_super() in procfs.c
* . remove remove_save_link() from reiserfs_do_truncate()
*
* I accept terms and conditions stated in the Legal Agreement
* (available at http://www.namesys.com/legalese.html)
*
* Revision 1.1.8.1 2001/07/11 16:48:50 god
* proc info support
*
* I accept terms and conditions stated in the Legal Agreement
* (available at http://www.namesys.com/legalese.html)
*
*/
/*
* Make Linus happy.
* Local variables:
* c-indentation-style: "K&R"
* mode-name: "LC"
* c-basic-offset: 8
* tab-width: 8
* End:
*/

210
kernel/fs/reiserfs/resize.c Normal file
View File

@@ -0,0 +1,210 @@
/*
* Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
*/
/*
* Written by Alexander Zarochentcev.
*
* The kernel part of the (on-line) reiserfs resizer.
*/
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/vmalloc.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/reiserfs_fs.h>
#include <linux/reiserfs_fs_sb.h>
#include <linux/buffer_head.h>
int reiserfs_resize(struct super_block *s, unsigned long block_count_new)
{
int err = 0;
struct reiserfs_super_block *sb;
struct reiserfs_bitmap_info *bitmap;
struct reiserfs_bitmap_info *info;
struct reiserfs_bitmap_info *old_bitmap = SB_AP_BITMAP(s);
struct buffer_head *bh;
struct reiserfs_transaction_handle th;
unsigned int bmap_nr_new, bmap_nr;
unsigned int block_r_new, block_r;
struct reiserfs_list_bitmap *jb;
struct reiserfs_list_bitmap jbitmap[JOURNAL_NUM_BITMAPS];
unsigned long int block_count, free_blocks;
int i;
int copy_size;
sb = SB_DISK_SUPER_BLOCK(s);
if (SB_BLOCK_COUNT(s) >= block_count_new) {
printk("can\'t shrink filesystem on-line\n");
return -EINVAL;
}
/* check the device size */
bh = sb_bread(s, block_count_new - 1);
if (!bh) {
printk("reiserfs_resize: can\'t read last block\n");
return -EINVAL;
}
bforget(bh);
/* old disk layout detection; those partitions can be mounted, but
* cannot be resized */
if (SB_BUFFER_WITH_SB(s)->b_blocknr * SB_BUFFER_WITH_SB(s)->b_size
!= REISERFS_DISK_OFFSET_IN_BYTES) {
printk
("reiserfs_resize: unable to resize a reiserfs without distributed bitmap (fs version < 3.5.12)\n");
return -ENOTSUPP;
}
/* count used bits in last bitmap block */
block_r = SB_BLOCK_COUNT(s) -
(reiserfs_bmap_count(s) - 1) * s->s_blocksize * 8;
/* count bitmap blocks in new fs */
bmap_nr_new = block_count_new / (s->s_blocksize * 8);
block_r_new = block_count_new - bmap_nr_new * s->s_blocksize * 8;
if (block_r_new)
bmap_nr_new++;
else
block_r_new = s->s_blocksize * 8;
/* save old values */
block_count = SB_BLOCK_COUNT(s);
bmap_nr = reiserfs_bmap_count(s);
/* resizing of reiserfs bitmaps (journal and real), if needed */
if (bmap_nr_new > bmap_nr) {
/* reallocate journal bitmaps */
if (reiserfs_allocate_list_bitmaps(s, jbitmap, bmap_nr_new) < 0) {
printk
("reiserfs_resize: unable to allocate memory for journal bitmaps\n");
return -ENOMEM;
}
/* the new journal bitmaps are zero filled, now we copy in the bitmap
** node pointers from the old journal bitmap structs, and then
** transfer the new data structures into the journal struct.
**
** using the copy_size var below allows this code to work for
** both shrinking and expanding the FS.
*/
copy_size = bmap_nr_new < bmap_nr ? bmap_nr_new : bmap_nr;
copy_size =
copy_size * sizeof(struct reiserfs_list_bitmap_node *);
for (i = 0; i < JOURNAL_NUM_BITMAPS; i++) {
struct reiserfs_bitmap_node **node_tmp;
jb = SB_JOURNAL(s)->j_list_bitmap + i;
memcpy(jbitmap[i].bitmaps, jb->bitmaps, copy_size);
/* just in case vfree schedules on us, copy the new
** pointer into the journal struct before freeing the
** old one
*/
node_tmp = jb->bitmaps;
jb->bitmaps = jbitmap[i].bitmaps;
vfree(node_tmp);
}
/* allocate additional bitmap blocks, reallocate array of bitmap
* block pointers */
bitmap =
vmalloc(sizeof(struct reiserfs_bitmap_info) * bmap_nr_new);
if (!bitmap) {
/* Journal bitmaps are still supersized, but the memory isn't
* leaked, so I guess it's ok */
printk("reiserfs_resize: unable to allocate memory.\n");
return -ENOMEM;
}
memset(bitmap, 0,
sizeof(struct reiserfs_bitmap_info) * bmap_nr_new);
for (i = 0; i < bmap_nr; i++)
bitmap[i] = old_bitmap[i];
/* This doesn't go through the journal, but it doesn't have to.
* The changes are still atomic: We're synced up when the journal
* transaction begins, and the new bitmaps don't matter if the
* transaction fails. */
for (i = bmap_nr; i < bmap_nr_new; i++) {
/* don't use read_bitmap_block since it will cache
* the uninitialized bitmap */
bh = sb_bread(s, i * s->s_blocksize * 8);
if (!bh) {
vfree(bitmap);
return -EIO;
}
memset(bh->b_data, 0, sb_blocksize(sb));
reiserfs_test_and_set_le_bit(0, bh->b_data);
reiserfs_cache_bitmap_metadata(s, bh, bitmap + i);
set_buffer_uptodate(bh);
mark_buffer_dirty(bh);
sync_dirty_buffer(bh);
// update bitmap_info stuff
bitmap[i].free_count = sb_blocksize(sb) * 8 - 1;
brelse(bh);
}
/* free old bitmap blocks array */
SB_AP_BITMAP(s) = bitmap;
vfree(old_bitmap);
}
/* begin transaction, if there was an error, it's fine. Yes, we have
* incorrect bitmaps now, but none of it is ever going to touch the
* disk anyway. */
err = journal_begin(&th, s, 10);
if (err)
return err;
/* Extend old last bitmap block - new blocks have been made available */
info = SB_AP_BITMAP(s) + bmap_nr - 1;
bh = reiserfs_read_bitmap_block(s, bmap_nr - 1);
if (!bh) {
int jerr = journal_end(&th, s, 10);
if (jerr)
return jerr;
return -EIO;
}
reiserfs_prepare_for_journal(s, bh, 1);
for (i = block_r; i < s->s_blocksize * 8; i++)
reiserfs_test_and_clear_le_bit(i, bh->b_data);
info->free_count += s->s_blocksize * 8 - block_r;
journal_mark_dirty(&th, s, bh);
brelse(bh);
/* Correct new last bitmap block - It may not be full */
info = SB_AP_BITMAP(s) + bmap_nr_new - 1;
bh = reiserfs_read_bitmap_block(s, bmap_nr_new - 1);
if (!bh) {
int jerr = journal_end(&th, s, 10);
if (jerr)
return jerr;
return -EIO;
}
reiserfs_prepare_for_journal(s, bh, 1);
for (i = block_r_new; i < s->s_blocksize * 8; i++)
reiserfs_test_and_set_le_bit(i, bh->b_data);
journal_mark_dirty(&th, s, bh);
brelse(bh);
info->free_count -= s->s_blocksize * 8 - block_r_new;
/* update super */
reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1);
free_blocks = SB_FREE_BLOCKS(s);
PUT_SB_FREE_BLOCKS(s,
free_blocks + (block_count_new - block_count -
(bmap_nr_new - bmap_nr)));
PUT_SB_BLOCK_COUNT(s, block_count_new);
PUT_SB_BMAP_NR(s, bmap_would_wrap(bmap_nr_new) ? : bmap_nr_new);
s->s_dirt = 1;
journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB(s));
SB_JOURNAL(s)->j_must_wait = 1;
return journal_end(&th, s, 10);
}

2081
kernel/fs/reiserfs/stree.c Normal file

File diff suppressed because it is too large Load Diff

2236
kernel/fs/reiserfs/super.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,280 @@
/*
* Copyright 1999 Hans Reiser, see reiserfs/README for licensing and copyright details
*/
#include <linux/time.h>
#include <linux/pagemap.h>
#include <linux/buffer_head.h>
#include <linux/reiserfs_fs.h>
/* access to tail : when one is going to read tail it must make sure, that is not running.
direct2indirect and indirect2direct can not run concurrently */
/* Converts direct items to an unformatted node. Panics if file has no
tail. -ENOSPC if no disk space for conversion */
/* path points to first direct item of the file regarless of how many of
them are there */
int direct2indirect(struct reiserfs_transaction_handle *th, struct inode *inode,
struct treepath *path, struct buffer_head *unbh,
loff_t tail_offset)
{
struct super_block *sb = inode->i_sb;
struct buffer_head *up_to_date_bh;
struct item_head *p_le_ih = PATH_PITEM_HEAD(path);
unsigned long total_tail = 0;
struct cpu_key end_key; /* Key to search for the last byte of the
converted item. */
struct item_head ind_ih; /* new indirect item to be inserted or
key of unfm pointer to be pasted */
int blk_size, retval; /* returned value for reiserfs_insert_item and clones */
unp_t unfm_ptr; /* Handle on an unformatted node
that will be inserted in the
tree. */
BUG_ON(!th->t_trans_id);
REISERFS_SB(sb)->s_direct2indirect++;
blk_size = sb->s_blocksize;
/* and key to search for append or insert pointer to the new
unformatted node. */
copy_item_head(&ind_ih, p_le_ih);
set_le_ih_k_offset(&ind_ih, tail_offset);
set_le_ih_k_type(&ind_ih, TYPE_INDIRECT);
/* Set the key to search for the place for new unfm pointer */
make_cpu_key(&end_key, inode, tail_offset, TYPE_INDIRECT, 4);
/* FIXME: we could avoid this */
if (search_for_position_by_key(sb, &end_key, path) == POSITION_FOUND) {
reiserfs_error(sb, "PAP-14030",
"pasted or inserted byte exists in "
"the tree %K. Use fsck to repair.", &end_key);
pathrelse(path);
return -EIO;
}
p_le_ih = PATH_PITEM_HEAD(path);
unfm_ptr = cpu_to_le32(unbh->b_blocknr);
if (is_statdata_le_ih(p_le_ih)) {
/* Insert new indirect item. */
set_ih_free_space(&ind_ih, 0); /* delete at nearest future */
put_ih_item_len(&ind_ih, UNFM_P_SIZE);
PATH_LAST_POSITION(path)++;
retval =
reiserfs_insert_item(th, path, &end_key, &ind_ih, inode,
(char *)&unfm_ptr);
} else {
/* Paste into last indirect item of an object. */
retval = reiserfs_paste_into_item(th, path, &end_key, inode,
(char *)&unfm_ptr,
UNFM_P_SIZE);
}
if (retval) {
return retval;
}
// note: from here there are two keys which have matching first
// three key components. They only differ by the fourth one.
/* Set the key to search for the direct items of the file */
make_cpu_key(&end_key, inode, max_reiserfs_offset(inode), TYPE_DIRECT,
4);
/* Move bytes from the direct items to the new unformatted node
and delete them. */
while (1) {
int tail_size;
/* end_key.k_offset is set so, that we will always have found
last item of the file */
if (search_for_position_by_key(sb, &end_key, path) ==
POSITION_FOUND)
reiserfs_panic(sb, "PAP-14050",
"direct item (%K) not found", &end_key);
p_le_ih = PATH_PITEM_HEAD(path);
RFALSE(!is_direct_le_ih(p_le_ih),
"vs-14055: direct item expected(%K), found %h",
&end_key, p_le_ih);
tail_size = (le_ih_k_offset(p_le_ih) & (blk_size - 1))
+ ih_item_len(p_le_ih) - 1;
/* we only send the unbh pointer if the buffer is not up to date.
** this avoids overwriting good data from writepage() with old data
** from the disk or buffer cache
** Special case: unbh->b_page will be NULL if we are coming through
** DIRECT_IO handler here.
*/
if (!unbh->b_page || buffer_uptodate(unbh)
|| PageUptodate(unbh->b_page)) {
up_to_date_bh = NULL;
} else {
up_to_date_bh = unbh;
}
retval = reiserfs_delete_item(th, path, &end_key, inode,
up_to_date_bh);
total_tail += retval;
if (tail_size == retval)
// done: file does not have direct items anymore
break;
}
/* if we've copied bytes from disk into the page, we need to zero
** out the unused part of the block (it was not up to date before)
*/
if (up_to_date_bh) {
unsigned pgoff =
(tail_offset + total_tail - 1) & (PAGE_CACHE_SIZE - 1);
char *kaddr = kmap_atomic(up_to_date_bh->b_page, KM_USER0);
memset(kaddr + pgoff, 0, blk_size - total_tail);
kunmap_atomic(kaddr, KM_USER0);
}
REISERFS_I(inode)->i_first_direct_byte = U32_MAX;
return 0;
}
/* stolen from fs/buffer.c */
void reiserfs_unmap_buffer(struct buffer_head *bh)
{
lock_buffer(bh);
if (buffer_journaled(bh) || buffer_journal_dirty(bh)) {
BUG();
}
clear_buffer_dirty(bh);
/* Remove the buffer from whatever list it belongs to. We are mostly
interested in removing it from per-sb j_dirty_buffers list, to avoid
BUG() on attempt to write not mapped buffer */
if ((!list_empty(&bh->b_assoc_buffers) || bh->b_private) && bh->b_page) {
struct inode *inode = bh->b_page->mapping->host;
struct reiserfs_journal *j = SB_JOURNAL(inode->i_sb);
spin_lock(&j->j_dirty_buffers_lock);
list_del_init(&bh->b_assoc_buffers);
reiserfs_free_jh(bh);
spin_unlock(&j->j_dirty_buffers_lock);
}
clear_buffer_mapped(bh);
clear_buffer_req(bh);
clear_buffer_new(bh);
bh->b_bdev = NULL;
unlock_buffer(bh);
}
/* this first locks inode (neither reads nor sync are permitted),
reads tail through page cache, insert direct item. When direct item
inserted successfully inode is left locked. Return value is always
what we expect from it (number of cut bytes). But when tail remains
in the unformatted node, we set mode to SKIP_BALANCING and unlock
inode */
int indirect2direct(struct reiserfs_transaction_handle *th,
struct inode *inode, struct page *page,
struct treepath *path, /* path to the indirect item. */
const struct cpu_key *item_key, /* Key to look for
* unformatted node
* pointer to be cut. */
loff_t n_new_file_size, /* New file size. */
char *mode)
{
struct super_block *sb = inode->i_sb;
struct item_head s_ih;
unsigned long block_size = sb->s_blocksize;
char *tail;
int tail_len, round_tail_len;
loff_t pos, pos1; /* position of first byte of the tail */
struct cpu_key key;
BUG_ON(!th->t_trans_id);
REISERFS_SB(sb)->s_indirect2direct++;
*mode = M_SKIP_BALANCING;
/* store item head path points to. */
copy_item_head(&s_ih, PATH_PITEM_HEAD(path));
tail_len = (n_new_file_size & (block_size - 1));
if (get_inode_sd_version(inode) == STAT_DATA_V2)
round_tail_len = ROUND_UP(tail_len);
else
round_tail_len = tail_len;
pos =
le_ih_k_offset(&s_ih) - 1 + (ih_item_len(&s_ih) / UNFM_P_SIZE -
1) * sb->s_blocksize;
pos1 = pos;
// we are protected by i_mutex. The tail can not disapper, not
// append can be done either
// we are in truncate or packing tail in file_release
tail = (char *)kmap(page); /* this can schedule */
if (path_changed(&s_ih, path)) {
/* re-search indirect item */
if (search_for_position_by_key(sb, item_key, path)
== POSITION_NOT_FOUND)
reiserfs_panic(sb, "PAP-5520",
"item to be converted %K does not exist",
item_key);
copy_item_head(&s_ih, PATH_PITEM_HEAD(path));
#ifdef CONFIG_REISERFS_CHECK
pos = le_ih_k_offset(&s_ih) - 1 +
(ih_item_len(&s_ih) / UNFM_P_SIZE -
1) * sb->s_blocksize;
if (pos != pos1)
reiserfs_panic(sb, "vs-5530", "tail position "
"changed while we were reading it");
#endif
}
/* Set direct item header to insert. */
make_le_item_head(&s_ih, NULL, get_inode_item_key_version(inode),
pos1 + 1, TYPE_DIRECT, round_tail_len,
0xffff /*ih_free_space */ );
/* we want a pointer to the first byte of the tail in the page.
** the page was locked and this part of the page was up to date when
** indirect2direct was called, so we know the bytes are still valid
*/
tail = tail + (pos & (PAGE_CACHE_SIZE - 1));
PATH_LAST_POSITION(path)++;
key = *item_key;
set_cpu_key_k_type(&key, TYPE_DIRECT);
key.key_length = 4;
/* Insert tail as new direct item in the tree */
if (reiserfs_insert_item(th, path, &key, &s_ih, inode,
tail ? tail : NULL) < 0) {
/* No disk memory. So we can not convert last unformatted node
to the direct item. In this case we used to adjust
indirect items's ih_free_space. Now ih_free_space is not
used, it would be ideal to write zeros to corresponding
unformatted node. For now i_size is considered as guard for
going out of file size */
kunmap(page);
return block_size - round_tail_len;
}
kunmap(page);
/* make sure to get the i_blocks changes from reiserfs_insert_item */
reiserfs_update_sd(th, inode);
// note: we have now the same as in above direct2indirect
// conversion: there are two keys which have matching first three
// key components. They only differ by the fouhth one.
/* We have inserted new direct item and must remove last
unformatted node. */
*mode = M_CUT;
/* we store position of first direct item in the in-core inode */
/* mark_file_with_tail (inode, pos1 + 1); */
REISERFS_I(inode)->i_first_direct_byte = pos1 + 1;
return block_size - round_tail_len;
}

1031
kernel/fs/reiserfs/xattr.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,557 @@
#include <linux/capability.h>
#include <linux/fs.h>
#include <linux/posix_acl.h>
#include <linux/reiserfs_fs.h>
#include <linux/errno.h>
#include <linux/pagemap.h>
#include <linux/xattr.h>
#include <linux/posix_acl_xattr.h>
#include <linux/reiserfs_xattr.h>
#include <linux/reiserfs_acl.h>
#include <asm/uaccess.h>
static int reiserfs_set_acl(struct reiserfs_transaction_handle *th,
struct inode *inode, int type,
struct posix_acl *acl);
static int
xattr_set_acl(struct inode *inode, int type, const void *value, size_t size)
{
struct posix_acl *acl;
int error, error2;
struct reiserfs_transaction_handle th;
size_t jcreate_blocks;
if (!reiserfs_posixacl(inode->i_sb))
return -EOPNOTSUPP;
if (!is_owner_or_cap(inode))
return -EPERM;
if (value) {
acl = posix_acl_from_xattr(value, size);
if (IS_ERR(acl)) {
return PTR_ERR(acl);
} else if (acl) {
error = posix_acl_valid(acl);
if (error)
goto release_and_out;
}
} else
acl = NULL;
/* Pessimism: We can't assume that anything from the xattr root up
* has been created. */
jcreate_blocks = reiserfs_xattr_jcreate_nblocks(inode) +
reiserfs_xattr_nblocks(inode, size) * 2;
reiserfs_write_lock(inode->i_sb);
error = journal_begin(&th, inode->i_sb, jcreate_blocks);
if (error == 0) {
error = reiserfs_set_acl(&th, inode, type, acl);
error2 = journal_end(&th, inode->i_sb, jcreate_blocks);
if (error2)
error = error2;
}
reiserfs_write_unlock(inode->i_sb);
release_and_out:
posix_acl_release(acl);
return error;
}
static int
xattr_get_acl(struct inode *inode, int type, void *buffer, size_t size)
{
struct posix_acl *acl;
int error;
if (!reiserfs_posixacl(inode->i_sb))
return -EOPNOTSUPP;
acl = reiserfs_get_acl(inode, type);
if (IS_ERR(acl))
return PTR_ERR(acl);
if (acl == NULL)
return -ENODATA;
error = posix_acl_to_xattr(acl, buffer, size);
posix_acl_release(acl);
return error;
}
/*
* Convert from filesystem to in-memory representation.
*/
static struct posix_acl *posix_acl_from_disk(const void *value, size_t size)
{
const char *end = (char *)value + size;
int n, count;
struct posix_acl *acl;
if (!value)
return NULL;
if (size < sizeof(reiserfs_acl_header))
return ERR_PTR(-EINVAL);
if (((reiserfs_acl_header *) value)->a_version !=
cpu_to_le32(REISERFS_ACL_VERSION))
return ERR_PTR(-EINVAL);
value = (char *)value + sizeof(reiserfs_acl_header);
count = reiserfs_acl_count(size);
if (count < 0)
return ERR_PTR(-EINVAL);
if (count == 0)
return NULL;
acl = posix_acl_alloc(count, GFP_NOFS);
if (!acl)
return ERR_PTR(-ENOMEM);
for (n = 0; n < count; n++) {
reiserfs_acl_entry *entry = (reiserfs_acl_entry *) value;
if ((char *)value + sizeof(reiserfs_acl_entry_short) > end)
goto fail;
acl->a_entries[n].e_tag = le16_to_cpu(entry->e_tag);
acl->a_entries[n].e_perm = le16_to_cpu(entry->e_perm);
switch (acl->a_entries[n].e_tag) {
case ACL_USER_OBJ:
case ACL_GROUP_OBJ:
case ACL_MASK:
case ACL_OTHER:
value = (char *)value +
sizeof(reiserfs_acl_entry_short);
acl->a_entries[n].e_id = ACL_UNDEFINED_ID;
break;
case ACL_USER:
case ACL_GROUP:
value = (char *)value + sizeof(reiserfs_acl_entry);
if ((char *)value > end)
goto fail;
acl->a_entries[n].e_id = le32_to_cpu(entry->e_id);
break;
default:
goto fail;
}
}
if (value != end)
goto fail;
return acl;
fail:
posix_acl_release(acl);
return ERR_PTR(-EINVAL);
}
/*
* Convert from in-memory to filesystem representation.
*/
static void *posix_acl_to_disk(const struct posix_acl *acl, size_t * size)
{
reiserfs_acl_header *ext_acl;
char *e;
int n;
*size = reiserfs_acl_size(acl->a_count);
ext_acl = kmalloc(sizeof(reiserfs_acl_header) +
acl->a_count *
sizeof(reiserfs_acl_entry),
GFP_NOFS);
if (!ext_acl)
return ERR_PTR(-ENOMEM);
ext_acl->a_version = cpu_to_le32(REISERFS_ACL_VERSION);
e = (char *)ext_acl + sizeof(reiserfs_acl_header);
for (n = 0; n < acl->a_count; n++) {
reiserfs_acl_entry *entry = (reiserfs_acl_entry *) e;
entry->e_tag = cpu_to_le16(acl->a_entries[n].e_tag);
entry->e_perm = cpu_to_le16(acl->a_entries[n].e_perm);
switch (acl->a_entries[n].e_tag) {
case ACL_USER:
case ACL_GROUP:
entry->e_id = cpu_to_le32(acl->a_entries[n].e_id);
e += sizeof(reiserfs_acl_entry);
break;
case ACL_USER_OBJ:
case ACL_GROUP_OBJ:
case ACL_MASK:
case ACL_OTHER:
e += sizeof(reiserfs_acl_entry_short);
break;
default:
goto fail;
}
}
return (char *)ext_acl;
fail:
kfree(ext_acl);
return ERR_PTR(-EINVAL);
}
/*
* Inode operation get_posix_acl().
*
* inode->i_mutex: down
* BKL held [before 2.5.x]
*/
struct posix_acl *reiserfs_get_acl(struct inode *inode, int type)
{
char *name, *value;
struct posix_acl *acl;
int size;
int retval;
acl = get_cached_acl(inode, type);
if (acl != ACL_NOT_CACHED)
return acl;
switch (type) {
case ACL_TYPE_ACCESS:
name = POSIX_ACL_XATTR_ACCESS;
break;
case ACL_TYPE_DEFAULT:
name = POSIX_ACL_XATTR_DEFAULT;
break;
default:
BUG();
}
size = reiserfs_xattr_get(inode, name, NULL, 0);
if (size < 0) {
if (size == -ENODATA || size == -ENOSYS) {
set_cached_acl(inode, type, NULL);
return NULL;
}
return ERR_PTR(size);
}
value = kmalloc(size, GFP_NOFS);
if (!value)
return ERR_PTR(-ENOMEM);
retval = reiserfs_xattr_get(inode, name, value, size);
if (retval == -ENODATA || retval == -ENOSYS) {
/* This shouldn't actually happen as it should have
been caught above.. but just in case */
acl = NULL;
} else if (retval < 0) {
acl = ERR_PTR(retval);
} else {
acl = posix_acl_from_disk(value, retval);
}
if (!IS_ERR(acl))
set_cached_acl(inode, type, acl);
kfree(value);
return acl;
}
/*
* Inode operation set_posix_acl().
*
* inode->i_mutex: down
* BKL held [before 2.5.x]
*/
static int
reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode,
int type, struct posix_acl *acl)
{
char *name;
void *value = NULL;
size_t size = 0;
int error;
if (S_ISLNK(inode->i_mode))
return -EOPNOTSUPP;
switch (type) {
case ACL_TYPE_ACCESS:
name = POSIX_ACL_XATTR_ACCESS;
if (acl) {
mode_t mode = inode->i_mode;
error = posix_acl_equiv_mode(acl, &mode);
if (error < 0)
return error;
else {
inode->i_mode = mode;
if (error == 0)
acl = NULL;
}
}
break;
case ACL_TYPE_DEFAULT:
name = POSIX_ACL_XATTR_DEFAULT;
if (!S_ISDIR(inode->i_mode))
return acl ? -EACCES : 0;
break;
default:
return -EINVAL;
}
if (acl) {
value = posix_acl_to_disk(acl, &size);
if (IS_ERR(value))
return (int)PTR_ERR(value);
}
error = reiserfs_xattr_set_handle(th, inode, name, value, size, 0);
/*
* Ensure that the inode gets dirtied if we're only using
* the mode bits and an old ACL didn't exist. We don't need
* to check if the inode is hashed here since we won't get
* called by reiserfs_inherit_default_acl().
*/
if (error == -ENODATA) {
error = 0;
if (type == ACL_TYPE_ACCESS) {
inode->i_ctime = CURRENT_TIME_SEC;
mark_inode_dirty(inode);
}
}
kfree(value);
if (!error)
set_cached_acl(inode, type, acl);
return error;
}
/* dir->i_mutex: locked,
* inode is new and not released into the wild yet */
int
reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th,
struct inode *dir, struct dentry *dentry,
struct inode *inode)
{
struct posix_acl *acl;
int err = 0;
/* ACLs only get applied to files and directories */
if (S_ISLNK(inode->i_mode))
return 0;
/* ACLs can only be used on "new" objects, so if it's an old object
* there is nothing to inherit from */
if (get_inode_sd_version(dir) == STAT_DATA_V1)
goto apply_umask;
/* Don't apply ACLs to objects in the .reiserfs_priv tree.. This
* would be useless since permissions are ignored, and a pain because
* it introduces locking cycles */
if (IS_PRIVATE(dir)) {
inode->i_flags |= S_PRIVATE;
goto apply_umask;
}
acl = reiserfs_get_acl(dir, ACL_TYPE_DEFAULT);
if (IS_ERR(acl))
return PTR_ERR(acl);
if (acl) {
struct posix_acl *acl_copy;
mode_t mode = inode->i_mode;
int need_acl;
/* Copy the default ACL to the default ACL of a new directory */
if (S_ISDIR(inode->i_mode)) {
err = reiserfs_set_acl(th, inode, ACL_TYPE_DEFAULT,
acl);
if (err)
goto cleanup;
}
/* Now we reconcile the new ACL and the mode,
potentially modifying both */
acl_copy = posix_acl_clone(acl, GFP_NOFS);
if (!acl_copy) {
err = -ENOMEM;
goto cleanup;
}
need_acl = posix_acl_create_masq(acl_copy, &mode);
if (need_acl >= 0) {
if (mode != inode->i_mode) {
inode->i_mode = mode;
}
/* If we need an ACL.. */
if (need_acl > 0) {
err = reiserfs_set_acl(th, inode,
ACL_TYPE_ACCESS,
acl_copy);
if (err)
goto cleanup_copy;
}
}
cleanup_copy:
posix_acl_release(acl_copy);
cleanup:
posix_acl_release(acl);
} else {
apply_umask:
/* no ACL, apply umask */
inode->i_mode &= ~current_umask();
}
return err;
}
/* This is used to cache the default acl before a new object is created.
* The biggest reason for this is to get an idea of how many blocks will
* actually be required for the create operation if we must inherit an ACL.
* An ACL write can add up to 3 object creations and an additional file write
* so we'd prefer not to reserve that many blocks in the journal if we can.
* It also has the advantage of not loading the ACL with a transaction open,
* this may seem silly, but if the owner of the directory is doing the
* creation, the ACL may not be loaded since the permissions wouldn't require
* it.
* We return the number of blocks required for the transaction.
*/
int reiserfs_cache_default_acl(struct inode *inode)
{
struct posix_acl *acl;
int nblocks = 0;
if (IS_PRIVATE(inode))
return 0;
acl = reiserfs_get_acl(inode, ACL_TYPE_DEFAULT);
if (acl && !IS_ERR(acl)) {
int size = reiserfs_acl_size(acl->a_count);
/* Other xattrs can be created during inode creation. We don't
* want to claim too many blocks, so we check to see if we
* we need to create the tree to the xattrs, and then we
* just want two files. */
nblocks = reiserfs_xattr_jcreate_nblocks(inode);
nblocks += JOURNAL_BLOCKS_PER_OBJECT(inode->i_sb);
REISERFS_I(inode)->i_flags |= i_has_xattr_dir;
/* We need to account for writes + bitmaps for two files */
nblocks += reiserfs_xattr_nblocks(inode, size) * 4;
posix_acl_release(acl);
}
return nblocks;
}
int reiserfs_acl_chmod(struct inode *inode)
{
struct posix_acl *acl, *clone;
int error;
if (S_ISLNK(inode->i_mode))
return -EOPNOTSUPP;
if (get_inode_sd_version(inode) == STAT_DATA_V1 ||
!reiserfs_posixacl(inode->i_sb)) {
return 0;
}
acl = reiserfs_get_acl(inode, ACL_TYPE_ACCESS);
if (!acl)
return 0;
if (IS_ERR(acl))
return PTR_ERR(acl);
clone = posix_acl_clone(acl, GFP_NOFS);
posix_acl_release(acl);
if (!clone)
return -ENOMEM;
error = posix_acl_chmod_masq(clone, inode->i_mode);
if (!error) {
struct reiserfs_transaction_handle th;
size_t size = reiserfs_xattr_nblocks(inode,
reiserfs_acl_size(clone->a_count));
reiserfs_write_lock(inode->i_sb);
error = journal_begin(&th, inode->i_sb, size * 2);
if (!error) {
int error2;
error = reiserfs_set_acl(&th, inode, ACL_TYPE_ACCESS,
clone);
error2 = journal_end(&th, inode->i_sb, size * 2);
if (error2)
error = error2;
}
reiserfs_write_unlock(inode->i_sb);
}
posix_acl_release(clone);
return error;
}
static int
posix_acl_access_get(struct inode *inode, const char *name,
void *buffer, size_t size)
{
if (strlen(name) != sizeof(POSIX_ACL_XATTR_ACCESS) - 1)
return -EINVAL;
return xattr_get_acl(inode, ACL_TYPE_ACCESS, buffer, size);
}
static int
posix_acl_access_set(struct inode *inode, const char *name,
const void *value, size_t size, int flags)
{
if (strlen(name) != sizeof(POSIX_ACL_XATTR_ACCESS) - 1)
return -EINVAL;
return xattr_set_acl(inode, ACL_TYPE_ACCESS, value, size);
}
static size_t posix_acl_access_list(struct inode *inode, char *list,
size_t list_size, const char *name,
size_t name_len)
{
const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS);
if (!reiserfs_posixacl(inode->i_sb))
return 0;
if (list && size <= list_size)
memcpy(list, POSIX_ACL_XATTR_ACCESS, size);
return size;
}
struct xattr_handler reiserfs_posix_acl_access_handler = {
.prefix = POSIX_ACL_XATTR_ACCESS,
.get = posix_acl_access_get,
.set = posix_acl_access_set,
.list = posix_acl_access_list,
};
static int
posix_acl_default_get(struct inode *inode, const char *name,
void *buffer, size_t size)
{
if (strlen(name) != sizeof(POSIX_ACL_XATTR_DEFAULT) - 1)
return -EINVAL;
return xattr_get_acl(inode, ACL_TYPE_DEFAULT, buffer, size);
}
static int
posix_acl_default_set(struct inode *inode, const char *name,
const void *value, size_t size, int flags)
{
if (strlen(name) != sizeof(POSIX_ACL_XATTR_DEFAULT) - 1)
return -EINVAL;
return xattr_set_acl(inode, ACL_TYPE_DEFAULT, value, size);
}
static size_t posix_acl_default_list(struct inode *inode, char *list,
size_t list_size, const char *name,
size_t name_len)
{
const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT);
if (!reiserfs_posixacl(inode->i_sb))
return 0;
if (list && size <= list_size)
memcpy(list, POSIX_ACL_XATTR_DEFAULT, size);
return size;
}
struct xattr_handler reiserfs_posix_acl_default_handler = {
.prefix = POSIX_ACL_XATTR_DEFAULT,
.get = posix_acl_default_get,
.set = posix_acl_default_set,
.list = posix_acl_default_list,
};

View File

@@ -0,0 +1,117 @@
#include <linux/reiserfs_fs.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/pagemap.h>
#include <linux/xattr.h>
#include <linux/reiserfs_xattr.h>
#include <linux/security.h>
#include <asm/uaccess.h>
static int
security_get(struct inode *inode, const char *name, void *buffer, size_t size)
{
if (strlen(name) < sizeof(XATTR_SECURITY_PREFIX))
return -EINVAL;
if (IS_PRIVATE(inode))
return -EPERM;
return reiserfs_xattr_get(inode, name, buffer, size);
}
static int
security_set(struct inode *inode, const char *name, const void *buffer,
size_t size, int flags)
{
if (strlen(name) < sizeof(XATTR_SECURITY_PREFIX))
return -EINVAL;
if (IS_PRIVATE(inode))
return -EPERM;
return reiserfs_xattr_set(inode, name, buffer, size, flags);
}
static size_t security_list(struct inode *inode, char *list, size_t list_len,
const char *name, size_t namelen)
{
const size_t len = namelen + 1;
if (IS_PRIVATE(inode))
return 0;
if (list && len <= list_len) {
memcpy(list, name, namelen);
list[namelen] = '\0';
}
return len;
}
/* Initializes the security context for a new inode and returns the number
* of blocks needed for the transaction. If successful, reiserfs_security
* must be released using reiserfs_security_free when the caller is done. */
int reiserfs_security_init(struct inode *dir, struct inode *inode,
struct reiserfs_security_handle *sec)
{
int blocks = 0;
int error;
sec->name = NULL;
/* Don't add selinux attributes on xattrs - they'll never get used */
if (IS_PRIVATE(dir))
return 0;
error = security_inode_init_security(inode, dir, &sec->name,
&sec->value, &sec->length);
if (error) {
if (error == -EOPNOTSUPP)
error = 0;
sec->name = NULL;
sec->value = NULL;
sec->length = 0;
return error;
}
if (sec->length && reiserfs_xattrs_initialized(inode->i_sb)) {
blocks = reiserfs_xattr_jcreate_nblocks(inode) +
reiserfs_xattr_nblocks(inode, sec->length);
/* We don't want to count the directories twice if we have
* a default ACL. */
REISERFS_I(inode)->i_flags |= i_has_xattr_dir;
}
return blocks;
}
int reiserfs_security_write(struct reiserfs_transaction_handle *th,
struct inode *inode,
struct reiserfs_security_handle *sec)
{
int error;
if (strlen(sec->name) < sizeof(XATTR_SECURITY_PREFIX))
return -EINVAL;
error = reiserfs_xattr_set_handle(th, inode, sec->name, sec->value,
sec->length, XATTR_CREATE);
if (error == -ENODATA || error == -EOPNOTSUPP)
error = 0;
return error;
}
void reiserfs_security_free(struct reiserfs_security_handle *sec)
{
kfree(sec->name);
kfree(sec->value);
sec->name = NULL;
sec->value = NULL;
}
struct xattr_handler reiserfs_xattr_security_handler = {
.prefix = XATTR_SECURITY_PREFIX,
.get = security_get,
.set = security_set,
.list = security_list,
};

View File

@@ -0,0 +1,55 @@
#include <linux/reiserfs_fs.h>
#include <linux/capability.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/pagemap.h>
#include <linux/xattr.h>
#include <linux/reiserfs_xattr.h>
#include <asm/uaccess.h>
static int
trusted_get(struct inode *inode, const char *name, void *buffer, size_t size)
{
if (strlen(name) < sizeof(XATTR_TRUSTED_PREFIX))
return -EINVAL;
if (!capable(CAP_SYS_ADMIN) || IS_PRIVATE(inode))
return -EPERM;
return reiserfs_xattr_get(inode, name, buffer, size);
}
static int
trusted_set(struct inode *inode, const char *name, const void *buffer,
size_t size, int flags)
{
if (strlen(name) < sizeof(XATTR_TRUSTED_PREFIX))
return -EINVAL;
if (!capable(CAP_SYS_ADMIN) || IS_PRIVATE(inode))
return -EPERM;
return reiserfs_xattr_set(inode, name, buffer, size, flags);
}
static size_t trusted_list(struct inode *inode, char *list, size_t list_size,
const char *name, size_t name_len)
{
const size_t len = name_len + 1;
if (!capable(CAP_SYS_ADMIN) || IS_PRIVATE(inode))
return 0;
if (list && len <= list_size) {
memcpy(list, name, name_len);
list[name_len] = '\0';
}
return len;
}
struct xattr_handler reiserfs_xattr_trusted_handler = {
.prefix = XATTR_TRUSTED_PREFIX,
.get = trusted_get,
.set = trusted_set,
.list = trusted_list,
};

View File

@@ -0,0 +1,51 @@
#include <linux/reiserfs_fs.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/pagemap.h>
#include <linux/xattr.h>
#include <linux/reiserfs_xattr.h>
#include <asm/uaccess.h>
static int
user_get(struct inode *inode, const char *name, void *buffer, size_t size)
{
if (strlen(name) < sizeof(XATTR_USER_PREFIX))
return -EINVAL;
if (!reiserfs_xattrs_user(inode->i_sb))
return -EOPNOTSUPP;
return reiserfs_xattr_get(inode, name, buffer, size);
}
static int
user_set(struct inode *inode, const char *name, const void *buffer,
size_t size, int flags)
{
if (strlen(name) < sizeof(XATTR_USER_PREFIX))
return -EINVAL;
if (!reiserfs_xattrs_user(inode->i_sb))
return -EOPNOTSUPP;
return reiserfs_xattr_set(inode, name, buffer, size, flags);
}
static size_t user_list(struct inode *inode, char *list, size_t list_size,
const char *name, size_t name_len)
{
const size_t len = name_len + 1;
if (!reiserfs_xattrs_user(inode->i_sb))
return 0;
if (list && len <= list_size) {
memcpy(list, name, name_len);
list[name_len] = '\0';
}
return len;
}
struct xattr_handler reiserfs_xattr_user_handler = {
.prefix = XATTR_USER_PREFIX,
.get = user_get,
.set = user_set,
.list = user_list,
};