Creation of Cybook 2416 (actually Gen4) repository
This commit is contained in:
36
fs/reiserfs/Makefile
Normal file
36
fs/reiserfs/Makefile
Normal 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
|
||||
|
||||
ifeq ($(CONFIG_REISERFS_FS_XATTR),y)
|
||||
reiserfs-objs += xattr.o 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
fs/reiserfs/README
Normal file
161
fs/reiserfs/README
Normal 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....
|
||||
|
||||
1345
fs/reiserfs/bitmap.c
Normal file
1345
fs/reiserfs/bitmap.c
Normal file
File diff suppressed because it is too large
Load Diff
293
fs/reiserfs/dir.c
Normal file
293
fs/reiserfs/dir.c
Normal file
@@ -0,0 +1,293 @@
|
||||
/*
|
||||
* 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/smp_lock.h>
|
||||
#include <linux/buffer_head.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
extern 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 int reiserfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
||||
{
|
||||
struct inode *inode = filp->f_path.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,
|
||||
(filp->f_pos) ? (filp->f_pos) : DOT_OFFSET, TYPE_DIRENTRY,
|
||||
3);
|
||||
next_pos = cpu_key_k_offset(&pos_key);
|
||||
|
||||
/* reiserfs_warning (inode->i_sb, "reiserfs_readdir 1: f_pos = %Ld", filp->f_pos); */
|
||||
|
||||
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_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 (reiserfs_xattrs(inode->i_sb) &&
|
||||
!old_format_only(inode->i_sb) &&
|
||||
filp->f_path.dentry == inode->i_sb->s_root &&
|
||||
REISERFS_SB(inode->i_sb)->priv_root &&
|
||||
REISERFS_SB(inode->i_sb)->priv_root->d_inode
|
||||
&& deh_objectid(deh) ==
|
||||
le32_to_cpu(INODE_PKEY
|
||||
(REISERFS_SB(inode->i_sb)->
|
||||
priv_root->d_inode)->
|
||||
k_objectid)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
d_off = deh_offset(deh);
|
||||
filp->f_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:
|
||||
filp->f_pos = next_pos;
|
||||
pathrelse(&path_to_entry);
|
||||
reiserfs_check_path(&path_to_entry);
|
||||
out:
|
||||
reiserfs_write_unlock(inode->i_sb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
2137
fs/reiserfs/do_balan.c
Normal file
2137
fs/reiserfs/do_balan.c
Normal file
File diff suppressed because it is too large
Load Diff
1567
fs/reiserfs/file.c
Normal file
1567
fs/reiserfs/file.c
Normal file
File diff suppressed because it is too large
Load Diff
2580
fs/reiserfs/fix_node.c
Normal file
2580
fs/reiserfs/fix_node.c
Normal file
File diff suppressed because it is too large
Load Diff
182
fs/reiserfs/hashes.c
Normal file
182
fs/reiserfs/hashes.c
Normal 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;
|
||||
}
|
||||
1089
fs/reiserfs/ibalance.c
Normal file
1089
fs/reiserfs/ibalance.c
Normal file
File diff suppressed because it is too large
Load Diff
3015
fs/reiserfs/inode.c
Normal file
3015
fs/reiserfs/inode.c
Normal file
File diff suppressed because it is too large
Load Diff
198
fs/reiserfs/ioctl.c
Normal file
198
fs/reiserfs/ioctl.c
Normal file
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
|
||||
*/
|
||||
|
||||
#include <linux/capability.h>
|
||||
#include <linux/fs.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>
|
||||
|
||||
static int reiserfs_unpack(struct inode *inode, struct file *filp);
|
||||
|
||||
/*
|
||||
** 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;
|
||||
|
||||
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;
|
||||
|
||||
if (IS_RDONLY(inode))
|
||||
return -EROFS;
|
||||
|
||||
if ((current->fsuid != inode->i_uid)
|
||||
&& !capable(CAP_FOWNER))
|
||||
return -EPERM;
|
||||
|
||||
if (get_user(flags, (int __user *)arg))
|
||||
return -EFAULT;
|
||||
|
||||
if (((flags ^ REISERFS_I(inode)->
|
||||
i_attrs) & (REISERFS_IMMUTABLE_FL |
|
||||
REISERFS_APPEND_FL))
|
||||
&& !capable(CAP_LINUX_IMMUTABLE))
|
||||
return -EPERM;
|
||||
|
||||
if ((flags & REISERFS_NOTAIL_FL) &&
|
||||
S_ISREG(inode->i_mode)) {
|
||||
int result;
|
||||
|
||||
result = reiserfs_unpack(inode, filp);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
sd_attrs_to_i_attrs(flags, inode);
|
||||
REISERFS_I(inode)->i_attrs = flags;
|
||||
inode->i_ctime = CURRENT_TIME_SEC;
|
||||
mark_inode_dirty(inode);
|
||||
return 0;
|
||||
}
|
||||
case REISERFS_IOC_GETVERSION:
|
||||
return put_user(inode->i_generation, (int __user *)arg);
|
||||
case REISERFS_IOC_SETVERSION:
|
||||
if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
|
||||
return -EPERM;
|
||||
if (IS_RDONLY(inode))
|
||||
return -EROFS;
|
||||
if (get_user(inode->i_generation, (int __user *)arg))
|
||||
return -EFAULT;
|
||||
inode->i_ctime = CURRENT_TIME_SEC;
|
||||
mark_inode_dirty(inode);
|
||||
return 0;
|
||||
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
|
||||
|
||||
/*
|
||||
** reiserfs_unpack
|
||||
** Function try to convert tail from direct item into indirect.
|
||||
** It set up nopack attribute in the REISERFS_I(inode)->nopack
|
||||
*/
|
||||
static 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 =
|
||||
mapping->a_ops->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 =
|
||||
mapping->a_ops->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;
|
||||
}
|
||||
750
fs/reiserfs/item_ops.c
Normal file
750
fs/reiserfs/item_ops.c
Normal file
@@ -0,0 +1,750 @@
|
||||
/*
|
||||
* 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, "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, "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, "indirect_print_item: 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, "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: direntry_bytes_number: "
|
||||
"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: set_entry_sizes: (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, "free space %d, entry_count %d\n", 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, "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) */
|
||||
};
|
||||
4281
fs/reiserfs/journal.c
Normal file
4281
fs/reiserfs/journal.c
Normal file
File diff suppressed because it is too large
Load Diff
1301
fs/reiserfs/lbalance.c
Normal file
1301
fs/reiserfs/lbalance.c
Normal file
File diff suppressed because it is too large
Load Diff
1575
fs/reiserfs/namei.c
Normal file
1575
fs/reiserfs/namei.c
Normal file
File diff suppressed because it is too large
Load Diff
206
fs/reiserfs/objectid.c
Normal file
206
fs/reiserfs/objectid.c
Normal file
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* 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: check_objectid_map: 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, "%s: no more object ids", __FUNCTION__);
|
||||
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]++;
|
||||
map[i] = cpu_to_le32(le32_to_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]--;
|
||||
map[i + 1] =
|
||||
cpu_to_le32(le32_to_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_warning(s,
|
||||
"vs-15011: reiserfs_release_objectid: 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;
|
||||
}
|
||||
748
fs/reiserfs/prints.c
Normal file
748
fs/reiserfs/prints.c
Normal file
@@ -0,0 +1,748 @@
|
||||
/*
|
||||
* 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, int *skip)
|
||||
{
|
||||
char *k = fmt;
|
||||
|
||||
*skip = 0;
|
||||
|
||||
while ((k = strchr(k, '%')) != NULL) {
|
||||
if (k[1] == 'k' || k[1] == 'K' || k[1] == 'h' || k[1] == 't' ||
|
||||
k[1] == 'z' || k[1] == 'b' || k[1] == 'y' || k[1] == 'a') {
|
||||
*what = k[1];
|
||||
break;
|
||||
}
|
||||
(*skip)++;
|
||||
k++;
|
||||
}
|
||||
return k;
|
||||
}
|
||||
|
||||
/* 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 void prepare_error_buf(const char *fmt, va_list args)
|
||||
{
|
||||
char *fmt1 = fmt_buf;
|
||||
char *k;
|
||||
char *p = error_buf;
|
||||
int i, j, what, skip;
|
||||
|
||||
strcpy(fmt1, fmt);
|
||||
|
||||
while ((k = is_there_reiserfs_struct(fmt1, &what, &skip)) != NULL) {
|
||||
*k = 0;
|
||||
|
||||
p += vsprintf(p, fmt1, args);
|
||||
|
||||
for (i = 0; i < skip; i++)
|
||||
j = va_arg(args, int);
|
||||
|
||||
switch (what) {
|
||||
case 'k':
|
||||
sprintf_le_key(p, va_arg(args, struct 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);
|
||||
|
||||
}
|
||||
|
||||
/* 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 *fmt, ...)
|
||||
{
|
||||
do_reiserfs_warning(fmt);
|
||||
if (sb)
|
||||
printk(KERN_WARNING "ReiserFS: %s: warning: %s\n",
|
||||
reiserfs_bdevname(sb), error_buf);
|
||||
else
|
||||
printk(KERN_WARNING "ReiserFS: warning: %s\n", 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: %s: %s",
|
||||
reiserfs_bdevname(sb), 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: %s: %s\n",
|
||||
reiserfs_bdevname(s), error_buf);
|
||||
else
|
||||
printk(KERN_DEBUG "ReiserFS: %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 *fmt, ...)
|
||||
{
|
||||
do_reiserfs_warning(fmt);
|
||||
printk(KERN_EMERG "REISERFS: panic (device %s): %s\n",
|
||||
reiserfs_bdevname(sb), error_buf);
|
||||
BUG();
|
||||
|
||||
/* this is not actually called, but makes reiserfs_panic() "noreturn" */
|
||||
panic("REISERFS: panic (device %s): %s\n",
|
||||
reiserfs_bdevname(sb), error_buf);
|
||||
}
|
||||
|
||||
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",
|
||||
reiserfs_bdevname(sb), error_buf);
|
||||
}
|
||||
|
||||
if (sb->s_flags & MS_RDONLY)
|
||||
return;
|
||||
|
||||
printk(KERN_CRIT "REISERFS: abort (device %s): %s\n",
|
||||
reiserfs_bdevname(sb), error_buf);
|
||||
|
||||
sb->s_flags |= MS_RDONLY;
|
||||
reiserfs_journal_abort(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);
|
||||
}
|
||||
|
||||
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: check_leaf_block_head: invalid item number %z",
|
||||
bh);
|
||||
if (blkh_free_space(blkh) > bh->b_size - BLKH_SIZE - IH_SIZE * nr)
|
||||
reiserfs_panic(NULL,
|
||||
"vs-6020: check_leaf_block_head: 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: check_internal_block_head: invalid level %z",
|
||||
bh);
|
||||
|
||||
if (B_NR_ITEMS(bh) > (bh->b_size - BLKH_SIZE) / IH_SIZE)
|
||||
reiserfs_panic(NULL,
|
||||
"vs-6030: check_internal_block_head: 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: check_internal_block_head: 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);
|
||||
*/
|
||||
|
||||
}
|
||||
661
fs/reiserfs/procfs.c
Normal file
661
fs/reiserfs/procfs.c
Normal file
@@ -0,0 +1,661 @@
|
||||
/* -*- 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 */
|
||||
|
||||
/* $Id: procfs.c,v 1.1.1.1 2007/06/12 07:27:12 eyryu Exp $ */
|
||||
|
||||
#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/smp_lock.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/proc_fs.h>
|
||||
|
||||
#if defined( 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%lu\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%lu\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);
|
||||
|
||||
if (de->deleted) {
|
||||
deactivate_super(s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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 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,
|
||||
};
|
||||
|
||||
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 *))
|
||||
{
|
||||
struct proc_dir_entry *de;
|
||||
de = create_proc_entry(name, 0, REISERFS_SB(sb)->procdir);
|
||||
if (de) {
|
||||
de->data = func;
|
||||
de->proc_fops = &r_file_operations;
|
||||
}
|
||||
}
|
||||
|
||||
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->owner = THIS_MODULE;
|
||||
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, "reiserfs: 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) {
|
||||
proc_info_root->owner = THIS_MODULE;
|
||||
} else {
|
||||
reiserfs_warning(NULL,
|
||||
"reiserfs: 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
|
||||
|
||||
/*
|
||||
* $Log: procfs.c,v $
|
||||
* Revision 1.1.1.1 2007/06/12 07:27:12 eyryu
|
||||
* s3c-linux-2.6.21.5
|
||||
*
|
||||
* 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:
|
||||
*/
|
||||
212
fs/reiserfs/resize.c
Normal file
212
fs/reiserfs/resize.c
Normal file
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
* 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) - (SB_BMAP_NR(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 = SB_BMAP_NR(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");
|
||||
unlock_super(s);
|
||||
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) * SB_BMAP_NR(s));
|
||||
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);
|
||||
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].first_zero_hint = 1;
|
||||
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;
|
||||
if (!info->first_zero_hint)
|
||||
info->first_zero_hint = 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;
|
||||
/* Extreme case where last bitmap is the only valid block in itself. */
|
||||
if (!info->free_count)
|
||||
info->first_zero_hint = 0;
|
||||
/* 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_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);
|
||||
}
|
||||
2121
fs/reiserfs/stree.c
Normal file
2121
fs/reiserfs/stree.c
Normal file
File diff suppressed because it is too large
Load Diff
2177
fs/reiserfs/super.c
Normal file
2177
fs/reiserfs/super.c
Normal file
File diff suppressed because it is too large
Load Diff
278
fs/reiserfs/tail_conversion.c
Normal file
278
fs/reiserfs/tail_conversion.c
Normal file
@@ -0,0 +1,278 @@
|
||||
/*
|
||||
* 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 n_blk_size, n_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++;
|
||||
|
||||
n_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_warning(sb, "PAP-14030: direct2indirect: "
|
||||
"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)++;
|
||||
n_retval =
|
||||
reiserfs_insert_item(th, path, &end_key, &ind_ih, inode,
|
||||
(char *)&unfm_ptr);
|
||||
} else {
|
||||
/* Paste into last indirect item of an object. */
|
||||
n_retval = reiserfs_paste_into_item(th, path, &end_key, inode,
|
||||
(char *)&unfm_ptr,
|
||||
UNFM_P_SIZE);
|
||||
}
|
||||
if (n_retval) {
|
||||
return n_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: direct2indirect: "
|
||||
"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) & (n_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;
|
||||
}
|
||||
n_retval = reiserfs_delete_item(th, path, &end_key, inode,
|
||||
up_to_date_bh);
|
||||
|
||||
total_tail += n_retval;
|
||||
if (tail_size == n_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, n_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 *p_s_inode, struct page *page, struct treepath *p_s_path, /* path to the indirect item. */
|
||||
const struct cpu_key *p_s_item_key, /* Key to look for unformatted node pointer to be cut. */
|
||||
loff_t n_new_file_size, /* New file size. */
|
||||
char *p_c_mode)
|
||||
{
|
||||
struct super_block *p_s_sb = p_s_inode->i_sb;
|
||||
struct item_head s_ih;
|
||||
unsigned long n_block_size = p_s_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(p_s_sb)->s_indirect2direct++;
|
||||
|
||||
*p_c_mode = M_SKIP_BALANCING;
|
||||
|
||||
/* store item head path points to. */
|
||||
copy_item_head(&s_ih, PATH_PITEM_HEAD(p_s_path));
|
||||
|
||||
tail_len = (n_new_file_size & (n_block_size - 1));
|
||||
if (get_inode_sd_version(p_s_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) * p_s_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, p_s_path)) {
|
||||
/* re-search indirect item */
|
||||
if (search_for_position_by_key(p_s_sb, p_s_item_key, p_s_path)
|
||||
== POSITION_NOT_FOUND)
|
||||
reiserfs_panic(p_s_sb,
|
||||
"PAP-5520: indirect2direct: "
|
||||
"item to be converted %K does not exist",
|
||||
p_s_item_key);
|
||||
copy_item_head(&s_ih, PATH_PITEM_HEAD(p_s_path));
|
||||
#ifdef CONFIG_REISERFS_CHECK
|
||||
pos = le_ih_k_offset(&s_ih) - 1 +
|
||||
(ih_item_len(&s_ih) / UNFM_P_SIZE -
|
||||
1) * p_s_sb->s_blocksize;
|
||||
if (pos != pos1)
|
||||
reiserfs_panic(p_s_sb, "vs-5530: indirect2direct: "
|
||||
"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(p_s_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(p_s_path)++;
|
||||
|
||||
key = *p_s_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, p_s_path, &key, &s_ih, p_s_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 n_block_size - round_tail_len;
|
||||
}
|
||||
kunmap(page);
|
||||
|
||||
/* make sure to get the i_blocks changes from reiserfs_insert_item */
|
||||
reiserfs_update_sd(th, p_s_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. */
|
||||
*p_c_mode = M_CUT;
|
||||
|
||||
/* we store position of first direct item in the in-core inode */
|
||||
//mark_file_with_tail (p_s_inode, pos1 + 1);
|
||||
REISERFS_I(p_s_inode)->i_first_direct_byte = pos1 + 1;
|
||||
|
||||
return n_block_size - round_tail_len;
|
||||
}
|
||||
1317
fs/reiserfs/xattr.c
Normal file
1317
fs/reiserfs/xattr.c
Normal file
File diff suppressed because it is too large
Load Diff
566
fs/reiserfs/xattr_acl.c
Normal file
566
fs/reiserfs/xattr_acl.c
Normal file
@@ -0,0 +1,566 @@
|
||||
#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 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;
|
||||
|
||||
if (!reiserfs_posixacl(inode->i_sb))
|
||||
return -EOPNOTSUPP;
|
||||
if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
|
||||
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;
|
||||
|
||||
error = reiserfs_set_acl(inode, type, acl);
|
||||
|
||||
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, **p_acl;
|
||||
int size;
|
||||
int retval;
|
||||
struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode);
|
||||
|
||||
switch (type) {
|
||||
case ACL_TYPE_ACCESS:
|
||||
name = POSIX_ACL_XATTR_ACCESS;
|
||||
p_acl = &reiserfs_i->i_acl_access;
|
||||
break;
|
||||
case ACL_TYPE_DEFAULT:
|
||||
name = POSIX_ACL_XATTR_DEFAULT;
|
||||
p_acl = &reiserfs_i->i_acl_default;
|
||||
break;
|
||||
default:
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
if (IS_ERR(*p_acl)) {
|
||||
if (PTR_ERR(*p_acl) == -ENODATA)
|
||||
return NULL;
|
||||
} else if (*p_acl != NULL)
|
||||
return posix_acl_dup(*p_acl);
|
||||
|
||||
size = reiserfs_xattr_get(inode, name, NULL, 0);
|
||||
if (size < 0) {
|
||||
if (size == -ENODATA || size == -ENOSYS) {
|
||||
*p_acl = ERR_PTR(-ENODATA);
|
||||
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;
|
||||
*p_acl = ERR_PTR(-ENODATA);
|
||||
} else if (retval < 0) {
|
||||
acl = ERR_PTR(retval);
|
||||
} else {
|
||||
acl = posix_acl_from_disk(value, retval);
|
||||
if (!IS_ERR(acl))
|
||||
*p_acl = posix_acl_dup(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 inode *inode, int type, struct posix_acl *acl)
|
||||
{
|
||||
char *name;
|
||||
void *value = NULL;
|
||||
struct posix_acl **p_acl;
|
||||
size_t size;
|
||||
int error;
|
||||
struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode);
|
||||
|
||||
if (S_ISLNK(inode->i_mode))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
switch (type) {
|
||||
case ACL_TYPE_ACCESS:
|
||||
name = POSIX_ACL_XATTR_ACCESS;
|
||||
p_acl = &reiserfs_i->i_acl_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;
|
||||
p_acl = &reiserfs_i->i_acl_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(inode, name, value, size, 0);
|
||||
} else {
|
||||
error = reiserfs_xattr_del(inode, name);
|
||||
if (error == -ENODATA) {
|
||||
/* This may seem odd here, but it means that the ACL was set
|
||||
* with a value representable with mode bits. If there was
|
||||
* an ACL before, reiserfs_xattr_del already dirtied the inode.
|
||||
*/
|
||||
mark_inode_dirty(inode);
|
||||
error = 0;
|
||||
}
|
||||
}
|
||||
|
||||
kfree(value);
|
||||
|
||||
if (!error) {
|
||||
/* Release the old one */
|
||||
if (!IS_ERR(*p_acl) && *p_acl)
|
||||
posix_acl_release(*p_acl);
|
||||
|
||||
if (acl == NULL)
|
||||
*p_acl = ERR_PTR(-ENODATA);
|
||||
else
|
||||
*p_acl = posix_acl_dup(acl);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/* dir->i_mutex: locked,
|
||||
* inode is new and not released into the wild yet */
|
||||
int
|
||||
reiserfs_inherit_default_acl(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_reiserfs_priv_object(dir)) {
|
||||
reiserfs_mark_inode_private(inode);
|
||||
goto apply_umask;
|
||||
}
|
||||
|
||||
acl = reiserfs_get_acl(dir, ACL_TYPE_DEFAULT);
|
||||
if (IS_ERR(acl)) {
|
||||
if (PTR_ERR(acl) == -ENODATA)
|
||||
goto apply_umask;
|
||||
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(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(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->fs->umask;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Looks up and caches the result of the default ACL.
|
||||
* We do this so that we don't need to carry the xattr_sem into
|
||||
* reiserfs_new_inode if we don't need to */
|
||||
int reiserfs_cache_default_acl(struct inode *inode)
|
||||
{
|
||||
int ret = 0;
|
||||
if (reiserfs_posixacl(inode->i_sb) && !is_reiserfs_priv_object(inode)) {
|
||||
struct posix_acl *acl;
|
||||
reiserfs_read_lock_xattr_i(inode);
|
||||
reiserfs_read_lock_xattrs(inode->i_sb);
|
||||
acl = reiserfs_get_acl(inode, ACL_TYPE_DEFAULT);
|
||||
reiserfs_read_unlock_xattrs(inode->i_sb);
|
||||
reiserfs_read_unlock_xattr_i(inode);
|
||||
ret = (acl && !IS_ERR(acl));
|
||||
if (ret)
|
||||
posix_acl_release(acl);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
reiserfs_read_lock_xattrs(inode->i_sb);
|
||||
acl = reiserfs_get_acl(inode, ACL_TYPE_ACCESS);
|
||||
reiserfs_read_unlock_xattrs(inode->i_sb);
|
||||
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) {
|
||||
int lock = !has_xattr_dir(inode);
|
||||
reiserfs_write_lock_xattr_i(inode);
|
||||
if (lock)
|
||||
reiserfs_write_lock_xattrs(inode->i_sb);
|
||||
else
|
||||
reiserfs_read_lock_xattrs(inode->i_sb);
|
||||
error = reiserfs_set_acl(inode, ACL_TYPE_ACCESS, clone);
|
||||
if (lock)
|
||||
reiserfs_write_unlock_xattrs(inode->i_sb);
|
||||
else
|
||||
reiserfs_read_unlock_xattrs(inode->i_sb);
|
||||
reiserfs_write_unlock_xattr_i(inode);
|
||||
}
|
||||
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 int posix_acl_access_del(struct inode *inode, const char *name)
|
||||
{
|
||||
struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode);
|
||||
struct posix_acl **acl = &reiserfs_i->i_acl_access;
|
||||
if (strlen(name) != sizeof(POSIX_ACL_XATTR_ACCESS) - 1)
|
||||
return -EINVAL;
|
||||
if (!IS_ERR(*acl) && *acl) {
|
||||
posix_acl_release(*acl);
|
||||
*acl = ERR_PTR(-ENODATA);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
posix_acl_access_list(struct inode *inode, const char *name, int namelen,
|
||||
char *out)
|
||||
{
|
||||
int len = namelen;
|
||||
if (!reiserfs_posixacl(inode->i_sb))
|
||||
return 0;
|
||||
if (out)
|
||||
memcpy(out, name, len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
struct reiserfs_xattr_handler posix_acl_access_handler = {
|
||||
.prefix = POSIX_ACL_XATTR_ACCESS,
|
||||
.get = posix_acl_access_get,
|
||||
.set = posix_acl_access_set,
|
||||
.del = posix_acl_access_del,
|
||||
.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 int posix_acl_default_del(struct inode *inode, const char *name)
|
||||
{
|
||||
struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode);
|
||||
struct posix_acl **acl = &reiserfs_i->i_acl_default;
|
||||
if (strlen(name) != sizeof(POSIX_ACL_XATTR_DEFAULT) - 1)
|
||||
return -EINVAL;
|
||||
if (!IS_ERR(*acl) && *acl) {
|
||||
posix_acl_release(*acl);
|
||||
*acl = ERR_PTR(-ENODATA);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
posix_acl_default_list(struct inode *inode, const char *name, int namelen,
|
||||
char *out)
|
||||
{
|
||||
int len = namelen;
|
||||
if (!reiserfs_posixacl(inode->i_sb))
|
||||
return 0;
|
||||
if (out)
|
||||
memcpy(out, name, len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
struct reiserfs_xattr_handler posix_acl_default_handler = {
|
||||
.prefix = POSIX_ACL_XATTR_DEFAULT,
|
||||
.get = posix_acl_default_get,
|
||||
.set = posix_acl_default_set,
|
||||
.del = posix_acl_default_del,
|
||||
.list = posix_acl_default_list,
|
||||
};
|
||||
67
fs/reiserfs/xattr_security.c
Normal file
67
fs/reiserfs/xattr_security.c
Normal file
@@ -0,0 +1,67 @@
|
||||
#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>
|
||||
|
||||
#define XATTR_SECURITY_PREFIX "security."
|
||||
|
||||
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_reiserfs_priv_object(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_reiserfs_priv_object(inode))
|
||||
return -EPERM;
|
||||
|
||||
return reiserfs_xattr_set(inode, name, buffer, size, flags);
|
||||
}
|
||||
|
||||
static int security_del(struct inode *inode, const char *name)
|
||||
{
|
||||
if (strlen(name) < sizeof(XATTR_SECURITY_PREFIX))
|
||||
return -EINVAL;
|
||||
|
||||
if (is_reiserfs_priv_object(inode))
|
||||
return -EPERM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
security_list(struct inode *inode, const char *name, int namelen, char *out)
|
||||
{
|
||||
int len = namelen;
|
||||
|
||||
if (is_reiserfs_priv_object(inode))
|
||||
return 0;
|
||||
|
||||
if (out)
|
||||
memcpy(out, name, len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
struct reiserfs_xattr_handler security_handler = {
|
||||
.prefix = XATTR_SECURITY_PREFIX,
|
||||
.get = security_get,
|
||||
.set = security_set,
|
||||
.del = security_del,
|
||||
.list = security_list,
|
||||
};
|
||||
80
fs/reiserfs/xattr_trusted.c
Normal file
80
fs/reiserfs/xattr_trusted.c
Normal file
@@ -0,0 +1,80 @@
|
||||
#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>
|
||||
|
||||
#define XATTR_TRUSTED_PREFIX "trusted."
|
||||
|
||||
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 (!reiserfs_xattrs(inode->i_sb))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!(capable(CAP_SYS_ADMIN) || is_reiserfs_priv_object(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 (!reiserfs_xattrs(inode->i_sb))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!(capable(CAP_SYS_ADMIN) || is_reiserfs_priv_object(inode)))
|
||||
return -EPERM;
|
||||
|
||||
return reiserfs_xattr_set(inode, name, buffer, size, flags);
|
||||
}
|
||||
|
||||
static int trusted_del(struct inode *inode, const char *name)
|
||||
{
|
||||
if (strlen(name) < sizeof(XATTR_TRUSTED_PREFIX))
|
||||
return -EINVAL;
|
||||
|
||||
if (!reiserfs_xattrs(inode->i_sb))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!(capable(CAP_SYS_ADMIN) || is_reiserfs_priv_object(inode)))
|
||||
return -EPERM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
trusted_list(struct inode *inode, const char *name, int namelen, char *out)
|
||||
{
|
||||
int len = namelen;
|
||||
|
||||
if (!reiserfs_xattrs(inode->i_sb))
|
||||
return 0;
|
||||
|
||||
if (!(capable(CAP_SYS_ADMIN) || is_reiserfs_priv_object(inode)))
|
||||
return 0;
|
||||
|
||||
if (out)
|
||||
memcpy(out, name, len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
struct reiserfs_xattr_handler trusted_handler = {
|
||||
.prefix = XATTR_TRUSTED_PREFIX,
|
||||
.get = trusted_get,
|
||||
.set = trusted_set,
|
||||
.del = trusted_del,
|
||||
.list = trusted_list,
|
||||
};
|
||||
68
fs/reiserfs/xattr_user.c
Normal file
68
fs/reiserfs/xattr_user.c
Normal file
@@ -0,0 +1,68 @@
|
||||
#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>
|
||||
|
||||
#ifdef CONFIG_REISERFS_FS_POSIX_ACL
|
||||
# include <linux/reiserfs_acl.h>
|
||||
#endif
|
||||
|
||||
#define XATTR_USER_PREFIX "user."
|
||||
|
||||
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 int user_del(struct inode *inode, const char *name)
|
||||
{
|
||||
if (strlen(name) < sizeof(XATTR_USER_PREFIX))
|
||||
return -EINVAL;
|
||||
|
||||
if (!reiserfs_xattrs_user(inode->i_sb))
|
||||
return -EOPNOTSUPP;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
user_list(struct inode *inode, const char *name, int namelen, char *out)
|
||||
{
|
||||
int len = namelen;
|
||||
if (!reiserfs_xattrs_user(inode->i_sb))
|
||||
return 0;
|
||||
|
||||
if (out)
|
||||
memcpy(out, name, len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
struct reiserfs_xattr_handler user_handler = {
|
||||
.prefix = XATTR_USER_PREFIX,
|
||||
.get = user_get,
|
||||
.set = user_set,
|
||||
.del = user_del,
|
||||
.list = user_list,
|
||||
};
|
||||
Reference in New Issue
Block a user