mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 03:01:39 -04:00
Automatic merge with /usr/src/ntfs-2.6.git.
This commit is contained in:
commit
c514720716
1360 changed files with 74907 additions and 49792 deletions
47
fs/Kconfig
47
fs/Kconfig
|
|
@ -29,6 +29,7 @@ config EXT2_FS_XATTR
|
|||
config EXT2_FS_POSIX_ACL
|
||||
bool "Ext2 POSIX Access Control Lists"
|
||||
depends on EXT2_FS_XATTR
|
||||
select FS_POSIX_ACL
|
||||
help
|
||||
Posix Access Control Lists (ACLs) support permissions for users and
|
||||
groups beyond the owner/group/world scheme.
|
||||
|
|
@ -114,6 +115,7 @@ config EXT3_FS_XATTR
|
|||
config EXT3_FS_POSIX_ACL
|
||||
bool "Ext3 POSIX Access Control Lists"
|
||||
depends on EXT3_FS_XATTR
|
||||
select FS_POSIX_ACL
|
||||
help
|
||||
Posix Access Control Lists (ACLs) support permissions for users and
|
||||
groups beyond the owner/group/world scheme.
|
||||
|
|
@ -241,6 +243,7 @@ config REISERFS_FS_XATTR
|
|||
config REISERFS_FS_POSIX_ACL
|
||||
bool "ReiserFS POSIX Access Control Lists"
|
||||
depends on REISERFS_FS_XATTR
|
||||
select FS_POSIX_ACL
|
||||
help
|
||||
Posix Access Control Lists (ACLs) support permissions for users and
|
||||
groups beyond the owner/group/world scheme.
|
||||
|
|
@ -274,6 +277,7 @@ config JFS_FS
|
|||
config JFS_POSIX_ACL
|
||||
bool "JFS POSIX Access Control Lists"
|
||||
depends on JFS_FS
|
||||
select FS_POSIX_ACL
|
||||
help
|
||||
Posix Access Control Lists (ACLs) support permissions for users and
|
||||
groups beyond the owner/group/world scheme.
|
||||
|
|
@ -318,8 +322,7 @@ config FS_POSIX_ACL
|
|||
# Never use this symbol for ifdefs.
|
||||
#
|
||||
bool
|
||||
depends on EXT2_FS_POSIX_ACL || EXT3_FS_POSIX_ACL || JFS_POSIX_ACL || REISERFS_FS_POSIX_ACL || NFSD_V4
|
||||
default y
|
||||
default n
|
||||
|
||||
source "fs/xfs/Kconfig"
|
||||
|
||||
|
|
@ -356,6 +359,19 @@ config ROMFS_FS
|
|||
If you don't know whether you need it, then you don't need it:
|
||||
answer N.
|
||||
|
||||
config INOTIFY
|
||||
bool "Inotify file change notification support"
|
||||
default y
|
||||
---help---
|
||||
Say Y here to enable inotify support and the /dev/inotify character
|
||||
device. Inotify is a file change notification system and a
|
||||
replacement for dnotify. Inotify fixes numerous shortcomings in
|
||||
dnotify and introduces several new features. It allows monitoring
|
||||
of both files and directories via a single open fd. Multiple file
|
||||
events are supported.
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
config QUOTA
|
||||
bool "Quota support"
|
||||
help
|
||||
|
|
@ -1036,26 +1052,18 @@ config JFFS2_FS_DEBUG
|
|||
If reporting bugs, please try to have available a full dump of the
|
||||
messages at debug level 1 while the misbehaviour was occurring.
|
||||
|
||||
config JFFS2_FS_NAND
|
||||
bool "JFFS2 support for NAND flash"
|
||||
config JFFS2_FS_WRITEBUFFER
|
||||
bool "JFFS2 write-buffering support"
|
||||
depends on JFFS2_FS
|
||||
default n
|
||||
default y
|
||||
help
|
||||
This enables the support for NAND flash in JFFS2. NAND is a newer
|
||||
type of flash chip design than the traditional NOR flash, with
|
||||
higher density but a handful of characteristics which make it more
|
||||
interesting for the file system to use.
|
||||
This enables the write-buffering support in JFFS2.
|
||||
|
||||
Say 'N' unless you have NAND flash.
|
||||
|
||||
config JFFS2_FS_NOR_ECC
|
||||
bool "JFFS2 support for ECC'd NOR flash (EXPERIMENTAL)"
|
||||
depends on JFFS2_FS && EXPERIMENTAL
|
||||
default n
|
||||
help
|
||||
This enables the experimental support for NOR flash with transparent
|
||||
ECC for JFFS2. This type of flash chip is not common, however it is
|
||||
available from ST Microelectronics.
|
||||
This functionality is required to support JFFS2 on the following
|
||||
types of flash devices:
|
||||
- NAND flash
|
||||
- NOR flash with transparent ECC
|
||||
- DataFlash
|
||||
|
||||
config JFFS2_COMPRESSION_OPTIONS
|
||||
bool "Advanced compression options for JFFS2"
|
||||
|
|
@ -1438,6 +1446,7 @@ config NFSD_V4
|
|||
select NFSD_TCP
|
||||
select CRYPTO_MD5
|
||||
select CRYPTO
|
||||
select FS_POSIX_ACL
|
||||
help
|
||||
If you would like to include the NFSv4 server as well as the NFSv2
|
||||
and NFSv3 servers, say Y here. This feature is experimental, and
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ obj-y := open.o read_write.o file_table.o buffer.o bio.o super.o \
|
|||
seq_file.o xattr.o libfs.o fs-writeback.o mpage.o direct-io.o \
|
||||
ioprio.o
|
||||
|
||||
obj-$(CONFIG_INOTIFY) += inotify.o
|
||||
obj-$(CONFIG_EPOLL) += eventpoll.o
|
||||
obj-$(CONFIG_COMPAT) += compat.o
|
||||
|
||||
|
|
|
|||
33
fs/attr.c
33
fs/attr.c
|
|
@ -10,7 +10,7 @@
|
|||
#include <linux/mm.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/dnotify.h>
|
||||
#include <linux/fsnotify.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/quotaops.h>
|
||||
#include <linux/security.h>
|
||||
|
|
@ -107,31 +107,8 @@ int inode_setattr(struct inode * inode, struct iattr * attr)
|
|||
out:
|
||||
return error;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(inode_setattr);
|
||||
|
||||
int setattr_mask(unsigned int ia_valid)
|
||||
{
|
||||
unsigned long dn_mask = 0;
|
||||
|
||||
if (ia_valid & ATTR_UID)
|
||||
dn_mask |= DN_ATTRIB;
|
||||
if (ia_valid & ATTR_GID)
|
||||
dn_mask |= DN_ATTRIB;
|
||||
if (ia_valid & ATTR_SIZE)
|
||||
dn_mask |= DN_MODIFY;
|
||||
/* both times implies a utime(s) call */
|
||||
if ((ia_valid & (ATTR_ATIME|ATTR_MTIME)) == (ATTR_ATIME|ATTR_MTIME))
|
||||
dn_mask |= DN_ATTRIB;
|
||||
else if (ia_valid & ATTR_ATIME)
|
||||
dn_mask |= DN_ACCESS;
|
||||
else if (ia_valid & ATTR_MTIME)
|
||||
dn_mask |= DN_MODIFY;
|
||||
if (ia_valid & ATTR_MODE)
|
||||
dn_mask |= DN_ATTRIB;
|
||||
return dn_mask;
|
||||
}
|
||||
|
||||
int notify_change(struct dentry * dentry, struct iattr * attr)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
|
|
@ -197,11 +174,9 @@ int notify_change(struct dentry * dentry, struct iattr * attr)
|
|||
if (ia_valid & ATTR_SIZE)
|
||||
up_write(&dentry->d_inode->i_alloc_sem);
|
||||
|
||||
if (!error) {
|
||||
unsigned long dn_mask = setattr_mask(ia_valid);
|
||||
if (dn_mask)
|
||||
dnotify_parent(dentry, dn_mask);
|
||||
}
|
||||
if (!error)
|
||||
fsnotify_change(dentry, ia_valid);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -231,8 +231,8 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry,
|
|||
int type = (notify == NFY_MOUNT ?
|
||||
autofs_ptype_missing : autofs_ptype_expire_multi);
|
||||
|
||||
DPRINTK(("new wait id = 0x%08lx, name = %.*s, nfy=%d\n",
|
||||
(unsigned long) wq->wait_queue_token, wq->len, wq->name, notify));
|
||||
DPRINTK("new wait id = 0x%08lx, name = %.*s, nfy=%d\n",
|
||||
(unsigned long) wq->wait_queue_token, wq->len, wq->name, notify);
|
||||
|
||||
/* autofs4_notify_daemon() may block */
|
||||
autofs4_notify_daemon(sbi, wq, type);
|
||||
|
|
|
|||
2
fs/bio.c
2
fs/bio.c
|
|
@ -52,7 +52,7 @@ struct biovec_slab {
|
|||
*/
|
||||
|
||||
#define BV(x) { .nr_vecs = x, .name = "biovec-"__stringify(x) }
|
||||
static struct biovec_slab bvec_slabs[BIOVEC_NR_POOLS] = {
|
||||
static struct biovec_slab bvec_slabs[BIOVEC_NR_POOLS] __read_mostly = {
|
||||
BV(1), BV(4), BV(16), BV(64), BV(128), BV(BIO_MAX_PAGES),
|
||||
};
|
||||
#undef BV
|
||||
|
|
|
|||
25
fs/buffer.c
25
fs/buffer.c
|
|
@ -513,8 +513,8 @@ static void free_more_memory(void)
|
|||
*/
|
||||
static void end_buffer_async_read(struct buffer_head *bh, int uptodate)
|
||||
{
|
||||
static DEFINE_SPINLOCK(page_uptodate_lock);
|
||||
unsigned long flags;
|
||||
struct buffer_head *first;
|
||||
struct buffer_head *tmp;
|
||||
struct page *page;
|
||||
int page_uptodate = 1;
|
||||
|
|
@ -536,7 +536,9 @@ static void end_buffer_async_read(struct buffer_head *bh, int uptodate)
|
|||
* two buffer heads end IO at almost the same time and both
|
||||
* decide that the page is now completely done.
|
||||
*/
|
||||
spin_lock_irqsave(&page_uptodate_lock, flags);
|
||||
first = page_buffers(page);
|
||||
local_irq_save(flags);
|
||||
bit_spin_lock(BH_Uptodate_Lock, &first->b_state);
|
||||
clear_buffer_async_read(bh);
|
||||
unlock_buffer(bh);
|
||||
tmp = bh;
|
||||
|
|
@ -549,7 +551,8 @@ static void end_buffer_async_read(struct buffer_head *bh, int uptodate)
|
|||
}
|
||||
tmp = tmp->b_this_page;
|
||||
} while (tmp != bh);
|
||||
spin_unlock_irqrestore(&page_uptodate_lock, flags);
|
||||
bit_spin_unlock(BH_Uptodate_Lock, &first->b_state);
|
||||
local_irq_restore(flags);
|
||||
|
||||
/*
|
||||
* If none of the buffers had errors and they are all
|
||||
|
|
@ -561,7 +564,8 @@ static void end_buffer_async_read(struct buffer_head *bh, int uptodate)
|
|||
return;
|
||||
|
||||
still_busy:
|
||||
spin_unlock_irqrestore(&page_uptodate_lock, flags);
|
||||
bit_spin_unlock(BH_Uptodate_Lock, &first->b_state);
|
||||
local_irq_restore(flags);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -572,8 +576,8 @@ still_busy:
|
|||
void end_buffer_async_write(struct buffer_head *bh, int uptodate)
|
||||
{
|
||||
char b[BDEVNAME_SIZE];
|
||||
static DEFINE_SPINLOCK(page_uptodate_lock);
|
||||
unsigned long flags;
|
||||
struct buffer_head *first;
|
||||
struct buffer_head *tmp;
|
||||
struct page *page;
|
||||
|
||||
|
|
@ -594,7 +598,10 @@ void end_buffer_async_write(struct buffer_head *bh, int uptodate)
|
|||
SetPageError(page);
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&page_uptodate_lock, flags);
|
||||
first = page_buffers(page);
|
||||
local_irq_save(flags);
|
||||
bit_spin_lock(BH_Uptodate_Lock, &first->b_state);
|
||||
|
||||
clear_buffer_async_write(bh);
|
||||
unlock_buffer(bh);
|
||||
tmp = bh->b_this_page;
|
||||
|
|
@ -605,12 +612,14 @@ void end_buffer_async_write(struct buffer_head *bh, int uptodate)
|
|||
}
|
||||
tmp = tmp->b_this_page;
|
||||
}
|
||||
spin_unlock_irqrestore(&page_uptodate_lock, flags);
|
||||
bit_spin_unlock(BH_Uptodate_Lock, &first->b_state);
|
||||
local_irq_restore(flags);
|
||||
end_page_writeback(page);
|
||||
return;
|
||||
|
||||
still_busy:
|
||||
spin_unlock_irqrestore(&page_uptodate_lock, flags);
|
||||
bit_spin_unlock(BH_Uptodate_Lock, &first->b_state);
|
||||
local_irq_restore(flags);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -277,8 +277,9 @@ static struct kobject *cdev_get(struct cdev *p)
|
|||
void cdev_put(struct cdev *p)
|
||||
{
|
||||
if (p) {
|
||||
struct module *owner = p->owner;
|
||||
kobject_put(&p->kobj);
|
||||
module_put(p->owner);
|
||||
module_put(owner);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
12
fs/compat.c
12
fs/compat.c
|
|
@ -37,7 +37,7 @@
|
|||
#include <linux/ctype.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/dirent.h>
|
||||
#include <linux/dnotify.h>
|
||||
#include <linux/fsnotify.h>
|
||||
#include <linux/highuid.h>
|
||||
#include <linux/sunrpc/svc.h>
|
||||
#include <linux/nfsd/nfsd.h>
|
||||
|
|
@ -1307,9 +1307,13 @@ static ssize_t compat_do_readv_writev(int type, struct file *file,
|
|||
out:
|
||||
if (iov != iovstack)
|
||||
kfree(iov);
|
||||
if ((ret + (type == READ)) > 0)
|
||||
dnotify_parent(file->f_dentry,
|
||||
(type == READ) ? DN_ACCESS : DN_MODIFY);
|
||||
if ((ret + (type == READ)) > 0) {
|
||||
struct dentry *dentry = file->f_dentry;
|
||||
if (type == READ)
|
||||
fsnotify_access(dentry);
|
||||
else
|
||||
fsnotify_modify(dentry);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -94,12 +94,10 @@ static struct dcookie_struct * alloc_dcookie(struct dentry * dentry,
|
|||
if (!dcs)
|
||||
return NULL;
|
||||
|
||||
atomic_inc(&dentry->d_count);
|
||||
atomic_inc(&vfsmnt->mnt_count);
|
||||
dentry->d_cookie = dcs;
|
||||
|
||||
dcs->dentry = dentry;
|
||||
dcs->vfsmnt = vfsmnt;
|
||||
dcs->dentry = dget(dentry);
|
||||
dcs->vfsmnt = mntget(vfsmnt);
|
||||
hash_dcookie(dcs);
|
||||
|
||||
return dcs;
|
||||
|
|
|
|||
12
fs/exec.c
12
fs/exec.c
|
|
@ -642,6 +642,18 @@ static inline int de_thread(struct task_struct *tsk)
|
|||
count = 2;
|
||||
if (thread_group_leader(current))
|
||||
count = 1;
|
||||
else {
|
||||
/*
|
||||
* The SIGALRM timer survives the exec, but needs to point
|
||||
* at us as the new group leader now. We have a race with
|
||||
* a timer firing now getting the old leader, so we need to
|
||||
* synchronize with any firing (by calling del_timer_sync)
|
||||
* before we can safely let the old group leader die.
|
||||
*/
|
||||
sig->real_timer.data = (unsigned long)current;
|
||||
if (del_timer_sync(&sig->real_timer))
|
||||
add_timer(&sig->real_timer);
|
||||
}
|
||||
while (atomic_read(&sig->count) > count) {
|
||||
sig->group_exit_task = current;
|
||||
sig->notify_count = count;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,15 @@
|
|||
#include <linux/fs.h>
|
||||
#include <linux/ext2_fs.h>
|
||||
|
||||
/*
|
||||
* ext2 mount options
|
||||
*/
|
||||
struct ext2_mount_options {
|
||||
unsigned long s_mount_opt;
|
||||
uid_t s_resuid;
|
||||
gid_t s_resgid;
|
||||
};
|
||||
|
||||
/*
|
||||
* second extended file system inode data in memory
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -936,12 +936,23 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data)
|
|||
struct ext2_sb_info * sbi = EXT2_SB(sb);
|
||||
struct ext2_super_block * es;
|
||||
unsigned long old_mount_opt = sbi->s_mount_opt;
|
||||
struct ext2_mount_options old_opts;
|
||||
unsigned long old_sb_flags;
|
||||
int err;
|
||||
|
||||
/* Store the old options */
|
||||
old_sb_flags = sb->s_flags;
|
||||
old_opts.s_mount_opt = sbi->s_mount_opt;
|
||||
old_opts.s_resuid = sbi->s_resuid;
|
||||
old_opts.s_resgid = sbi->s_resgid;
|
||||
|
||||
/*
|
||||
* Allow the "check" option to be passed as a remount option.
|
||||
*/
|
||||
if (!parse_options (data, sbi))
|
||||
return -EINVAL;
|
||||
if (!parse_options (data, sbi)) {
|
||||
err = -EINVAL;
|
||||
goto restore_opts;
|
||||
}
|
||||
|
||||
sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
|
||||
((sbi->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0);
|
||||
|
|
@ -971,7 +982,8 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data)
|
|||
printk("EXT2-fs: %s: couldn't remount RDWR because of "
|
||||
"unsupported optional features (%x).\n",
|
||||
sb->s_id, le32_to_cpu(ret));
|
||||
return -EROFS;
|
||||
err = -EROFS;
|
||||
goto restore_opts;
|
||||
}
|
||||
/*
|
||||
* Mounting a RDONLY partition read-write, so reread and
|
||||
|
|
@ -984,6 +996,12 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data)
|
|||
}
|
||||
ext2_sync_super(sb, es);
|
||||
return 0;
|
||||
restore_opts:
|
||||
sbi->s_mount_opt = old_opts.s_mount_opt;
|
||||
sbi->s_resuid = old_opts.s_resuid;
|
||||
sbi->s_resgid = old_opts.s_resgid;
|
||||
sb->s_flags = old_sb_flags;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ext2_statfs (struct super_block * sb, struct kstatfs * buf)
|
||||
|
|
|
|||
|
|
@ -2663,7 +2663,7 @@ static int ext3_do_update_inode(handle_t *handle,
|
|||
} else for (block = 0; block < EXT3_N_BLOCKS; block++)
|
||||
raw_inode->i_block[block] = ei->i_data[block];
|
||||
|
||||
if (EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE)
|
||||
if (ei->i_extra_isize)
|
||||
raw_inode->i_extra_isize = cpu_to_le16(ei->i_extra_isize);
|
||||
|
||||
BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata");
|
||||
|
|
|
|||
|
|
@ -890,7 +890,10 @@ clear_qf_name:
|
|||
"quota turned on.\n");
|
||||
return 0;
|
||||
}
|
||||
kfree(sbi->s_qf_names[qtype]);
|
||||
/*
|
||||
* The space will be released later when all options
|
||||
* are confirmed to be correct
|
||||
*/
|
||||
sbi->s_qf_names[qtype] = NULL;
|
||||
break;
|
||||
case Opt_jqfmt_vfsold:
|
||||
|
|
@ -939,7 +942,7 @@ clear_qf_name:
|
|||
case Opt_ignore:
|
||||
break;
|
||||
case Opt_resize:
|
||||
if (!n_blocks_count) {
|
||||
if (!is_remount) {
|
||||
printk("EXT3-fs: resize option only available "
|
||||
"for remount\n");
|
||||
return 0;
|
||||
|
|
@ -2109,14 +2112,33 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)
|
|||
{
|
||||
struct ext3_super_block * es;
|
||||
struct ext3_sb_info *sbi = EXT3_SB(sb);
|
||||
unsigned long tmp;
|
||||
unsigned long n_blocks_count = 0;
|
||||
unsigned long old_sb_flags;
|
||||
struct ext3_mount_options old_opts;
|
||||
int err;
|
||||
#ifdef CONFIG_QUOTA
|
||||
int i;
|
||||
#endif
|
||||
|
||||
/* Store the original options */
|
||||
old_sb_flags = sb->s_flags;
|
||||
old_opts.s_mount_opt = sbi->s_mount_opt;
|
||||
old_opts.s_resuid = sbi->s_resuid;
|
||||
old_opts.s_resgid = sbi->s_resgid;
|
||||
old_opts.s_commit_interval = sbi->s_commit_interval;
|
||||
#ifdef CONFIG_QUOTA
|
||||
old_opts.s_jquota_fmt = sbi->s_jquota_fmt;
|
||||
for (i = 0; i < MAXQUOTAS; i++)
|
||||
old_opts.s_qf_names[i] = sbi->s_qf_names[i];
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Allow the "check" option to be passed as a remount option.
|
||||
*/
|
||||
if (!parse_options(data, sb, &tmp, &n_blocks_count, 1))
|
||||
return -EINVAL;
|
||||
if (!parse_options(data, sb, NULL, &n_blocks_count, 1)) {
|
||||
err = -EINVAL;
|
||||
goto restore_opts;
|
||||
}
|
||||
|
||||
if (sbi->s_mount_opt & EXT3_MOUNT_ABORT)
|
||||
ext3_abort(sb, __FUNCTION__, "Abort forced by user");
|
||||
|
|
@ -2130,8 +2152,10 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)
|
|||
|
||||
if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY) ||
|
||||
n_blocks_count > le32_to_cpu(es->s_blocks_count)) {
|
||||
if (sbi->s_mount_opt & EXT3_MOUNT_ABORT)
|
||||
return -EROFS;
|
||||
if (sbi->s_mount_opt & EXT3_MOUNT_ABORT) {
|
||||
err = -EROFS;
|
||||
goto restore_opts;
|
||||
}
|
||||
|
||||
if (*flags & MS_RDONLY) {
|
||||
/*
|
||||
|
|
@ -2158,7 +2182,8 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)
|
|||
"remount RDWR because of unsupported "
|
||||
"optional features (%x).\n",
|
||||
sb->s_id, le32_to_cpu(ret));
|
||||
return -EROFS;
|
||||
err = -EROFS;
|
||||
goto restore_opts;
|
||||
}
|
||||
/*
|
||||
* Mounting a RDONLY partition read-write, so reread
|
||||
|
|
@ -2168,13 +2193,38 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)
|
|||
*/
|
||||
ext3_clear_journal_err(sb, es);
|
||||
sbi->s_mount_state = le16_to_cpu(es->s_state);
|
||||
if ((ret = ext3_group_extend(sb, es, n_blocks_count)))
|
||||
return ret;
|
||||
if ((ret = ext3_group_extend(sb, es, n_blocks_count))) {
|
||||
err = ret;
|
||||
goto restore_opts;
|
||||
}
|
||||
if (!ext3_setup_super (sb, es, 0))
|
||||
sb->s_flags &= ~MS_RDONLY;
|
||||
}
|
||||
}
|
||||
#ifdef CONFIG_QUOTA
|
||||
/* Release old quota file names */
|
||||
for (i = 0; i < MAXQUOTAS; i++)
|
||||
if (old_opts.s_qf_names[i] &&
|
||||
old_opts.s_qf_names[i] != sbi->s_qf_names[i])
|
||||
kfree(old_opts.s_qf_names[i]);
|
||||
#endif
|
||||
return 0;
|
||||
restore_opts:
|
||||
sb->s_flags = old_sb_flags;
|
||||
sbi->s_mount_opt = old_opts.s_mount_opt;
|
||||
sbi->s_resuid = old_opts.s_resuid;
|
||||
sbi->s_resgid = old_opts.s_resgid;
|
||||
sbi->s_commit_interval = old_opts.s_commit_interval;
|
||||
#ifdef CONFIG_QUOTA
|
||||
sbi->s_jquota_fmt = old_opts.s_jquota_fmt;
|
||||
for (i = 0; i < MAXQUOTAS; i++) {
|
||||
if (sbi->s_qf_names[i] &&
|
||||
old_opts.s_qf_names[i] != sbi->s_qf_names[i])
|
||||
kfree(sbi->s_qf_names[i]);
|
||||
sbi->s_qf_names[i] = old_opts.s_qf_names[i];
|
||||
}
|
||||
#endif
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ext3_statfs (struct super_block * sb, struct kstatfs * buf)
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
#include <linux/eventpoll.h>
|
||||
#include <linux/mount.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/fsnotify.h>
|
||||
|
||||
/* sysctl tunables... */
|
||||
struct files_stat_struct files_stat = {
|
||||
|
|
@ -126,6 +127,8 @@ void fastcall __fput(struct file *file)
|
|||
struct inode *inode = dentry->d_inode;
|
||||
|
||||
might_sleep();
|
||||
|
||||
fsnotify_close(file);
|
||||
/*
|
||||
* The function eventpoll_release() should be the first called
|
||||
* in the file cleanup chain.
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
|
|
@ -491,7 +492,7 @@ static int hppfs_open(struct inode *inode, struct file *file)
|
|||
fd = open_host_sock(host_file, &filter);
|
||||
if(fd > 0){
|
||||
data->contents = hppfs_get_data(fd, filter,
|
||||
&data->proc_file,
|
||||
data->proc_file,
|
||||
file, &data->len);
|
||||
if(!IS_ERR(data->contents))
|
||||
data->host_fd = fd;
|
||||
|
|
@ -543,7 +544,7 @@ static int hppfs_dir_open(struct inode *inode, struct file *file)
|
|||
static loff_t hppfs_llseek(struct file *file, loff_t off, int where)
|
||||
{
|
||||
struct hppfs_private *data = file->private_data;
|
||||
struct file *proc_file = &data->proc_file;
|
||||
struct file *proc_file = data->proc_file;
|
||||
loff_t (*llseek)(struct file *, loff_t, int);
|
||||
loff_t ret;
|
||||
|
||||
|
|
@ -586,7 +587,7 @@ static int hppfs_filldir(void *d, const char *name, int size,
|
|||
static int hppfs_readdir(struct file *file, void *ent, filldir_t filldir)
|
||||
{
|
||||
struct hppfs_private *data = file->private_data;
|
||||
struct file *proc_file = &data->proc_file;
|
||||
struct file *proc_file = data->proc_file;
|
||||
int (*readdir)(struct file *, void *, filldir_t);
|
||||
struct hppfs_dirent dirent = ((struct hppfs_dirent)
|
||||
{ .vfs_dirent = ent,
|
||||
|
|
|
|||
92
fs/inode.c
92
fs/inode.c
|
|
@ -21,6 +21,7 @@
|
|||
#include <linux/pagemap.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/bootmem.h>
|
||||
#include <linux/inotify.h>
|
||||
|
||||
/*
|
||||
* This is needed for the following functions:
|
||||
|
|
@ -202,6 +203,10 @@ void inode_init_once(struct inode *inode)
|
|||
INIT_LIST_HEAD(&inode->i_data.i_mmap_nonlinear);
|
||||
spin_lock_init(&inode->i_lock);
|
||||
i_size_ordered_init(inode);
|
||||
#ifdef CONFIG_INOTIFY
|
||||
INIT_LIST_HEAD(&inode->inotify_watches);
|
||||
sema_init(&inode->inotify_sem, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(inode_init_once);
|
||||
|
|
@ -282,6 +287,13 @@ static void dispose_list(struct list_head *head)
|
|||
if (inode->i_data.nrpages)
|
||||
truncate_inode_pages(&inode->i_data, 0);
|
||||
clear_inode(inode);
|
||||
|
||||
spin_lock(&inode_lock);
|
||||
hlist_del_init(&inode->i_hash);
|
||||
list_del_init(&inode->i_sb_list);
|
||||
spin_unlock(&inode_lock);
|
||||
|
||||
wake_up_inode(inode);
|
||||
destroy_inode(inode);
|
||||
nr_disposed++;
|
||||
}
|
||||
|
|
@ -317,8 +329,6 @@ static int invalidate_list(struct list_head *head, struct list_head *dispose)
|
|||
inode = list_entry(tmp, struct inode, i_sb_list);
|
||||
invalidate_inode_buffers(inode);
|
||||
if (!atomic_read(&inode->i_count)) {
|
||||
hlist_del_init(&inode->i_hash);
|
||||
list_del(&inode->i_sb_list);
|
||||
list_move(&inode->i_list, dispose);
|
||||
inode->i_state |= I_FREEING;
|
||||
count++;
|
||||
|
|
@ -346,6 +356,7 @@ int invalidate_inodes(struct super_block * sb)
|
|||
|
||||
down(&iprune_sem);
|
||||
spin_lock(&inode_lock);
|
||||
inotify_unmount_inodes(&sb->s_inodes);
|
||||
busy = invalidate_list(&sb->s_inodes, &throw_away);
|
||||
spin_unlock(&inode_lock);
|
||||
|
||||
|
|
@ -439,8 +450,6 @@ static void prune_icache(int nr_to_scan)
|
|||
if (!can_unuse(inode))
|
||||
continue;
|
||||
}
|
||||
hlist_del_init(&inode->i_hash);
|
||||
list_del_init(&inode->i_sb_list);
|
||||
list_move(&inode->i_list, &freeable);
|
||||
inode->i_state |= I_FREEING;
|
||||
nr_pruned++;
|
||||
|
|
@ -748,6 +757,7 @@ EXPORT_SYMBOL(igrab);
|
|||
* @head: the head of the list to search
|
||||
* @test: callback used for comparisons between inodes
|
||||
* @data: opaque data pointer to pass to @test
|
||||
* @wait: if true wait for the inode to be unlocked, if false do not
|
||||
*
|
||||
* ifind() searches for the inode specified by @data in the inode
|
||||
* cache. This is a generalized version of ifind_fast() for file systems where
|
||||
|
|
@ -762,7 +772,7 @@ EXPORT_SYMBOL(igrab);
|
|||
*/
|
||||
static inline struct inode *ifind(struct super_block *sb,
|
||||
struct hlist_head *head, int (*test)(struct inode *, void *),
|
||||
void *data)
|
||||
void *data, const int wait)
|
||||
{
|
||||
struct inode *inode;
|
||||
|
||||
|
|
@ -771,7 +781,8 @@ static inline struct inode *ifind(struct super_block *sb,
|
|||
if (inode) {
|
||||
__iget(inode);
|
||||
spin_unlock(&inode_lock);
|
||||
wait_on_inode(inode);
|
||||
if (likely(wait))
|
||||
wait_on_inode(inode);
|
||||
return inode;
|
||||
}
|
||||
spin_unlock(&inode_lock);
|
||||
|
|
@ -811,7 +822,7 @@ static inline struct inode *ifind_fast(struct super_block *sb,
|
|||
}
|
||||
|
||||
/**
|
||||
* ilookup5 - search for an inode in the inode cache
|
||||
* ilookup5_nowait - search for an inode in the inode cache
|
||||
* @sb: super block of file system to search
|
||||
* @hashval: hash value (usually inode number) to search for
|
||||
* @test: callback used for comparisons between inodes
|
||||
|
|
@ -823,7 +834,38 @@ static inline struct inode *ifind_fast(struct super_block *sb,
|
|||
* identification of an inode.
|
||||
*
|
||||
* If the inode is in the cache, the inode is returned with an incremented
|
||||
* reference count.
|
||||
* reference count. Note, the inode lock is not waited upon so you have to be
|
||||
* very careful what you do with the returned inode. You probably should be
|
||||
* using ilookup5() instead.
|
||||
*
|
||||
* Otherwise NULL is returned.
|
||||
*
|
||||
* Note, @test is called with the inode_lock held, so can't sleep.
|
||||
*/
|
||||
struct inode *ilookup5_nowait(struct super_block *sb, unsigned long hashval,
|
||||
int (*test)(struct inode *, void *), void *data)
|
||||
{
|
||||
struct hlist_head *head = inode_hashtable + hash(sb, hashval);
|
||||
|
||||
return ifind(sb, head, test, data, 0);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(ilookup5_nowait);
|
||||
|
||||
/**
|
||||
* ilookup5 - search for an inode in the inode cache
|
||||
* @sb: super block of file system to search
|
||||
* @hashval: hash value (usually inode number) to search for
|
||||
* @test: callback used for comparisons between inodes
|
||||
* @data: opaque data pointer to pass to @test
|
||||
*
|
||||
* ilookup5() uses ifind() to search for the inode specified by @hashval and
|
||||
* @data in the inode cache. This is a generalized version of ilookup() for
|
||||
* file systems where the inode number is not sufficient for unique
|
||||
* identification of an inode.
|
||||
*
|
||||
* If the inode is in the cache, the inode lock is waited upon and the inode is
|
||||
* returned with an incremented reference count.
|
||||
*
|
||||
* Otherwise NULL is returned.
|
||||
*
|
||||
|
|
@ -834,7 +876,7 @@ struct inode *ilookup5(struct super_block *sb, unsigned long hashval,
|
|||
{
|
||||
struct hlist_head *head = inode_hashtable + hash(sb, hashval);
|
||||
|
||||
return ifind(sb, head, test, data);
|
||||
return ifind(sb, head, test, data, 1);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(ilookup5);
|
||||
|
|
@ -891,7 +933,7 @@ struct inode *iget5_locked(struct super_block *sb, unsigned long hashval,
|
|||
struct hlist_head *head = inode_hashtable + hash(sb, hashval);
|
||||
struct inode *inode;
|
||||
|
||||
inode = ifind(sb, head, test, data);
|
||||
inode = ifind(sb, head, test, data, 1);
|
||||
if (inode)
|
||||
return inode;
|
||||
/*
|
||||
|
|
@ -1052,7 +1094,7 @@ static void generic_forget_inode(struct inode *inode)
|
|||
* inode when the usage count drops to zero, and
|
||||
* i_nlink is zero.
|
||||
*/
|
||||
static void generic_drop_inode(struct inode *inode)
|
||||
void generic_drop_inode(struct inode *inode)
|
||||
{
|
||||
if (!inode->i_nlink)
|
||||
generic_delete_inode(inode);
|
||||
|
|
@ -1060,6 +1102,8 @@ static void generic_drop_inode(struct inode *inode)
|
|||
generic_forget_inode(inode);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(generic_drop_inode);
|
||||
|
||||
/*
|
||||
* Called when we're dropping the last reference
|
||||
* to an inode.
|
||||
|
|
@ -1242,29 +1286,21 @@ int inode_wait(void *word)
|
|||
}
|
||||
|
||||
/*
|
||||
* If we try to find an inode in the inode hash while it is being deleted, we
|
||||
* have to wait until the filesystem completes its deletion before reporting
|
||||
* that it isn't found. This is because iget will immediately call
|
||||
* ->read_inode, and we want to be sure that evidence of the deletion is found
|
||||
* by ->read_inode.
|
||||
* If we try to find an inode in the inode hash while it is being
|
||||
* deleted, we have to wait until the filesystem completes its
|
||||
* deletion before reporting that it isn't found. This function waits
|
||||
* until the deletion _might_ have completed. Callers are responsible
|
||||
* to recheck inode state.
|
||||
*
|
||||
* It doesn't matter if I_LOCK is not set initially, a call to
|
||||
* wake_up_inode() after removing from the hash list will DTRT.
|
||||
*
|
||||
* This is called with inode_lock held.
|
||||
*/
|
||||
static void __wait_on_freeing_inode(struct inode *inode)
|
||||
{
|
||||
wait_queue_head_t *wq;
|
||||
DEFINE_WAIT_BIT(wait, &inode->i_state, __I_LOCK);
|
||||
|
||||
/*
|
||||
* I_FREEING and I_CLEAR are cleared in process context under
|
||||
* inode_lock, so we have to give the tasks who would clear them
|
||||
* a chance to run and acquire inode_lock.
|
||||
*/
|
||||
if (!(inode->i_state & I_LOCK)) {
|
||||
spin_unlock(&inode_lock);
|
||||
yield();
|
||||
spin_lock(&inode_lock);
|
||||
return;
|
||||
}
|
||||
wq = bit_waitqueue(&inode->i_state, __I_LOCK);
|
||||
prepare_to_wait(wq, &wait.wait, TASK_UNINTERRUPTIBLE);
|
||||
spin_unlock(&inode_lock);
|
||||
|
|
|
|||
1037
fs/inotify.c
Normal file
1037
fs/inotify.c
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -43,7 +43,7 @@ static int set_task_ioprio(struct task_struct *task, int ioprio)
|
|||
return 0;
|
||||
}
|
||||
|
||||
asmlinkage int sys_ioprio_set(int which, int who, int ioprio)
|
||||
asmlinkage long sys_ioprio_set(int which, int who, int ioprio)
|
||||
{
|
||||
int class = IOPRIO_PRIO_CLASS(ioprio);
|
||||
int data = IOPRIO_PRIO_DATA(ioprio);
|
||||
|
|
@ -115,7 +115,7 @@ asmlinkage int sys_ioprio_set(int which, int who, int ioprio)
|
|||
return ret;
|
||||
}
|
||||
|
||||
asmlinkage int sys_ioprio_get(int which, int who)
|
||||
asmlinkage long sys_ioprio_get(int which, int who)
|
||||
{
|
||||
struct task_struct *g, *p;
|
||||
struct user_struct *user;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#
|
||||
# Makefile for the Linux Journalling Flash File System v2 (JFFS2)
|
||||
#
|
||||
# $Id: Makefile.common,v 1.7 2004/11/03 12:57:38 jwboyer Exp $
|
||||
# $Id: Makefile.common,v 1.9 2005/02/09 09:23:53 pavlov Exp $
|
||||
#
|
||||
|
||||
obj-$(CONFIG_JFFS2_FS) += jffs2.o
|
||||
|
|
@ -11,8 +11,7 @@ jffs2-y += read.o nodemgmt.o readinode.o write.o scan.o gc.o
|
|||
jffs2-y += symlink.o build.o erase.o background.o fs.o writev.o
|
||||
jffs2-y += super.o
|
||||
|
||||
jffs2-$(CONFIG_JFFS2_FS_NAND) += wbuf.o
|
||||
jffs2-$(CONFIG_JFFS2_FS_NOR_ECC) += wbuf.o
|
||||
jffs2-$(CONFIG_JFFS2_FS_WRITEBUFFER) += wbuf.o
|
||||
jffs2-$(CONFIG_JFFS2_RUBIN) += compr_rubin.o
|
||||
jffs2-$(CONFIG_JFFS2_RTIME) += compr_rtime.o
|
||||
jffs2-$(CONFIG_JFFS2_ZLIB) += compr_zlib.o
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
$Id: README.Locking,v 1.9 2004/11/20 10:35:40 dwmw2 Exp $
|
||||
$Id: README.Locking,v 1.12 2005/04/13 13:22:35 dwmw2 Exp $
|
||||
|
||||
JFFS2 LOCKING DOCUMENTATION
|
||||
---------------------------
|
||||
|
|
@ -108,6 +108,10 @@ in-core jffs2_inode_cache objects (each inode in JFFS2 has the
|
|||
correspondent jffs2_inode_cache object). So, the inocache_lock
|
||||
has to be locked while walking the c->inocache_list hash buckets.
|
||||
|
||||
This spinlock also covers allocation of new inode numbers, which is
|
||||
currently just '++->highest_ino++', but might one day get more complicated
|
||||
if we need to deal with wrapping after 4 milliard inode numbers are used.
|
||||
|
||||
Note, the f->sem guarantees that the correspondent jffs2_inode_cache
|
||||
will not be removed. So, it is allowed to access it without locking
|
||||
the inocache_lock spinlock.
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* $Id: background.c,v 1.50 2004/11/16 20:36:10 dwmw2 Exp $
|
||||
* $Id: background.c,v 1.54 2005/05/20 21:37:12 gleixner Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -37,7 +37,7 @@ int jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c)
|
|||
if (c->gc_task)
|
||||
BUG();
|
||||
|
||||
init_MUTEX_LOCKED(&c->gc_thread_start);
|
||||
init_completion(&c->gc_thread_start);
|
||||
init_completion(&c->gc_thread_exit);
|
||||
|
||||
pid = kernel_thread(jffs2_garbage_collect_thread, c, CLONE_FS|CLONE_FILES);
|
||||
|
|
@ -48,7 +48,7 @@ int jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c)
|
|||
} else {
|
||||
/* Wait for it... */
|
||||
D1(printk(KERN_DEBUG "JFFS2: Garbage collect thread is pid %d\n", pid));
|
||||
down(&c->gc_thread_start);
|
||||
wait_for_completion(&c->gc_thread_start);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
@ -56,13 +56,16 @@ int jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c)
|
|||
|
||||
void jffs2_stop_garbage_collect_thread(struct jffs2_sb_info *c)
|
||||
{
|
||||
int wait = 0;
|
||||
spin_lock(&c->erase_completion_lock);
|
||||
if (c->gc_task) {
|
||||
D1(printk(KERN_DEBUG "jffs2: Killing GC task %d\n", c->gc_task->pid));
|
||||
send_sig(SIGKILL, c->gc_task, 1);
|
||||
wait = 1;
|
||||
}
|
||||
spin_unlock(&c->erase_completion_lock);
|
||||
wait_for_completion(&c->gc_thread_exit);
|
||||
if (wait)
|
||||
wait_for_completion(&c->gc_thread_exit);
|
||||
}
|
||||
|
||||
static int jffs2_garbage_collect_thread(void *_c)
|
||||
|
|
@ -75,7 +78,7 @@ static int jffs2_garbage_collect_thread(void *_c)
|
|||
allow_signal(SIGCONT);
|
||||
|
||||
c->gc_task = current;
|
||||
up(&c->gc_thread_start);
|
||||
complete(&c->gc_thread_start);
|
||||
|
||||
set_user_nice(current, 10);
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* $Id: build.c,v 1.69 2004/12/16 20:22:18 dmarlin Exp $
|
||||
* $Id: build.c,v 1.71 2005/07/12 16:37:08 dedekind Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -97,14 +97,16 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
|
|||
/* First, scan the medium and build all the inode caches with
|
||||
lists of physical nodes */
|
||||
|
||||
c->flags |= JFFS2_SB_FLAG_MOUNTING;
|
||||
c->flags |= JFFS2_SB_FLAG_SCANNING;
|
||||
ret = jffs2_scan_medium(c);
|
||||
c->flags &= ~JFFS2_SB_FLAG_SCANNING;
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
D1(printk(KERN_DEBUG "Scanned flash completely\n"));
|
||||
D2(jffs2_dump_block_lists(c));
|
||||
|
||||
c->flags |= JFFS2_SB_FLAG_BUILDING;
|
||||
/* Now scan the directory tree, increasing nlink according to every dirent found. */
|
||||
for_each_inode(i, c, ic) {
|
||||
D1(printk(KERN_DEBUG "Pass 1: ino #%u\n", ic->ino));
|
||||
|
|
@ -116,7 +118,6 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
|
|||
cond_resched();
|
||||
}
|
||||
}
|
||||
c->flags &= ~JFFS2_SB_FLAG_MOUNTING;
|
||||
|
||||
D1(printk(KERN_DEBUG "Pass 1 complete\n"));
|
||||
|
||||
|
|
@ -164,6 +165,8 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
|
|||
ic->scan_dents = NULL;
|
||||
cond_resched();
|
||||
}
|
||||
c->flags &= ~JFFS2_SB_FLAG_BUILDING;
|
||||
|
||||
D1(printk(KERN_DEBUG "Pass 3 complete\n"));
|
||||
D2(jffs2_dump_block_lists(c));
|
||||
|
||||
|
|
@ -333,13 +336,6 @@ int jffs2_do_mount_fs(struct jffs2_sb_info *c)
|
|||
c->blocks[i].bad_count = 0;
|
||||
}
|
||||
|
||||
init_MUTEX(&c->alloc_sem);
|
||||
init_MUTEX(&c->erase_free_sem);
|
||||
init_waitqueue_head(&c->erase_wait);
|
||||
init_waitqueue_head(&c->inocache_wq);
|
||||
spin_lock_init(&c->erase_completion_lock);
|
||||
spin_lock_init(&c->inocache_lock);
|
||||
|
||||
INIT_LIST_HEAD(&c->clean_list);
|
||||
INIT_LIST_HEAD(&c->very_dirty_list);
|
||||
INIT_LIST_HEAD(&c->dirty_list);
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* $Id: compr_zlib.c,v 1.29 2004/11/16 20:36:11 dwmw2 Exp $
|
||||
* $Id: compr_zlib.c,v 1.31 2005/05/20 19:30:06 gleixner Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -17,10 +17,10 @@
|
|||
|
||||
#include <linux/config.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/zlib.h>
|
||||
#include <linux/zutil.h>
|
||||
#include <asm/semaphore.h>
|
||||
#include "nodelist.h"
|
||||
#include "compr.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* $Id: dir.c,v 1.84 2004/11/16 20:36:11 dwmw2 Exp $
|
||||
* $Id: dir.c,v 1.86 2005/07/06 12:13:09 dwmw2 Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -22,16 +22,6 @@
|
|||
#include <linux/time.h>
|
||||
#include "nodelist.h"
|
||||
|
||||
/* Urgh. Please tell me there's a nicer way of doing these. */
|
||||
#include <linux/version.h>
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,48)
|
||||
typedef int mknod_arg_t;
|
||||
#define NAMEI_COMPAT(x) ((void *)x)
|
||||
#else
|
||||
typedef dev_t mknod_arg_t;
|
||||
#define NAMEI_COMPAT(x) (x)
|
||||
#endif
|
||||
|
||||
static int jffs2_readdir (struct file *, void *, filldir_t);
|
||||
|
||||
static int jffs2_create (struct inode *,struct dentry *,int,
|
||||
|
|
@ -43,7 +33,7 @@ static int jffs2_unlink (struct inode *,struct dentry *);
|
|||
static int jffs2_symlink (struct inode *,struct dentry *,const char *);
|
||||
static int jffs2_mkdir (struct inode *,struct dentry *,int);
|
||||
static int jffs2_rmdir (struct inode *,struct dentry *);
|
||||
static int jffs2_mknod (struct inode *,struct dentry *,int,mknod_arg_t);
|
||||
static int jffs2_mknod (struct inode *,struct dentry *,int,dev_t);
|
||||
static int jffs2_rename (struct inode *, struct dentry *,
|
||||
struct inode *, struct dentry *);
|
||||
|
||||
|
|
@ -58,8 +48,8 @@ struct file_operations jffs2_dir_operations =
|
|||
|
||||
struct inode_operations jffs2_dir_inode_operations =
|
||||
{
|
||||
.create = NAMEI_COMPAT(jffs2_create),
|
||||
.lookup = NAMEI_COMPAT(jffs2_lookup),
|
||||
.create = jffs2_create,
|
||||
.lookup = jffs2_lookup,
|
||||
.link = jffs2_link,
|
||||
.unlink = jffs2_unlink,
|
||||
.symlink = jffs2_symlink,
|
||||
|
|
@ -296,11 +286,11 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
|
|||
struct jffs2_full_dirent *fd;
|
||||
int namelen;
|
||||
uint32_t alloclen, phys_ofs;
|
||||
int ret;
|
||||
int ret, targetlen = strlen(target);
|
||||
|
||||
/* FIXME: If you care. We'd need to use frags for the target
|
||||
if it grows much more than this */
|
||||
if (strlen(target) > 254)
|
||||
if (targetlen > 254)
|
||||
return -EINVAL;
|
||||
|
||||
ri = jffs2_alloc_raw_inode();
|
||||
|
|
@ -314,7 +304,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
|
|||
* Just the node will do for now, though
|
||||
*/
|
||||
namelen = dentry->d_name.len;
|
||||
ret = jffs2_reserve_space(c, sizeof(*ri) + strlen(target), &phys_ofs, &alloclen, ALLOC_NORMAL);
|
||||
ret = jffs2_reserve_space(c, sizeof(*ri) + targetlen, &phys_ofs, &alloclen, ALLOC_NORMAL);
|
||||
|
||||
if (ret) {
|
||||
jffs2_free_raw_inode(ri);
|
||||
|
|
@ -333,16 +323,16 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
|
|||
|
||||
f = JFFS2_INODE_INFO(inode);
|
||||
|
||||
inode->i_size = strlen(target);
|
||||
inode->i_size = targetlen;
|
||||
ri->isize = ri->dsize = ri->csize = cpu_to_je32(inode->i_size);
|
||||
ri->totlen = cpu_to_je32(sizeof(*ri) + inode->i_size);
|
||||
ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4));
|
||||
|
||||
ri->compr = JFFS2_COMPR_NONE;
|
||||
ri->data_crc = cpu_to_je32(crc32(0, target, strlen(target)));
|
||||
ri->data_crc = cpu_to_je32(crc32(0, target, targetlen));
|
||||
ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
|
||||
|
||||
fn = jffs2_write_dnode(c, f, ri, target, strlen(target), phys_ofs, ALLOC_NORMAL);
|
||||
fn = jffs2_write_dnode(c, f, ri, target, targetlen, phys_ofs, ALLOC_NORMAL);
|
||||
|
||||
jffs2_free_raw_inode(ri);
|
||||
|
||||
|
|
@ -353,6 +343,20 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
|
|||
jffs2_clear_inode(inode);
|
||||
return PTR_ERR(fn);
|
||||
}
|
||||
|
||||
/* We use f->dents field to store the target path. */
|
||||
f->dents = kmalloc(targetlen + 1, GFP_KERNEL);
|
||||
if (!f->dents) {
|
||||
printk(KERN_WARNING "Can't allocate %d bytes of memory\n", targetlen + 1);
|
||||
up(&f->sem);
|
||||
jffs2_complete_reservation(c);
|
||||
jffs2_clear_inode(inode);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
memcpy(f->dents, target, targetlen + 1);
|
||||
D1(printk(KERN_DEBUG "jffs2_symlink: symlink's target '%s' cached\n", (char *)f->dents));
|
||||
|
||||
/* No data here. Only a metadata node, which will be
|
||||
obsoleted by the first data write
|
||||
*/
|
||||
|
|
@ -564,7 +568,7 @@ static int jffs2_rmdir (struct inode *dir_i, struct dentry *dentry)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, mknod_arg_t rdev)
|
||||
static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, dev_t rdev)
|
||||
{
|
||||
struct jffs2_inode_info *f, *dir_f;
|
||||
struct jffs2_sb_info *c;
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* $Id: erase.c,v 1.66 2004/11/16 20:36:11 dwmw2 Exp $
|
||||
* $Id: erase.c,v 1.76 2005/05/03 15:11:40 dedekind Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -48,6 +48,7 @@ static void jffs2_erase_block(struct jffs2_sb_info *c,
|
|||
#else /* Linux */
|
||||
struct erase_info *instr;
|
||||
|
||||
D1(printk(KERN_DEBUG "jffs2_erase_block(): erase block %#x (range %#x-%#x)\n", jeb->offset, jeb->offset, jeb->offset + c->sector_size));
|
||||
instr = kmalloc(sizeof(struct erase_info) + sizeof(struct erase_priv_struct), GFP_KERNEL);
|
||||
if (!instr) {
|
||||
printk(KERN_WARNING "kmalloc for struct erase_info in jffs2_erase_block failed. Refiling block for later\n");
|
||||
|
|
@ -233,7 +234,7 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c,
|
|||
continue;
|
||||
}
|
||||
|
||||
if (((*prev)->flash_offset & ~(c->sector_size -1)) == jeb->offset) {
|
||||
if (SECTOR_ADDR((*prev)->flash_offset) == jeb->offset) {
|
||||
/* It's in the block we're erasing */
|
||||
struct jffs2_raw_node_ref *this;
|
||||
|
||||
|
|
@ -277,11 +278,8 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c,
|
|||
printk("\n");
|
||||
});
|
||||
|
||||
if (ic->nodes == (void *)ic) {
|
||||
D1(printk(KERN_DEBUG "inocache for ino #%u is all gone now. Freeing\n", ic->ino));
|
||||
if (ic->nodes == (void *)ic && ic->nlink == 0)
|
||||
jffs2_del_ino_cache(c, ic);
|
||||
jffs2_free_inode_cache(ic);
|
||||
}
|
||||
}
|
||||
|
||||
static void jffs2_free_all_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
|
||||
|
|
@ -310,7 +308,7 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb
|
|||
int ret;
|
||||
uint32_t bad_offset;
|
||||
|
||||
if (!jffs2_cleanmarker_oob(c)) {
|
||||
if ((!jffs2_cleanmarker_oob(c)) && (c->cleanmarker_size > 0)) {
|
||||
marker_ref = jffs2_alloc_raw_node_ref();
|
||||
if (!marker_ref) {
|
||||
printk(KERN_WARNING "Failed to allocate raw node ref for clean marker\n");
|
||||
|
|
@ -335,7 +333,8 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb
|
|||
|
||||
bad_offset = ofs;
|
||||
|
||||
ret = jffs2_flash_read(c, ofs, readlen, &retlen, ebuf);
|
||||
ret = c->mtd->read(c->mtd, ofs, readlen, &retlen, ebuf);
|
||||
|
||||
if (ret) {
|
||||
printk(KERN_WARNING "Read of newly-erased block at 0x%08x failed: %d. Putting on bad_list\n", ofs, ret);
|
||||
goto bad;
|
||||
|
|
@ -351,7 +350,7 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb
|
|||
bad_offset += i;
|
||||
printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08x\n", datum, bad_offset);
|
||||
bad:
|
||||
if (!jffs2_cleanmarker_oob(c))
|
||||
if ((!jffs2_cleanmarker_oob(c)) && (c->cleanmarker_size > 0))
|
||||
jffs2_free_raw_node_ref(marker_ref);
|
||||
kfree(ebuf);
|
||||
bad2:
|
||||
|
|
@ -383,6 +382,13 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb
|
|||
|
||||
jeb->first_node = jeb->last_node = NULL;
|
||||
|
||||
jeb->free_size = c->sector_size;
|
||||
jeb->used_size = 0;
|
||||
jeb->dirty_size = 0;
|
||||
jeb->wasted_size = 0;
|
||||
} else if (c->cleanmarker_size == 0) {
|
||||
jeb->first_node = jeb->last_node = NULL;
|
||||
|
||||
jeb->free_size = c->sector_size;
|
||||
jeb->used_size = 0;
|
||||
jeb->dirty_size = 0;
|
||||
|
|
|
|||
|
|
@ -7,11 +7,10 @@
|
|||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* $Id: file.c,v 1.99 2004/11/16 20:36:11 dwmw2 Exp $
|
||||
* $Id: file.c,v 1.102 2005/07/06 12:13:09 dwmw2 Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/version.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/fs.h>
|
||||
|
|
@ -51,9 +50,7 @@ struct file_operations jffs2_file_operations =
|
|||
.ioctl = jffs2_ioctl,
|
||||
.mmap = generic_file_readonly_mmap,
|
||||
.fsync = jffs2_fsync,
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,29)
|
||||
.sendfile = generic_file_sendfile
|
||||
#endif
|
||||
};
|
||||
|
||||
/* jffs2_file_inode_operations */
|
||||
|
|
|
|||
|
|
@ -7,11 +7,10 @@
|
|||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* $Id: fs.c,v 1.51 2004/11/28 12:19:37 dedekind Exp $
|
||||
* $Id: fs.c,v 1.56 2005/07/06 12:13:09 dwmw2 Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/version.h>
|
||||
#include <linux/config.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
|
|
@ -450,11 +449,15 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent)
|
|||
|
||||
c = JFFS2_SB_INFO(sb);
|
||||
|
||||
#ifndef CONFIG_JFFS2_FS_NAND
|
||||
#ifndef CONFIG_JFFS2_FS_WRITEBUFFER
|
||||
if (c->mtd->type == MTD_NANDFLASH) {
|
||||
printk(KERN_ERR "jffs2: Cannot operate on NAND flash unless jffs2 NAND support is compiled in.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (c->mtd->type == MTD_DATAFLASH) {
|
||||
printk(KERN_ERR "jffs2: Cannot operate on DataFlash unless jffs2 DataFlash support is compiled in.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
c->flash_size = c->mtd->size;
|
||||
|
|
@ -522,9 +525,7 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent)
|
|||
if (!sb->s_root)
|
||||
goto out_root_i;
|
||||
|
||||
#if LINUX_VERSION_CODE >= 0x20403
|
||||
sb->s_maxbytes = 0xFFFFFFFF;
|
||||
#endif
|
||||
sb->s_blocksize = PAGE_CACHE_SIZE;
|
||||
sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
|
||||
sb->s_magic = JFFS2_SUPER_MAGIC;
|
||||
|
|
@ -661,6 +662,14 @@ static int jffs2_flash_setup(struct jffs2_sb_info *c) {
|
|||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* and Dataflash */
|
||||
if (jffs2_dataflash(c)) {
|
||||
ret = jffs2_dataflash_setup(c);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -674,4 +683,9 @@ void jffs2_flash_cleanup(struct jffs2_sb_info *c) {
|
|||
if (jffs2_nor_ecc(c)) {
|
||||
jffs2_nor_ecc_flash_cleanup(c);
|
||||
}
|
||||
|
||||
/* and DataFlash */
|
||||
if (jffs2_dataflash(c)) {
|
||||
jffs2_dataflash_cleanup(c);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* $Id: gc.c,v 1.144 2004/12/21 11:18:50 dwmw2 Exp $
|
||||
* $Id: gc.c,v 1.148 2005/04/09 10:47:00 dedekind Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -50,6 +50,7 @@ static struct jffs2_eraseblock *jffs2_find_gc_block(struct jffs2_sb_info *c)
|
|||
put the clever wear-levelling algorithms. Eventually. */
|
||||
/* We possibly want to favour the dirtier blocks more when the
|
||||
number of free blocks is low. */
|
||||
again:
|
||||
if (!list_empty(&c->bad_used_list) && c->nr_free_blocks > c->resv_blocks_gcbad) {
|
||||
D1(printk(KERN_DEBUG "Picking block from bad_used_list to GC next\n"));
|
||||
nextlist = &c->bad_used_list;
|
||||
|
|
@ -79,6 +80,13 @@ static struct jffs2_eraseblock *jffs2_find_gc_block(struct jffs2_sb_info *c)
|
|||
D1(printk(KERN_DEBUG "Picking block from erasable_list to GC next (clean_list and {very_,}dirty_list were empty)\n"));
|
||||
|
||||
nextlist = &c->erasable_list;
|
||||
} else if (!list_empty(&c->erasable_pending_wbuf_list)) {
|
||||
/* There are blocks are wating for the wbuf sync */
|
||||
D1(printk(KERN_DEBUG "Synching wbuf in order to reuse erasable_pending_wbuf_list blocks\n"));
|
||||
spin_unlock(&c->erase_completion_lock);
|
||||
jffs2_flush_wbuf_pad(c);
|
||||
spin_lock(&c->erase_completion_lock);
|
||||
goto again;
|
||||
} else {
|
||||
/* Eep. All were empty */
|
||||
D1(printk(KERN_NOTICE "jffs2: No clean, dirty _or_ erasable blocks to GC from! Where are they all?\n"));
|
||||
|
|
@ -661,9 +669,10 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_
|
|||
{
|
||||
struct jffs2_full_dnode *new_fn;
|
||||
struct jffs2_raw_inode ri;
|
||||
struct jffs2_node_frag *last_frag;
|
||||
jint16_t dev;
|
||||
char *mdata = NULL, mdatalen = 0;
|
||||
uint32_t alloclen, phys_ofs;
|
||||
uint32_t alloclen, phys_ofs, ilen;
|
||||
int ret;
|
||||
|
||||
if (S_ISBLK(JFFS2_F_I_MODE(f)) ||
|
||||
|
|
@ -699,6 +708,14 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_
|
|||
goto out;
|
||||
}
|
||||
|
||||
last_frag = frag_last(&f->fragtree);
|
||||
if (last_frag)
|
||||
/* Fetch the inode length from the fragtree rather then
|
||||
* from i_size since i_size may have not been updated yet */
|
||||
ilen = last_frag->ofs + last_frag->size;
|
||||
else
|
||||
ilen = JFFS2_F_I_SIZE(f);
|
||||
|
||||
memset(&ri, 0, sizeof(ri));
|
||||
ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
|
||||
ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
|
||||
|
|
@ -710,7 +727,7 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_
|
|||
ri.mode = cpu_to_jemode(JFFS2_F_I_MODE(f));
|
||||
ri.uid = cpu_to_je16(JFFS2_F_I_UID(f));
|
||||
ri.gid = cpu_to_je16(JFFS2_F_I_GID(f));
|
||||
ri.isize = cpu_to_je32(JFFS2_F_I_SIZE(f));
|
||||
ri.isize = cpu_to_je32(ilen);
|
||||
ri.atime = cpu_to_je32(JFFS2_F_I_ATIME(f));
|
||||
ri.ctime = cpu_to_je32(JFFS2_F_I_CTIME(f));
|
||||
ri.mtime = cpu_to_je32(JFFS2_F_I_MTIME(f));
|
||||
|
|
@ -816,8 +833,7 @@ static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct
|
|||
|
||||
/* Doesn't matter if there's one in the same erase block. We're going to
|
||||
delete it too at the same time. */
|
||||
if ((raw->flash_offset & ~(c->sector_size-1)) ==
|
||||
(fd->raw->flash_offset & ~(c->sector_size-1)))
|
||||
if (SECTOR_ADDR(raw->flash_offset) == SECTOR_ADDR(fd->raw->flash_offset))
|
||||
continue;
|
||||
|
||||
D1(printk(KERN_DEBUG "Check potential deletion dirent at %08x\n", ref_offset(raw)));
|
||||
|
|
@ -891,7 +907,7 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras
|
|||
struct jffs2_raw_inode ri;
|
||||
struct jffs2_node_frag *frag;
|
||||
struct jffs2_full_dnode *new_fn;
|
||||
uint32_t alloclen, phys_ofs;
|
||||
uint32_t alloclen, phys_ofs, ilen;
|
||||
int ret;
|
||||
|
||||
D1(printk(KERN_DEBUG "Writing replacement hole node for ino #%u from offset 0x%x to 0x%x\n",
|
||||
|
|
@ -951,10 +967,19 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras
|
|||
ri.csize = cpu_to_je32(0);
|
||||
ri.compr = JFFS2_COMPR_ZERO;
|
||||
}
|
||||
|
||||
frag = frag_last(&f->fragtree);
|
||||
if (frag)
|
||||
/* Fetch the inode length from the fragtree rather then
|
||||
* from i_size since i_size may have not been updated yet */
|
||||
ilen = frag->ofs + frag->size;
|
||||
else
|
||||
ilen = JFFS2_F_I_SIZE(f);
|
||||
|
||||
ri.mode = cpu_to_jemode(JFFS2_F_I_MODE(f));
|
||||
ri.uid = cpu_to_je16(JFFS2_F_I_UID(f));
|
||||
ri.gid = cpu_to_je16(JFFS2_F_I_GID(f));
|
||||
ri.isize = cpu_to_je32(JFFS2_F_I_SIZE(f));
|
||||
ri.isize = cpu_to_je32(ilen);
|
||||
ri.atime = cpu_to_je32(JFFS2_F_I_ATIME(f));
|
||||
ri.ctime = cpu_to_je32(JFFS2_F_I_CTIME(f));
|
||||
ri.mtime = cpu_to_je32(JFFS2_F_I_MTIME(f));
|
||||
|
|
@ -1161,7 +1186,7 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era
|
|||
D1(printk(KERN_DEBUG "Expanded dnode to write from (0x%x-0x%x) to (0x%x-0x%x)\n",
|
||||
orig_start, orig_end, start, end));
|
||||
|
||||
BUG_ON(end > JFFS2_F_I_SIZE(f));
|
||||
D1(BUG_ON(end > frag_last(&f->fragtree)->ofs + frag_last(&f->fragtree)->size));
|
||||
BUG_ON(end < orig_end);
|
||||
BUG_ON(start > orig_start);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* $Id: nodelist.c,v 1.90 2004/12/08 17:59:20 dwmw2 Exp $
|
||||
* $Id: nodelist.c,v 1.98 2005/07/10 15:15:32 dedekind Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -55,30 +55,63 @@ void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new
|
|||
});
|
||||
}
|
||||
|
||||
/* Put a new tmp_dnode_info into the list, keeping the list in
|
||||
order of increasing version
|
||||
*/
|
||||
static void jffs2_add_tn_to_list(struct jffs2_tmp_dnode_info *tn, struct jffs2_tmp_dnode_info **list)
|
||||
/*
|
||||
* Put a new tmp_dnode_info into the temporaty RB-tree, keeping the list in
|
||||
* order of increasing version.
|
||||
*/
|
||||
static void jffs2_add_tn_to_tree(struct jffs2_tmp_dnode_info *tn, struct rb_root *list)
|
||||
{
|
||||
struct jffs2_tmp_dnode_info **prev = list;
|
||||
|
||||
while ((*prev) && (*prev)->version < tn->version) {
|
||||
prev = &((*prev)->next);
|
||||
}
|
||||
tn->next = (*prev);
|
||||
*prev = tn;
|
||||
struct rb_node **p = &list->rb_node;
|
||||
struct rb_node * parent = NULL;
|
||||
struct jffs2_tmp_dnode_info *this;
|
||||
|
||||
while (*p) {
|
||||
parent = *p;
|
||||
this = rb_entry(parent, struct jffs2_tmp_dnode_info, rb);
|
||||
|
||||
/* There may actually be a collision here, but it doesn't
|
||||
actually matter. As long as the two nodes with the same
|
||||
version are together, it's all fine. */
|
||||
if (tn->version < this->version)
|
||||
p = &(*p)->rb_left;
|
||||
else
|
||||
p = &(*p)->rb_right;
|
||||
}
|
||||
|
||||
rb_link_node(&tn->rb, parent, p);
|
||||
rb_insert_color(&tn->rb, list);
|
||||
}
|
||||
|
||||
static void jffs2_free_tmp_dnode_info_list(struct jffs2_tmp_dnode_info *tn)
|
||||
static void jffs2_free_tmp_dnode_info_list(struct rb_root *list)
|
||||
{
|
||||
struct jffs2_tmp_dnode_info *next;
|
||||
struct rb_node *this;
|
||||
struct jffs2_tmp_dnode_info *tn;
|
||||
|
||||
while (tn) {
|
||||
next = tn;
|
||||
tn = tn->next;
|
||||
jffs2_free_full_dnode(next->fn);
|
||||
jffs2_free_tmp_dnode_info(next);
|
||||
this = list->rb_node;
|
||||
|
||||
/* Now at bottom of tree */
|
||||
while (this) {
|
||||
if (this->rb_left)
|
||||
this = this->rb_left;
|
||||
else if (this->rb_right)
|
||||
this = this->rb_right;
|
||||
else {
|
||||
tn = rb_entry(this, struct jffs2_tmp_dnode_info, rb);
|
||||
jffs2_free_full_dnode(tn->fn);
|
||||
jffs2_free_tmp_dnode_info(tn);
|
||||
|
||||
this = this->rb_parent;
|
||||
if (!this)
|
||||
break;
|
||||
|
||||
if (this->rb_left == &tn->rb)
|
||||
this->rb_left = NULL;
|
||||
else if (this->rb_right == &tn->rb)
|
||||
this->rb_right = NULL;
|
||||
else BUG();
|
||||
}
|
||||
}
|
||||
list->rb_node = NULL;
|
||||
}
|
||||
|
||||
static void jffs2_free_full_dirent_list(struct jffs2_full_dirent *fd)
|
||||
|
|
@ -108,12 +141,13 @@ static struct jffs2_raw_node_ref *jffs2_first_valid_node(struct jffs2_raw_node_r
|
|||
with this ino, returning the former in order of version */
|
||||
|
||||
int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
|
||||
struct jffs2_tmp_dnode_info **tnp, struct jffs2_full_dirent **fdp,
|
||||
struct rb_root *tnp, struct jffs2_full_dirent **fdp,
|
||||
uint32_t *highest_version, uint32_t *latest_mctime,
|
||||
uint32_t *mctime_ver)
|
||||
{
|
||||
struct jffs2_raw_node_ref *ref, *valid_ref;
|
||||
struct jffs2_tmp_dnode_info *tn, *ret_tn = NULL;
|
||||
struct jffs2_tmp_dnode_info *tn;
|
||||
struct rb_root ret_tn = RB_ROOT;
|
||||
struct jffs2_full_dirent *fd, *ret_fd = NULL;
|
||||
union jffs2_node_union node;
|
||||
size_t retlen;
|
||||
|
|
@ -127,7 +161,7 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
|
|||
|
||||
valid_ref = jffs2_first_valid_node(f->inocache->nodes);
|
||||
|
||||
if (!valid_ref)
|
||||
if (!valid_ref && (f->inocache->ino != 1))
|
||||
printk(KERN_WARNING "Eep. No valid nodes for ino #%u\n", f->inocache->ino);
|
||||
|
||||
while (valid_ref) {
|
||||
|
|
@ -386,7 +420,7 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
|
|||
D1(printk(KERN_DEBUG "dnode @%08x: ver %u, offset %04x, dsize %04x\n",
|
||||
ref_offset(ref), je32_to_cpu(node.i.version),
|
||||
je32_to_cpu(node.i.offset), je32_to_cpu(node.i.dsize)));
|
||||
jffs2_add_tn_to_list(tn, &ret_tn);
|
||||
jffs2_add_tn_to_tree(tn, &ret_tn);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -450,7 +484,7 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
|
|||
return 0;
|
||||
|
||||
free_out:
|
||||
jffs2_free_tmp_dnode_info_list(ret_tn);
|
||||
jffs2_free_tmp_dnode_info_list(&ret_tn);
|
||||
jffs2_free_full_dirent_list(ret_fd);
|
||||
return err;
|
||||
}
|
||||
|
|
@ -489,9 +523,13 @@ struct jffs2_inode_cache *jffs2_get_ino_cache(struct jffs2_sb_info *c, uint32_t
|
|||
void jffs2_add_ino_cache (struct jffs2_sb_info *c, struct jffs2_inode_cache *new)
|
||||
{
|
||||
struct jffs2_inode_cache **prev;
|
||||
D2(printk(KERN_DEBUG "jffs2_add_ino_cache: Add %p (ino #%u)\n", new, new->ino));
|
||||
|
||||
spin_lock(&c->inocache_lock);
|
||||
|
||||
if (!new->ino)
|
||||
new->ino = ++c->highest_ino;
|
||||
|
||||
D2(printk(KERN_DEBUG "jffs2_add_ino_cache: Add %p (ino #%u)\n", new, new->ino));
|
||||
|
||||
prev = &c->inocache_list[new->ino % INOCACHE_HASHSIZE];
|
||||
|
||||
while ((*prev) && (*prev)->ino < new->ino) {
|
||||
|
|
@ -506,7 +544,7 @@ void jffs2_add_ino_cache (struct jffs2_sb_info *c, struct jffs2_inode_cache *new
|
|||
void jffs2_del_ino_cache(struct jffs2_sb_info *c, struct jffs2_inode_cache *old)
|
||||
{
|
||||
struct jffs2_inode_cache **prev;
|
||||
D2(printk(KERN_DEBUG "jffs2_del_ino_cache: Del %p (ino #%u)\n", old, old->ino));
|
||||
D1(printk(KERN_DEBUG "jffs2_del_ino_cache: Del %p (ino #%u)\n", old, old->ino));
|
||||
spin_lock(&c->inocache_lock);
|
||||
|
||||
prev = &c->inocache_list[old->ino % INOCACHE_HASHSIZE];
|
||||
|
|
@ -518,6 +556,14 @@ void jffs2_del_ino_cache(struct jffs2_sb_info *c, struct jffs2_inode_cache *old)
|
|||
*prev = old->next;
|
||||
}
|
||||
|
||||
/* Free it now unless it's in READING or CLEARING state, which
|
||||
are the transitions upon read_inode() and clear_inode(). The
|
||||
rest of the time we know nobody else is looking at it, and
|
||||
if it's held by read_inode() or clear_inode() they'll free it
|
||||
for themselves. */
|
||||
if (old->state != INO_STATE_READING && old->state != INO_STATE_CLEARING)
|
||||
jffs2_free_inode_cache(old);
|
||||
|
||||
spin_unlock(&c->inocache_lock);
|
||||
}
|
||||
|
||||
|
|
@ -530,7 +576,6 @@ void jffs2_free_ino_caches(struct jffs2_sb_info *c)
|
|||
this = c->inocache_list[i];
|
||||
while (this) {
|
||||
next = this->next;
|
||||
D2(printk(KERN_DEBUG "jffs2_free_ino_caches: Freeing ino #%u at %p\n", this->ino, this));
|
||||
jffs2_free_inode_cache(this);
|
||||
this = next;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* $Id: nodelist.h,v 1.126 2004/11/19 15:06:29 dedekind Exp $
|
||||
* $Id: nodelist.h,v 1.131 2005/07/05 21:03:07 dwmw2 Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -135,6 +135,7 @@ struct jffs2_inode_cache {
|
|||
#define INO_STATE_CHECKEDABSENT 3 /* Checked, cleared again */
|
||||
#define INO_STATE_GC 4 /* GCing a 'pristine' node */
|
||||
#define INO_STATE_READING 5 /* In read_inode() */
|
||||
#define INO_STATE_CLEARING 6 /* In clear_inode() */
|
||||
|
||||
#define INOCACHE_HASHSIZE 128
|
||||
|
||||
|
|
@ -160,7 +161,7 @@ struct jffs2_full_dnode
|
|||
*/
|
||||
struct jffs2_tmp_dnode_info
|
||||
{
|
||||
struct jffs2_tmp_dnode_info *next;
|
||||
struct rb_node rb;
|
||||
struct jffs2_full_dnode *fn;
|
||||
uint32_t version;
|
||||
};
|
||||
|
|
@ -362,6 +363,18 @@ static inline struct jffs2_node_frag *frag_first(struct rb_root *root)
|
|||
node = node->rb_left;
|
||||
return rb_entry(node, struct jffs2_node_frag, rb);
|
||||
}
|
||||
|
||||
static inline struct jffs2_node_frag *frag_last(struct rb_root *root)
|
||||
{
|
||||
struct rb_node *node = root->rb_node;
|
||||
|
||||
if (!node)
|
||||
return NULL;
|
||||
while(node->rb_right)
|
||||
node = node->rb_right;
|
||||
return rb_entry(node, struct jffs2_node_frag, rb);
|
||||
}
|
||||
|
||||
#define rb_parent(rb) ((rb)->rb_parent)
|
||||
#define frag_next(frag) rb_entry(rb_next(&(frag)->rb), struct jffs2_node_frag, rb)
|
||||
#define frag_prev(frag) rb_entry(rb_prev(&(frag)->rb), struct jffs2_node_frag, rb)
|
||||
|
|
@ -374,7 +387,7 @@ static inline struct jffs2_node_frag *frag_first(struct rb_root *root)
|
|||
D2(void jffs2_print_frag_list(struct jffs2_inode_info *f));
|
||||
void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new, struct jffs2_full_dirent **list);
|
||||
int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
|
||||
struct jffs2_tmp_dnode_info **tnp, struct jffs2_full_dirent **fdp,
|
||||
struct rb_root *tnp, struct jffs2_full_dirent **fdp,
|
||||
uint32_t *highest_version, uint32_t *latest_mctime,
|
||||
uint32_t *mctime_ver);
|
||||
void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, int state);
|
||||
|
|
@ -462,7 +475,7 @@ int jffs2_do_mount_fs(struct jffs2_sb_info *c);
|
|||
/* erase.c */
|
||||
void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count);
|
||||
|
||||
#ifdef CONFIG_JFFS2_FS_NAND
|
||||
#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
|
||||
/* wbuf.c */
|
||||
int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino);
|
||||
int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c);
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* $Id: nodemgmt.c,v 1.115 2004/11/22 11:07:21 dwmw2 Exp $
|
||||
* $Id: nodemgmt.c,v 1.122 2005/05/06 09:30:27 dedekind Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -75,7 +75,7 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs
|
|||
dirty = c->dirty_size + c->erasing_size - c->nr_erasing_blocks * c->sector_size + c->unchecked_size;
|
||||
if (dirty < c->nospc_dirty_size) {
|
||||
if (prio == ALLOC_DELETION && c->nr_free_blocks + c->nr_erasing_blocks >= c->resv_blocks_deletion) {
|
||||
printk(KERN_NOTICE "jffs2_reserve_space(): Low on dirty space to GC, but it's a deletion. Allowing...\n");
|
||||
D1(printk(KERN_NOTICE "jffs2_reserve_space(): Low on dirty space to GC, but it's a deletion. Allowing...\n"));
|
||||
break;
|
||||
}
|
||||
D1(printk(KERN_DEBUG "dirty size 0x%08x + unchecked_size 0x%08x < nospc_dirty_size 0x%08x, returning -ENOSPC\n",
|
||||
|
|
@ -98,7 +98,7 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs
|
|||
avail = c->free_size + c->dirty_size + c->erasing_size + c->unchecked_size;
|
||||
if ( (avail / c->sector_size) <= blocksneeded) {
|
||||
if (prio == ALLOC_DELETION && c->nr_free_blocks + c->nr_erasing_blocks >= c->resv_blocks_deletion) {
|
||||
printk(KERN_NOTICE "jffs2_reserve_space(): Low on possibly available space, but it's a deletion. Allowing...\n");
|
||||
D1(printk(KERN_NOTICE "jffs2_reserve_space(): Low on possibly available space, but it's a deletion. Allowing...\n"));
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -308,7 +308,10 @@ int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_r
|
|||
|
||||
D1(printk(KERN_DEBUG "jffs2_add_physical_node_ref(): Node at 0x%x(%d), size 0x%x\n", ref_offset(new), ref_flags(new), len));
|
||||
#if 1
|
||||
if (jeb != c->nextblock || (ref_offset(new)) != jeb->offset + (c->sector_size - jeb->free_size)) {
|
||||
/* we could get some obsolete nodes after nextblock was refiled
|
||||
in wbuf.c */
|
||||
if ((c->nextblock || !ref_obsolete(new))
|
||||
&&(jeb != c->nextblock || ref_offset(new) != jeb->offset + (c->sector_size - jeb->free_size))) {
|
||||
printk(KERN_WARNING "argh. node added in wrong place\n");
|
||||
jffs2_free_raw_node_ref(new);
|
||||
return -EINVAL;
|
||||
|
|
@ -332,7 +335,7 @@ int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_r
|
|||
c->used_size += len;
|
||||
}
|
||||
|
||||
if (!jeb->free_size && !jeb->dirty_size) {
|
||||
if (!jeb->free_size && !jeb->dirty_size && !ISDIRTY(jeb->wasted_size)) {
|
||||
/* If it lives on the dirty_list, jffs2_reserve_space will put it there */
|
||||
D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to clean_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
|
||||
jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
|
||||
|
|
@ -400,7 +403,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
|
|||
jeb = &c->blocks[blocknr];
|
||||
|
||||
if (jffs2_can_mark_obsolete(c) && !jffs2_is_readonly(c) &&
|
||||
!(c->flags & JFFS2_SB_FLAG_MOUNTING)) {
|
||||
!(c->flags & (JFFS2_SB_FLAG_SCANNING | JFFS2_SB_FLAG_BUILDING))) {
|
||||
/* Hm. This may confuse static lock analysis. If any of the above
|
||||
three conditions is false, we're going to return from this
|
||||
function without actually obliterating any nodes or freeing
|
||||
|
|
@ -434,7 +437,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
|
|||
|
||||
// Take care, that wasted size is taken into concern
|
||||
if ((jeb->dirty_size || ISDIRTY(jeb->wasted_size + ref_totlen(c, jeb, ref))) && jeb != c->nextblock) {
|
||||
D1(printk("Dirtying\n"));
|
||||
D1(printk(KERN_DEBUG "Dirtying\n"));
|
||||
addedsize = ref_totlen(c, jeb, ref);
|
||||
jeb->dirty_size += ref_totlen(c, jeb, ref);
|
||||
c->dirty_size += ref_totlen(c, jeb, ref);
|
||||
|
|
@ -456,7 +459,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
|
|||
}
|
||||
}
|
||||
} else {
|
||||
D1(printk("Wasting\n"));
|
||||
D1(printk(KERN_DEBUG "Wasting\n"));
|
||||
addedsize = 0;
|
||||
jeb->wasted_size += ref_totlen(c, jeb, ref);
|
||||
c->wasted_size += ref_totlen(c, jeb, ref);
|
||||
|
|
@ -467,8 +470,8 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
|
|||
|
||||
D1(ACCT_PARANOIA_CHECK(jeb));
|
||||
|
||||
if (c->flags & JFFS2_SB_FLAG_MOUNTING) {
|
||||
/* Mount in progress. Don't muck about with the block
|
||||
if (c->flags & JFFS2_SB_FLAG_SCANNING) {
|
||||
/* Flash scanning is in progress. Don't muck about with the block
|
||||
lists because they're not ready yet, and don't actually
|
||||
obliterate nodes that look obsolete. If they weren't
|
||||
marked obsolete on the flash at the time they _became_
|
||||
|
|
@ -527,7 +530,8 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
|
|||
|
||||
spin_unlock(&c->erase_completion_lock);
|
||||
|
||||
if (!jffs2_can_mark_obsolete(c) || jffs2_is_readonly(c)) {
|
||||
if (!jffs2_can_mark_obsolete(c) || jffs2_is_readonly(c) ||
|
||||
(c->flags & JFFS2_SB_FLAG_BUILDING)) {
|
||||
/* We didn't lock the erase_free_sem */
|
||||
return;
|
||||
}
|
||||
|
|
@ -590,11 +594,8 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
|
|||
*p = ref->next_in_ino;
|
||||
ref->next_in_ino = NULL;
|
||||
|
||||
if (ic->nodes == (void *)ic) {
|
||||
D1(printk(KERN_DEBUG "inocache for ino #%u is all gone now. Freeing\n", ic->ino));
|
||||
if (ic->nodes == (void *)ic && ic->nlink == 0)
|
||||
jffs2_del_ino_cache(c, ic);
|
||||
jffs2_free_inode_cache(ic);
|
||||
}
|
||||
|
||||
spin_unlock(&c->erase_completion_lock);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,41 +7,24 @@
|
|||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* $Id: os-linux.h,v 1.51 2004/11/16 20:36:11 dwmw2 Exp $
|
||||
* $Id: os-linux.h,v 1.58 2005/07/12 02:34:35 tpoynor Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __JFFS2_OS_LINUX_H__
|
||||
#define __JFFS2_OS_LINUX_H__
|
||||
#include <linux/version.h>
|
||||
|
||||
/* JFFS2 uses Linux mode bits natively -- no need for conversion */
|
||||
#define os_to_jffs2_mode(x) (x)
|
||||
#define jffs2_to_os_mode(x) (x)
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,73)
|
||||
#define kstatfs statfs
|
||||
#endif
|
||||
|
||||
struct kstatfs;
|
||||
struct kvec;
|
||||
|
||||
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2)
|
||||
#define JFFS2_INODE_INFO(i) (list_entry(i, struct jffs2_inode_info, vfs_inode))
|
||||
#define OFNI_EDONI_2SFFJ(f) (&(f)->vfs_inode)
|
||||
#define JFFS2_SB_INFO(sb) (sb->s_fs_info)
|
||||
#define OFNI_BS_2SFFJ(c) ((struct super_block *)c->os_priv)
|
||||
#elif defined(JFFS2_OUT_OF_KERNEL)
|
||||
#define JFFS2_INODE_INFO(i) ((struct jffs2_inode_info *) &(i)->u)
|
||||
#define OFNI_EDONI_2SFFJ(f) ((struct inode *) ( ((char *)f) - ((char *)(&((struct inode *)NULL)->u)) ) )
|
||||
#define JFFS2_SB_INFO(sb) ((struct jffs2_sb_info *) &(sb)->u)
|
||||
#define OFNI_BS_2SFFJ(c) ((struct super_block *) ( ((char *)c) - ((char *)(&((struct super_block *)NULL)->u)) ) )
|
||||
#else
|
||||
#define JFFS2_INODE_INFO(i) (&i->u.jffs2_i)
|
||||
#define OFNI_EDONI_2SFFJ(f) ((struct inode *) ( ((char *)f) - ((char *)(&((struct inode *)NULL)->u)) ) )
|
||||
#define JFFS2_SB_INFO(sb) (&sb->u.jffs2_sb)
|
||||
#define OFNI_BS_2SFFJ(c) ((struct super_block *) ( ((char *)c) - ((char *)(&((struct super_block *)NULL)->u)) ) )
|
||||
#endif
|
||||
|
||||
|
||||
#define JFFS2_F_I_SIZE(f) (OFNI_EDONI_2SFFJ(f)->i_size)
|
||||
|
|
@ -49,28 +32,14 @@ struct kvec;
|
|||
#define JFFS2_F_I_UID(f) (OFNI_EDONI_2SFFJ(f)->i_uid)
|
||||
#define JFFS2_F_I_GID(f) (OFNI_EDONI_2SFFJ(f)->i_gid)
|
||||
|
||||
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,1)
|
||||
#define JFFS2_F_I_RDEV_MIN(f) (iminor(OFNI_EDONI_2SFFJ(f)))
|
||||
#define JFFS2_F_I_RDEV_MAJ(f) (imajor(OFNI_EDONI_2SFFJ(f)))
|
||||
#else
|
||||
#define JFFS2_F_I_RDEV_MIN(f) (MINOR(to_kdev_t(OFNI_EDONI_2SFFJ(f)->i_rdev)))
|
||||
#define JFFS2_F_I_RDEV_MAJ(f) (MAJOR(to_kdev_t(OFNI_EDONI_2SFFJ(f)->i_rdev)))
|
||||
#endif
|
||||
|
||||
/* Urgh. The things we do to keep the 2.4 build working */
|
||||
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,47)
|
||||
#define ITIME(sec) ((struct timespec){sec, 0})
|
||||
#define I_SEC(tv) ((tv).tv_sec)
|
||||
#define JFFS2_F_I_CTIME(f) (OFNI_EDONI_2SFFJ(f)->i_ctime.tv_sec)
|
||||
#define JFFS2_F_I_MTIME(f) (OFNI_EDONI_2SFFJ(f)->i_mtime.tv_sec)
|
||||
#define JFFS2_F_I_ATIME(f) (OFNI_EDONI_2SFFJ(f)->i_atime.tv_sec)
|
||||
#else
|
||||
#define ITIME(x) (x)
|
||||
#define I_SEC(x) (x)
|
||||
#define JFFS2_F_I_CTIME(f) (OFNI_EDONI_2SFFJ(f)->i_ctime)
|
||||
#define JFFS2_F_I_MTIME(f) (OFNI_EDONI_2SFFJ(f)->i_mtime)
|
||||
#define JFFS2_F_I_ATIME(f) (OFNI_EDONI_2SFFJ(f)->i_atime)
|
||||
#endif
|
||||
|
||||
#define sleep_on_spinunlock(wq, s) \
|
||||
do { \
|
||||
|
|
@ -84,23 +53,21 @@ struct kvec;
|
|||
|
||||
static inline void jffs2_init_inode_info(struct jffs2_inode_info *f)
|
||||
{
|
||||
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2)
|
||||
f->highest_version = 0;
|
||||
f->fragtree = RB_ROOT;
|
||||
f->metadata = NULL;
|
||||
f->dents = NULL;
|
||||
f->flags = 0;
|
||||
f->usercompr = 0;
|
||||
#else
|
||||
memset(f, 0, sizeof(*f));
|
||||
init_MUTEX_LOCKED(&f->sem);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#define jffs2_is_readonly(c) (OFNI_BS_2SFFJ(c)->s_flags & MS_RDONLY)
|
||||
|
||||
#if (!defined CONFIG_JFFS2_FS_NAND && !defined CONFIG_JFFS2_FS_NOR_ECC)
|
||||
#ifndef CONFIG_JFFS2_FS_WRITEBUFFER
|
||||
#define SECTOR_ADDR(x) ( ((unsigned long)(x) & ~(c->sector_size-1)) )
|
||||
#define jffs2_can_mark_obsolete(c) (1)
|
||||
#define jffs2_is_writebuffered(c) (0)
|
||||
#define jffs2_cleanmarker_oob(c) (0)
|
||||
#define jffs2_write_nand_cleanmarker(c,jeb) (-EIO)
|
||||
|
||||
|
|
@ -116,11 +83,16 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f)
|
|||
#define jffs2_wbuf_timeout NULL
|
||||
#define jffs2_wbuf_process NULL
|
||||
#define jffs2_nor_ecc(c) (0)
|
||||
#define jffs2_dataflash(c) (0)
|
||||
#define jffs2_nor_ecc_flash_setup(c) (0)
|
||||
#define jffs2_nor_ecc_flash_cleanup(c) do {} while (0)
|
||||
#define jffs2_dataflash_setup(c) (0)
|
||||
#define jffs2_dataflash_cleanup(c) do {} while (0)
|
||||
|
||||
#else /* NAND and/or ECC'd NOR support present */
|
||||
|
||||
#define jffs2_is_writebuffered(c) (c->wbuf != NULL)
|
||||
#define SECTOR_ADDR(x) ( ((unsigned long)(x) / (unsigned long)(c->sector_size)) * c->sector_size )
|
||||
#define jffs2_can_mark_obsolete(c) ((c->mtd->type == MTD_NORFLASH && !(c->mtd->flags & MTD_ECC)) || c->mtd->type == MTD_RAM)
|
||||
#define jffs2_cleanmarker_oob(c) (c->mtd->type == MTD_NANDFLASH)
|
||||
|
||||
|
|
@ -142,16 +114,16 @@ int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino);
|
|||
int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c);
|
||||
int jffs2_nand_flash_setup(struct jffs2_sb_info *c);
|
||||
void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c);
|
||||
#ifdef CONFIG_JFFS2_FS_NOR_ECC
|
||||
|
||||
#define jffs2_nor_ecc(c) (c->mtd->type == MTD_NORFLASH && (c->mtd->flags & MTD_ECC))
|
||||
int jffs2_nor_ecc_flash_setup(struct jffs2_sb_info *c);
|
||||
void jffs2_nor_ecc_flash_cleanup(struct jffs2_sb_info *c);
|
||||
#else
|
||||
#define jffs2_nor_ecc(c) (0)
|
||||
#define jffs2_nor_ecc_flash_setup(c) (0)
|
||||
#define jffs2_nor_ecc_flash_cleanup(c) do {} while (0)
|
||||
#endif /* NOR ECC */
|
||||
#endif /* NAND */
|
||||
|
||||
#define jffs2_dataflash(c) (c->mtd->type == MTD_DATAFLASH)
|
||||
int jffs2_dataflash_setup(struct jffs2_sb_info *c);
|
||||
void jffs2_dataflash_cleanup(struct jffs2_sb_info *c);
|
||||
|
||||
#endif /* WRITEBUFFER */
|
||||
|
||||
/* erase.c */
|
||||
static inline void jffs2_erase_pending_trigger(struct jffs2_sb_info *c)
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* $Id: read.c,v 1.38 2004/11/16 20:36:12 dwmw2 Exp $
|
||||
* $Id: read.c,v 1.39 2005/03/01 10:34:03 dedekind Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -214,33 +214,3 @@ int jffs2_read_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Core function to read symlink target. */
|
||||
char *jffs2_getlink(struct jffs2_sb_info *c, struct jffs2_inode_info *f)
|
||||
{
|
||||
char *buf;
|
||||
int ret;
|
||||
|
||||
down(&f->sem);
|
||||
|
||||
if (!f->metadata) {
|
||||
printk(KERN_NOTICE "No metadata for symlink inode #%u\n", f->inocache->ino);
|
||||
up(&f->sem);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
buf = kmalloc(f->metadata->size+1, GFP_USER);
|
||||
if (!buf) {
|
||||
up(&f->sem);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
buf[f->metadata->size]=0;
|
||||
|
||||
ret = jffs2_read_dnode(c, f, f->metadata, buf, 0, f->metadata->size);
|
||||
|
||||
up(&f->sem);
|
||||
|
||||
if (ret) {
|
||||
kfree(buf);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* $Id: readinode.c,v 1.117 2004/11/20 18:06:54 dwmw2 Exp $
|
||||
* $Id: readinode.c,v 1.125 2005/07/10 13:13:55 dedekind Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -151,6 +151,9 @@ int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_in
|
|||
|
||||
D1(printk(KERN_DEBUG "jffs2_add_full_dnode_to_inode(ino #%u, f %p, fn %p)\n", f->inocache->ino, f, fn));
|
||||
|
||||
if (unlikely(!fn->size))
|
||||
return 0;
|
||||
|
||||
newfrag = jffs2_alloc_node_frag();
|
||||
if (unlikely(!newfrag))
|
||||
return -ENOMEM;
|
||||
|
|
@ -158,11 +161,6 @@ int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_in
|
|||
D2(printk(KERN_DEBUG "adding node %04x-%04x @0x%08x on flash, newfrag *%p\n",
|
||||
fn->ofs, fn->ofs+fn->size, ref_offset(fn->raw), newfrag));
|
||||
|
||||
if (unlikely(!fn->size)) {
|
||||
jffs2_free_node_frag(newfrag);
|
||||
return 0;
|
||||
}
|
||||
|
||||
newfrag->ofs = fn->ofs;
|
||||
newfrag->size = fn->size;
|
||||
newfrag->node = fn;
|
||||
|
|
@ -500,7 +498,9 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
|
|||
struct jffs2_inode_info *f,
|
||||
struct jffs2_raw_inode *latest_node)
|
||||
{
|
||||
struct jffs2_tmp_dnode_info *tn_list, *tn;
|
||||
struct jffs2_tmp_dnode_info *tn = NULL;
|
||||
struct rb_root tn_list;
|
||||
struct rb_node *rb, *repl_rb;
|
||||
struct jffs2_full_dirent *fd_list;
|
||||
struct jffs2_full_dnode *fn = NULL;
|
||||
uint32_t crc;
|
||||
|
|
@ -522,9 +522,10 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
|
|||
}
|
||||
f->dents = fd_list;
|
||||
|
||||
while (tn_list) {
|
||||
tn = tn_list;
|
||||
rb = rb_first(&tn_list);
|
||||
|
||||
while (rb) {
|
||||
tn = rb_entry(rb, struct jffs2_tmp_dnode_info, rb);
|
||||
fn = tn->fn;
|
||||
|
||||
if (f->metadata) {
|
||||
|
|
@ -556,7 +557,29 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
|
|||
mdata_ver = tn->version;
|
||||
}
|
||||
next_tn:
|
||||
tn_list = tn->next;
|
||||
BUG_ON(rb->rb_left);
|
||||
if (rb->rb_parent && rb->rb_parent->rb_left == rb) {
|
||||
/* We were then left-hand child of our parent. We need
|
||||
to move our own right-hand child into our place. */
|
||||
repl_rb = rb->rb_right;
|
||||
if (repl_rb)
|
||||
repl_rb->rb_parent = rb->rb_parent;
|
||||
} else
|
||||
repl_rb = NULL;
|
||||
|
||||
rb = rb_next(rb);
|
||||
|
||||
/* Remove the spent tn from the tree; don't bother rebalancing
|
||||
but put our right-hand child in our own place. */
|
||||
if (tn->rb.rb_parent) {
|
||||
if (tn->rb.rb_parent->rb_left == &tn->rb)
|
||||
tn->rb.rb_parent->rb_left = repl_rb;
|
||||
else if (tn->rb.rb_parent->rb_right == &tn->rb)
|
||||
tn->rb.rb_parent->rb_right = repl_rb;
|
||||
else BUG();
|
||||
} else if (tn->rb.rb_right)
|
||||
tn->rb.rb_right->rb_parent = NULL;
|
||||
|
||||
jffs2_free_tmp_dnode_info(tn);
|
||||
}
|
||||
D1(jffs2_sanitycheck_fragtree(f));
|
||||
|
|
@ -623,6 +646,40 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
|
|||
case. */
|
||||
if (!je32_to_cpu(latest_node->isize))
|
||||
latest_node->isize = latest_node->dsize;
|
||||
|
||||
if (f->inocache->state != INO_STATE_CHECKING) {
|
||||
/* Symlink's inode data is the target path. Read it and
|
||||
* keep in RAM to facilitate quick follow symlink operation.
|
||||
* We use f->dents field to store the target path, which
|
||||
* is somewhat ugly. */
|
||||
f->dents = kmalloc(je32_to_cpu(latest_node->csize) + 1, GFP_KERNEL);
|
||||
if (!f->dents) {
|
||||
printk(KERN_WARNING "Can't allocate %d bytes of memory "
|
||||
"for the symlink target path cache\n",
|
||||
je32_to_cpu(latest_node->csize));
|
||||
up(&f->sem);
|
||||
jffs2_do_clear_inode(c, f);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = jffs2_flash_read(c, ref_offset(fn->raw) + sizeof(*latest_node),
|
||||
je32_to_cpu(latest_node->csize), &retlen, (char *)f->dents);
|
||||
|
||||
if (ret || retlen != je32_to_cpu(latest_node->csize)) {
|
||||
if (retlen != je32_to_cpu(latest_node->csize))
|
||||
ret = -EIO;
|
||||
kfree(f->dents);
|
||||
f->dents = NULL;
|
||||
up(&f->sem);
|
||||
jffs2_do_clear_inode(c, f);
|
||||
return -ret;
|
||||
}
|
||||
|
||||
((char *)f->dents)[je32_to_cpu(latest_node->csize)] = '\0';
|
||||
D1(printk(KERN_DEBUG "jffs2_do_read_inode(): symlink's target '%s' cached\n",
|
||||
(char *)f->dents));
|
||||
}
|
||||
|
||||
/* fall through... */
|
||||
|
||||
case S_IFBLK:
|
||||
|
|
@ -672,6 +729,9 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f)
|
|||
down(&f->sem);
|
||||
deleted = f->inocache && !f->inocache->nlink;
|
||||
|
||||
if (f->inocache && f->inocache->state != INO_STATE_CHECKING)
|
||||
jffs2_set_inocache_state(c, f->inocache, INO_STATE_CLEARING);
|
||||
|
||||
if (f->metadata) {
|
||||
if (deleted)
|
||||
jffs2_mark_node_obsolete(c, f->metadata->raw);
|
||||
|
|
@ -680,16 +740,27 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f)
|
|||
|
||||
jffs2_kill_fragtree(&f->fragtree, deleted?c:NULL);
|
||||
|
||||
fds = f->dents;
|
||||
/* For symlink inodes we us f->dents to store the target path name */
|
||||
if (S_ISLNK(OFNI_EDONI_2SFFJ(f)->i_mode)) {
|
||||
if (f->dents) {
|
||||
kfree(f->dents);
|
||||
f->dents = NULL;
|
||||
}
|
||||
} else {
|
||||
fds = f->dents;
|
||||
|
||||
while(fds) {
|
||||
fd = fds;
|
||||
fds = fd->next;
|
||||
jffs2_free_full_dirent(fd);
|
||||
while(fds) {
|
||||
fd = fds;
|
||||
fds = fd->next;
|
||||
jffs2_free_full_dirent(fd);
|
||||
}
|
||||
}
|
||||
|
||||
if (f->inocache && f->inocache->state != INO_STATE_CHECKING)
|
||||
if (f->inocache && f->inocache->state != INO_STATE_CHECKING) {
|
||||
jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT);
|
||||
if (f->inocache->nodes == (void *)f->inocache)
|
||||
jffs2_del_ino_cache(c, f->inocache);
|
||||
}
|
||||
|
||||
up(&f->sem);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* $Id: scan.c,v 1.115 2004/11/17 12:59:08 dedekind Exp $
|
||||
* $Id: scan.c,v 1.119 2005/02/17 17:51:13 dedekind Exp $
|
||||
*
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
|
|
@ -19,7 +19,7 @@
|
|||
#include <linux/compiler.h>
|
||||
#include "nodelist.h"
|
||||
|
||||
#define EMPTY_SCAN_SIZE 1024
|
||||
#define DEFAULT_EMPTY_SCAN_SIZE 1024
|
||||
|
||||
#define DIRTY_SPACE(x) do { typeof(x) _x = (x); \
|
||||
c->free_size -= _x; c->dirty_size += _x; \
|
||||
|
|
@ -68,13 +68,21 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo
|
|||
static inline int min_free(struct jffs2_sb_info *c)
|
||||
{
|
||||
uint32_t min = 2 * sizeof(struct jffs2_raw_inode);
|
||||
#if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC
|
||||
#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
|
||||
if (!jffs2_can_mark_obsolete(c) && min < c->wbuf_pagesize)
|
||||
return c->wbuf_pagesize;
|
||||
#endif
|
||||
return min;
|
||||
|
||||
}
|
||||
|
||||
static inline uint32_t EMPTY_SCAN_SIZE(uint32_t sector_size) {
|
||||
if (sector_size < DEFAULT_EMPTY_SCAN_SIZE)
|
||||
return sector_size;
|
||||
else
|
||||
return DEFAULT_EMPTY_SCAN_SIZE;
|
||||
}
|
||||
|
||||
int jffs2_scan_medium(struct jffs2_sb_info *c)
|
||||
{
|
||||
int i, ret;
|
||||
|
|
@ -220,7 +228,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
|
|||
c->dirty_size -= c->nextblock->dirty_size;
|
||||
c->nextblock->dirty_size = 0;
|
||||
}
|
||||
#if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC
|
||||
#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
|
||||
if (!jffs2_can_mark_obsolete(c) && c->nextblock && (c->nextblock->free_size & (c->wbuf_pagesize-1))) {
|
||||
/* If we're going to start writing into a block which already
|
||||
contains data, and the end of the data isn't page-aligned,
|
||||
|
|
@ -286,7 +294,7 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
|
|||
uint32_t hdr_crc, buf_ofs, buf_len;
|
||||
int err;
|
||||
int noise = 0;
|
||||
#ifdef CONFIG_JFFS2_FS_NAND
|
||||
#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
|
||||
int cleanmarkerfound = 0;
|
||||
#endif
|
||||
|
||||
|
|
@ -295,7 +303,7 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
|
|||
|
||||
D1(printk(KERN_DEBUG "jffs2_scan_eraseblock(): Scanning block at 0x%x\n", ofs));
|
||||
|
||||
#ifdef CONFIG_JFFS2_FS_NAND
|
||||
#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
|
||||
if (jffs2_cleanmarker_oob(c)) {
|
||||
int ret = jffs2_check_nand_cleanmarker(c, jeb);
|
||||
D2(printk(KERN_NOTICE "jffs_check_nand_cleanmarker returned %d\n",ret));
|
||||
|
|
@ -316,7 +324,7 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
|
|||
if (!buf_size) {
|
||||
buf_len = c->sector_size;
|
||||
} else {
|
||||
buf_len = EMPTY_SCAN_SIZE;
|
||||
buf_len = EMPTY_SCAN_SIZE(c->sector_size);
|
||||
err = jffs2_fill_scan_buf(c, buf, buf_ofs, buf_len);
|
||||
if (err)
|
||||
return err;
|
||||
|
|
@ -326,11 +334,11 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
|
|||
ofs = 0;
|
||||
|
||||
/* Scan only 4KiB of 0xFF before declaring it's empty */
|
||||
while(ofs < EMPTY_SCAN_SIZE && *(uint32_t *)(&buf[ofs]) == 0xFFFFFFFF)
|
||||
while(ofs < EMPTY_SCAN_SIZE(c->sector_size) && *(uint32_t *)(&buf[ofs]) == 0xFFFFFFFF)
|
||||
ofs += 4;
|
||||
|
||||
if (ofs == EMPTY_SCAN_SIZE) {
|
||||
#ifdef CONFIG_JFFS2_FS_NAND
|
||||
if (ofs == EMPTY_SCAN_SIZE(c->sector_size)) {
|
||||
#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
|
||||
if (jffs2_cleanmarker_oob(c)) {
|
||||
/* scan oob, take care of cleanmarker */
|
||||
int ret = jffs2_check_oob_empty(c, jeb, cleanmarkerfound);
|
||||
|
|
@ -343,7 +351,10 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
|
|||
}
|
||||
#endif
|
||||
D1(printk(KERN_DEBUG "Block at 0x%08x is empty (erased)\n", jeb->offset));
|
||||
return BLK_STATE_ALLFF; /* OK to erase if all blocks are like this */
|
||||
if (c->cleanmarker_size == 0)
|
||||
return BLK_STATE_CLEANMARKER; /* don't bother with re-erase */
|
||||
else
|
||||
return BLK_STATE_ALLFF; /* OK to erase if all blocks are like this */
|
||||
}
|
||||
if (ofs) {
|
||||
D1(printk(KERN_DEBUG "Free space at %08x ends at %08x\n", jeb->offset,
|
||||
|
|
@ -422,8 +433,8 @@ scan_more:
|
|||
/* If we're only checking the beginning of a block with a cleanmarker,
|
||||
bail now */
|
||||
if (buf_ofs == jeb->offset && jeb->used_size == PAD(c->cleanmarker_size) &&
|
||||
c->cleanmarker_size && !jeb->dirty_size && !jeb->first_node->next_in_ino) {
|
||||
D1(printk(KERN_DEBUG "%d bytes at start of block seems clean... assuming all clean\n", EMPTY_SCAN_SIZE));
|
||||
c->cleanmarker_size && !jeb->dirty_size && !jeb->first_node->next_phys) {
|
||||
D1(printk(KERN_DEBUG "%d bytes at start of block seems clean... assuming all clean\n", EMPTY_SCAN_SIZE(c->sector_size)));
|
||||
return BLK_STATE_CLEANMARKER;
|
||||
}
|
||||
|
||||
|
|
@ -618,7 +629,7 @@ scan_more:
|
|||
}
|
||||
|
||||
if ((jeb->used_size + jeb->unchecked_size) == PAD(c->cleanmarker_size) && !jeb->dirty_size
|
||||
&& (!jeb->first_node || !jeb->first_node->next_in_ino) )
|
||||
&& (!jeb->first_node || !jeb->first_node->next_phys) )
|
||||
return BLK_STATE_CLEANMARKER;
|
||||
|
||||
/* move blocks with max 4 byte dirty space to cleanlist */
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* $Id: super.c,v 1.104 2004/11/23 15:37:31 gleixner Exp $
|
||||
* $Id: super.c,v 1.107 2005/07/12 16:37:08 dedekind Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -140,6 +140,15 @@ static struct super_block *jffs2_get_sb_mtd(struct file_system_type *fs_type,
|
|||
D1(printk(KERN_DEBUG "jffs2_get_sb_mtd(): New superblock for device %d (\"%s\")\n",
|
||||
mtd->index, mtd->name));
|
||||
|
||||
/* Initialize JFFS2 superblock locks, the further initialization will be
|
||||
* done later */
|
||||
init_MUTEX(&c->alloc_sem);
|
||||
init_MUTEX(&c->erase_free_sem);
|
||||
init_waitqueue_head(&c->erase_wait);
|
||||
init_waitqueue_head(&c->inocache_wq);
|
||||
spin_lock_init(&c->erase_completion_lock);
|
||||
spin_lock_init(&c->inocache_lock);
|
||||
|
||||
sb->s_op = &jffs2_super_operations;
|
||||
sb->s_flags = flags | MS_NOATIME;
|
||||
|
||||
|
|
@ -270,8 +279,6 @@ static void jffs2_put_super (struct super_block *sb)
|
|||
|
||||
D2(printk(KERN_DEBUG "jffs2: jffs2_put_super()\n"));
|
||||
|
||||
if (!(sb->s_flags & MS_RDONLY))
|
||||
jffs2_stop_garbage_collect_thread(c);
|
||||
down(&c->alloc_sem);
|
||||
jffs2_flush_wbuf_pad(c);
|
||||
up(&c->alloc_sem);
|
||||
|
|
@ -292,6 +299,8 @@ static void jffs2_put_super (struct super_block *sb)
|
|||
static void jffs2_kill_sb(struct super_block *sb)
|
||||
{
|
||||
struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
|
||||
if (!(sb->s_flags & MS_RDONLY))
|
||||
jffs2_stop_garbage_collect_thread(c);
|
||||
generic_shutdown_super(sb);
|
||||
put_mtd_device(c->mtd);
|
||||
kfree(c);
|
||||
|
|
@ -309,7 +318,7 @@ static int __init init_jffs2_fs(void)
|
|||
int ret;
|
||||
|
||||
printk(KERN_INFO "JFFS2 version 2.2."
|
||||
#ifdef CONFIG_JFFS2_FS_NAND
|
||||
#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
|
||||
" (NAND)"
|
||||
#endif
|
||||
" (C) 2001-2003 Red Hat, Inc.\n");
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* $Id: symlink.c,v 1.14 2004/11/16 20:36:12 dwmw2 Exp $
|
||||
* $Id: symlink.c,v 1.16 2005/03/01 10:50:48 dedekind Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -19,27 +19,45 @@
|
|||
#include "nodelist.h"
|
||||
|
||||
static int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd);
|
||||
static void jffs2_put_link(struct dentry *dentry, struct nameidata *nd);
|
||||
|
||||
struct inode_operations jffs2_symlink_inode_operations =
|
||||
{
|
||||
.readlink = generic_readlink,
|
||||
.follow_link = jffs2_follow_link,
|
||||
.put_link = jffs2_put_link,
|
||||
.setattr = jffs2_setattr
|
||||
};
|
||||
|
||||
static int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
{
|
||||
unsigned char *buf;
|
||||
buf = jffs2_getlink(JFFS2_SB_INFO(dentry->d_inode->i_sb), JFFS2_INODE_INFO(dentry->d_inode));
|
||||
nd_set_link(nd, buf);
|
||||
struct jffs2_inode_info *f = JFFS2_INODE_INFO(dentry->d_inode);
|
||||
|
||||
/*
|
||||
* We don't acquire the f->sem mutex here since the only data we
|
||||
* use is f->dents which in case of the symlink inode points to the
|
||||
* symlink's target path.
|
||||
*
|
||||
* 1. If we are here the inode has already built and f->dents has
|
||||
* to point to the target path.
|
||||
* 2. Nobody uses f->dents (if the inode is symlink's inode). The
|
||||
* exception is inode freeing function which frees f->dents. But
|
||||
* it can't be called while we are here and before VFS has
|
||||
* stopped using our f->dents string which we provide by means of
|
||||
* nd_set_link() call.
|
||||
*/
|
||||
|
||||
if (!f->dents) {
|
||||
printk(KERN_ERR "jffs2_follow_link(): can't find symlink taerget\n");
|
||||
return -EIO;
|
||||
}
|
||||
D1(printk(KERN_DEBUG "jffs2_follow_link(): target path is '%s'\n", (char *) f->dents));
|
||||
|
||||
nd_set_link(nd, (char *)f->dents);
|
||||
|
||||
/*
|
||||
* We unlock the f->sem mutex but VFS will use the f->dents string. This is safe
|
||||
* since the only way that may cause f->dents to be changed is iput() operation.
|
||||
* But VFS will not use f->dents after iput() has been called.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void jffs2_put_link(struct dentry *dentry, struct nameidata *nd)
|
||||
{
|
||||
char *s = nd_get_link(nd);
|
||||
if (!IS_ERR(s))
|
||||
kfree(s);
|
||||
}
|
||||
|
|
|
|||
164
fs/jffs2/wbuf.c
164
fs/jffs2/wbuf.c
|
|
@ -9,7 +9,7 @@
|
|||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* $Id: wbuf.c,v 1.82 2004/11/20 22:08:31 dwmw2 Exp $
|
||||
* $Id: wbuf.c,v 1.92 2005/04/05 12:51:54 dedekind Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -83,7 +83,7 @@ static void jffs2_wbuf_dirties_inode(struct jffs2_sb_info *c, uint32_t ino)
|
|||
struct jffs2_inodirty *new;
|
||||
|
||||
/* Mark the superblock dirty so that kupdated will flush... */
|
||||
OFNI_BS_2SFFJ(c)->s_dirt = 1;
|
||||
jffs2_erase_pending_trigger(c);
|
||||
|
||||
if (jffs2_wbuf_pending_for_ino(c, ino))
|
||||
return;
|
||||
|
|
@ -130,7 +130,10 @@ static inline void jffs2_refile_wbuf_blocks(struct jffs2_sb_info *c)
|
|||
}
|
||||
}
|
||||
|
||||
static void jffs2_block_refile(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
|
||||
#define REFILE_NOTEMPTY 0
|
||||
#define REFILE_ANYWAY 1
|
||||
|
||||
static void jffs2_block_refile(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, int allow_empty)
|
||||
{
|
||||
D1(printk("About to refile bad block at %08x\n", jeb->offset));
|
||||
|
||||
|
|
@ -144,7 +147,7 @@ static void jffs2_block_refile(struct jffs2_sb_info *c, struct jffs2_eraseblock
|
|||
D1(printk("Refiling block at %08x to bad_used_list\n", jeb->offset));
|
||||
list_add(&jeb->list, &c->bad_used_list);
|
||||
} else {
|
||||
BUG();
|
||||
BUG_ON(allow_empty == REFILE_NOTEMPTY);
|
||||
/* It has to have had some nodes or we couldn't be here */
|
||||
D1(printk("Refiling block at %08x to erase_pending_list\n", jeb->offset));
|
||||
list_add(&jeb->list, &c->erase_pending_list);
|
||||
|
|
@ -179,7 +182,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
|
|||
|
||||
jeb = &c->blocks[c->wbuf_ofs / c->sector_size];
|
||||
|
||||
jffs2_block_refile(c, jeb);
|
||||
jffs2_block_refile(c, jeb, REFILE_NOTEMPTY);
|
||||
|
||||
/* Find the first node to be recovered, by skipping over every
|
||||
node which ends before the wbuf starts, or which is obsolete. */
|
||||
|
|
@ -264,17 +267,16 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
|
|||
ret = jffs2_reserve_space_gc(c, end-start, &ofs, &len);
|
||||
if (ret) {
|
||||
printk(KERN_WARNING "Failed to allocate space for wbuf recovery. Data loss ensues.\n");
|
||||
if (buf)
|
||||
kfree(buf);
|
||||
kfree(buf);
|
||||
return;
|
||||
}
|
||||
if (end-start >= c->wbuf_pagesize) {
|
||||
/* Need to do another write immediately. This, btw,
|
||||
means that we'll be writing from 'buf' and not from
|
||||
the wbuf. Since if we're writing from the wbuf there
|
||||
won't be more than a wbuf full of data, now will
|
||||
there? :) */
|
||||
|
||||
/* Need to do another write immediately, but it's possible
|
||||
that this is just because the wbuf itself is completely
|
||||
full, and there's nothing earlier read back from the
|
||||
flash. Hence 'buf' isn't necessarily what we're writing
|
||||
from. */
|
||||
unsigned char *rewrite_buf = buf?:c->wbuf;
|
||||
uint32_t towrite = (end-start) - ((end-start)%c->wbuf_pagesize);
|
||||
|
||||
D1(printk(KERN_DEBUG "Write 0x%x bytes at 0x%08x in wbuf recover\n",
|
||||
|
|
@ -292,9 +294,9 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
|
|||
#endif
|
||||
if (jffs2_cleanmarker_oob(c))
|
||||
ret = c->mtd->write_ecc(c->mtd, ofs, towrite, &retlen,
|
||||
buf, NULL, c->oobinfo);
|
||||
rewrite_buf, NULL, c->oobinfo);
|
||||
else
|
||||
ret = c->mtd->write(c->mtd, ofs, towrite, &retlen, buf);
|
||||
ret = c->mtd->write(c->mtd, ofs, towrite, &retlen, rewrite_buf);
|
||||
|
||||
if (ret || retlen != towrite) {
|
||||
/* Argh. We tried. Really we did. */
|
||||
|
|
@ -321,10 +323,10 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
|
|||
|
||||
c->wbuf_len = (end - start) - towrite;
|
||||
c->wbuf_ofs = ofs + towrite;
|
||||
memcpy(c->wbuf, buf + towrite, c->wbuf_len);
|
||||
memmove(c->wbuf, rewrite_buf + towrite, c->wbuf_len);
|
||||
/* Don't muck about with c->wbuf_inodes. False positives are harmless. */
|
||||
|
||||
kfree(buf);
|
||||
if (buf)
|
||||
kfree(buf);
|
||||
} else {
|
||||
/* OK, now we're left with the dregs in whichever buffer we're using */
|
||||
if (buf) {
|
||||
|
|
@ -413,9 +415,9 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
|
|||
int ret;
|
||||
size_t retlen;
|
||||
|
||||
/* Nothing to do if not NAND flash. In particular, we shouldn't
|
||||
/* Nothing to do if not write-buffering the flash. In particular, we shouldn't
|
||||
del_timer() the timer we never initialised. */
|
||||
if (jffs2_can_mark_obsolete(c))
|
||||
if (!jffs2_is_writebuffered(c))
|
||||
return 0;
|
||||
|
||||
if (!down_trylock(&c->alloc_sem)) {
|
||||
|
|
@ -424,7 +426,7 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
|
|||
BUG();
|
||||
}
|
||||
|
||||
if(!c->wbuf || !c->wbuf_len)
|
||||
if (!c->wbuf_len) /* already checked c->wbuf above */
|
||||
return 0;
|
||||
|
||||
/* claim remaining space on the page
|
||||
|
|
@ -433,7 +435,7 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
|
|||
if we have a switch to next page, we will not have
|
||||
enough remaining space for this.
|
||||
*/
|
||||
if (pad) {
|
||||
if (pad && !jffs2_dataflash(c)) {
|
||||
c->wbuf_len = PAD(c->wbuf_len);
|
||||
|
||||
/* Pad with JFFS2_DIRTY_BITMASK initially. this helps out ECC'd NOR
|
||||
|
|
@ -484,7 +486,7 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
|
|||
spin_lock(&c->erase_completion_lock);
|
||||
|
||||
/* Adjust free size of the block if we padded. */
|
||||
if (pad) {
|
||||
if (pad && !jffs2_dataflash(c)) {
|
||||
struct jffs2_eraseblock *jeb;
|
||||
|
||||
jeb = &c->blocks[c->wbuf_ofs / c->sector_size];
|
||||
|
|
@ -532,6 +534,9 @@ int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino)
|
|||
|
||||
D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() called for ino #%u...\n", ino));
|
||||
|
||||
if (!c->wbuf)
|
||||
return 0;
|
||||
|
||||
down(&c->alloc_sem);
|
||||
if (!jffs2_wbuf_pending_for_ino(c, ino)) {
|
||||
D1(printk(KERN_DEBUG "Ino #%d not pending in wbuf. Returning\n", ino));
|
||||
|
|
@ -547,6 +552,10 @@ int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino)
|
|||
D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() padding. Not finished checking\n"));
|
||||
down_write(&c->wbuf_sem);
|
||||
ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING);
|
||||
/* retry flushing wbuf in case jffs2_wbuf_recover
|
||||
left some data in the wbuf */
|
||||
if (ret)
|
||||
ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING);
|
||||
up_write(&c->wbuf_sem);
|
||||
} else while (old_wbuf_len &&
|
||||
old_wbuf_ofs == c->wbuf_ofs) {
|
||||
|
|
@ -561,6 +570,10 @@ int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino)
|
|||
down(&c->alloc_sem);
|
||||
down_write(&c->wbuf_sem);
|
||||
ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING);
|
||||
/* retry flushing wbuf in case jffs2_wbuf_recover
|
||||
left some data in the wbuf */
|
||||
if (ret)
|
||||
ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING);
|
||||
up_write(&c->wbuf_sem);
|
||||
break;
|
||||
}
|
||||
|
|
@ -578,15 +591,27 @@ int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c)
|
|||
{
|
||||
int ret;
|
||||
|
||||
if (!c->wbuf)
|
||||
return 0;
|
||||
|
||||
down_write(&c->wbuf_sem);
|
||||
ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT);
|
||||
/* retry - maybe wbuf recover left some data in wbuf. */
|
||||
if (ret)
|
||||
ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT);
|
||||
up_write(&c->wbuf_sem);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
|
||||
#define PAGE_DIV(x) ( ((unsigned long)(x) / (unsigned long)(c->wbuf_pagesize)) * (unsigned long)(c->wbuf_pagesize) )
|
||||
#define PAGE_MOD(x) ( (unsigned long)(x) % (unsigned long)(c->wbuf_pagesize) )
|
||||
#else
|
||||
#define PAGE_DIV(x) ( (x) & (~(c->wbuf_pagesize - 1)) )
|
||||
#define PAGE_MOD(x) ( (x) & (c->wbuf_pagesize - 1) )
|
||||
#endif
|
||||
|
||||
int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsigned long count, loff_t to, size_t *retlen, uint32_t ino)
|
||||
{
|
||||
struct kvec outvecs[3];
|
||||
|
|
@ -601,7 +626,7 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig
|
|||
uint32_t outvec_to = to;
|
||||
|
||||
/* If not NAND flash, don't bother */
|
||||
if (!c->wbuf)
|
||||
if (!jffs2_is_writebuffered(c))
|
||||
return jffs2_flash_direct_writev(c, invecs, count, to, retlen);
|
||||
|
||||
down_write(&c->wbuf_sem);
|
||||
|
|
@ -630,7 +655,7 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig
|
|||
erase block. Anything else, and you die.
|
||||
New block starts at xxx000c (0-b = block header)
|
||||
*/
|
||||
if ( (to & ~(c->sector_size-1)) != (c->wbuf_ofs & ~(c->sector_size-1)) ) {
|
||||
if (SECTOR_ADDR(to) != SECTOR_ADDR(c->wbuf_ofs)) {
|
||||
/* It's a write to a new block */
|
||||
if (c->wbuf_len) {
|
||||
D1(printk(KERN_DEBUG "jffs2_flash_writev() to 0x%lx causes flush of wbuf at 0x%08x\n", (unsigned long)to, c->wbuf_ofs));
|
||||
|
|
@ -762,9 +787,18 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig
|
|||
|
||||
if (ret < 0 || wbuf_retlen != PAGE_DIV(totlen)) {
|
||||
/* At this point we have no problem,
|
||||
c->wbuf is empty.
|
||||
c->wbuf is empty. However refile nextblock to avoid
|
||||
writing again to same address.
|
||||
*/
|
||||
*retlen = donelen;
|
||||
struct jffs2_eraseblock *jeb;
|
||||
|
||||
spin_lock(&c->erase_completion_lock);
|
||||
|
||||
jeb = &c->blocks[outvec_to / c->sector_size];
|
||||
jffs2_block_refile(c, jeb, REFILE_ANYWAY);
|
||||
|
||||
*retlen = 0;
|
||||
spin_unlock(&c->erase_completion_lock);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
|
|
@ -819,7 +853,7 @@ int jffs2_flash_write(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *r
|
|||
{
|
||||
struct kvec vecs[1];
|
||||
|
||||
if (jffs2_can_mark_obsolete(c))
|
||||
if (!jffs2_is_writebuffered(c))
|
||||
return c->mtd->write(c->mtd, ofs, len, retlen, buf);
|
||||
|
||||
vecs[0].iov_base = (unsigned char *) buf;
|
||||
|
|
@ -835,39 +869,38 @@ int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *re
|
|||
loff_t orbf = 0, owbf = 0, lwbf = 0;
|
||||
int ret;
|
||||
|
||||
/* Read flash */
|
||||
if (!jffs2_can_mark_obsolete(c)) {
|
||||
down_read(&c->wbuf_sem);
|
||||
|
||||
if (jffs2_cleanmarker_oob(c))
|
||||
ret = c->mtd->read_ecc(c->mtd, ofs, len, retlen, buf, NULL, c->oobinfo);
|
||||
else
|
||||
ret = c->mtd->read(c->mtd, ofs, len, retlen, buf);
|
||||
|
||||
if ( (ret == -EBADMSG) && (*retlen == len) ) {
|
||||
printk(KERN_WARNING "mtd->read(0x%zx bytes from 0x%llx) returned ECC error\n",
|
||||
len, ofs);
|
||||
/*
|
||||
* We have the raw data without ECC correction in the buffer, maybe
|
||||
* we are lucky and all data or parts are correct. We check the node.
|
||||
* If data are corrupted node check will sort it out.
|
||||
* We keep this block, it will fail on write or erase and the we
|
||||
* mark it bad. Or should we do that now? But we should give him a chance.
|
||||
* Maybe we had a system crash or power loss before the ecc write or
|
||||
* a erase was completed.
|
||||
* So we return success. :)
|
||||
*/
|
||||
ret = 0;
|
||||
}
|
||||
} else
|
||||
if (!jffs2_is_writebuffered(c))
|
||||
return c->mtd->read(c->mtd, ofs, len, retlen, buf);
|
||||
|
||||
/* Read flash */
|
||||
down_read(&c->wbuf_sem);
|
||||
if (jffs2_cleanmarker_oob(c))
|
||||
ret = c->mtd->read_ecc(c->mtd, ofs, len, retlen, buf, NULL, c->oobinfo);
|
||||
else
|
||||
ret = c->mtd->read(c->mtd, ofs, len, retlen, buf);
|
||||
|
||||
if ( (ret == -EBADMSG) && (*retlen == len) ) {
|
||||
printk(KERN_WARNING "mtd->read(0x%zx bytes from 0x%llx) returned ECC error\n",
|
||||
len, ofs);
|
||||
/*
|
||||
* We have the raw data without ECC correction in the buffer, maybe
|
||||
* we are lucky and all data or parts are correct. We check the node.
|
||||
* If data are corrupted node check will sort it out.
|
||||
* We keep this block, it will fail on write or erase and the we
|
||||
* mark it bad. Or should we do that now? But we should give him a chance.
|
||||
* Maybe we had a system crash or power loss before the ecc write or
|
||||
* a erase was completed.
|
||||
* So we return success. :)
|
||||
*/
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
/* if no writebuffer available or write buffer empty, return */
|
||||
if (!c->wbuf_pagesize || !c->wbuf_len)
|
||||
goto exit;
|
||||
|
||||
/* if we read in a different block, return */
|
||||
if ( (ofs & ~(c->sector_size-1)) != (c->wbuf_ofs & ~(c->sector_size-1)) )
|
||||
if (SECTOR_ADDR(ofs) != SECTOR_ADDR(c->wbuf_ofs))
|
||||
goto exit;
|
||||
|
||||
if (ofs >= c->wbuf_ofs) {
|
||||
|
|
@ -1161,7 +1194,27 @@ void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c)
|
|||
kfree(c->wbuf);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_JFFS2_FS_NOR_ECC
|
||||
int jffs2_dataflash_setup(struct jffs2_sb_info *c) {
|
||||
c->cleanmarker_size = 0; /* No cleanmarkers needed */
|
||||
|
||||
/* Initialize write buffer */
|
||||
init_rwsem(&c->wbuf_sem);
|
||||
c->wbuf_pagesize = c->sector_size;
|
||||
c->wbuf_ofs = 0xFFFFFFFF;
|
||||
|
||||
c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
|
||||
if (!c->wbuf)
|
||||
return -ENOMEM;
|
||||
|
||||
printk(KERN_INFO "JFFS2 write-buffering enabled (%i)\n", c->wbuf_pagesize);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void jffs2_dataflash_cleanup(struct jffs2_sb_info *c) {
|
||||
kfree(c->wbuf);
|
||||
}
|
||||
|
||||
int jffs2_nor_ecc_flash_setup(struct jffs2_sb_info *c) {
|
||||
/* Cleanmarker is actually larger on the flashes */
|
||||
c->cleanmarker_size = 16;
|
||||
|
|
@ -1181,4 +1234,3 @@ int jffs2_nor_ecc_flash_setup(struct jffs2_sb_info *c) {
|
|||
void jffs2_nor_ecc_flash_cleanup(struct jffs2_sb_info *c) {
|
||||
kfree(c->wbuf);
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* $Id: write.c,v 1.87 2004/11/16 20:36:12 dwmw2 Exp $
|
||||
* $Id: write.c,v 1.92 2005/04/13 13:22:35 dwmw2 Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -35,13 +35,12 @@ int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint
|
|||
f->inocache = ic;
|
||||
f->inocache->nlink = 1;
|
||||
f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache;
|
||||
f->inocache->ino = ++c->highest_ino;
|
||||
f->inocache->state = INO_STATE_PRESENT;
|
||||
|
||||
ri->ino = cpu_to_je32(f->inocache->ino);
|
||||
|
||||
D1(printk(KERN_DEBUG "jffs2_do_new_inode(): Assigned ino# %d\n", f->inocache->ino));
|
||||
jffs2_add_ino_cache(c, f->inocache);
|
||||
D1(printk(KERN_DEBUG "jffs2_do_new_inode(): Assigned ino# %d\n", f->inocache->ino));
|
||||
ri->ino = cpu_to_je32(f->inocache->ino);
|
||||
|
||||
ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
|
||||
ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
|
||||
|
|
@ -136,6 +135,15 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2
|
|||
raw->__totlen = PAD(sizeof(*ri)+datalen);
|
||||
raw->next_phys = NULL;
|
||||
|
||||
if ((alloc_mode!=ALLOC_GC) && (je32_to_cpu(ri->version) < f->highest_version)) {
|
||||
BUG_ON(!retried);
|
||||
D1(printk(KERN_DEBUG "jffs2_write_dnode : dnode_version %d, "
|
||||
"highest version %d -> updating dnode\n",
|
||||
je32_to_cpu(ri->version), f->highest_version));
|
||||
ri->version = cpu_to_je32(++f->highest_version);
|
||||
ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
|
||||
}
|
||||
|
||||
ret = jffs2_flash_writev(c, vecs, cnt, flash_ofs, &retlen,
|
||||
(alloc_mode==ALLOC_GC)?0:f->inocache->ino);
|
||||
|
||||
|
|
@ -280,6 +288,16 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff
|
|||
raw->__totlen = PAD(sizeof(*rd)+namelen);
|
||||
raw->next_phys = NULL;
|
||||
|
||||
if ((alloc_mode!=ALLOC_GC) && (je32_to_cpu(rd->version) < f->highest_version)) {
|
||||
BUG_ON(!retried);
|
||||
D1(printk(KERN_DEBUG "jffs2_write_dirent : dirent_version %d, "
|
||||
"highest version %d -> updating dirent\n",
|
||||
je32_to_cpu(rd->version), f->highest_version));
|
||||
rd->version = cpu_to_je32(++f->highest_version);
|
||||
fd->version = je32_to_cpu(rd->version);
|
||||
rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
|
||||
}
|
||||
|
||||
ret = jffs2_flash_writev(c, vecs, 2, flash_ofs, &retlen,
|
||||
(alloc_mode==ALLOC_GC)?0:je32_to_cpu(rd->pino));
|
||||
if (ret || (retlen != sizeof(*rd) + namelen)) {
|
||||
|
|
@ -625,20 +643,23 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
|
|||
|
||||
down(&dead_f->sem);
|
||||
|
||||
while (dead_f->dents) {
|
||||
/* There can be only deleted ones */
|
||||
fd = dead_f->dents;
|
||||
|
||||
dead_f->dents = fd->next;
|
||||
|
||||
if (fd->ino) {
|
||||
printk(KERN_WARNING "Deleting inode #%u with active dentry \"%s\"->ino #%u\n",
|
||||
dead_f->inocache->ino, fd->name, fd->ino);
|
||||
} else {
|
||||
D1(printk(KERN_DEBUG "Removing deletion dirent for \"%s\" from dir ino #%u\n", fd->name, dead_f->inocache->ino));
|
||||
if (S_ISDIR(OFNI_EDONI_2SFFJ(dead_f)->i_mode)) {
|
||||
while (dead_f->dents) {
|
||||
/* There can be only deleted ones */
|
||||
fd = dead_f->dents;
|
||||
|
||||
dead_f->dents = fd->next;
|
||||
|
||||
if (fd->ino) {
|
||||
printk(KERN_WARNING "Deleting inode #%u with active dentry \"%s\"->ino #%u\n",
|
||||
dead_f->inocache->ino, fd->name, fd->ino);
|
||||
} else {
|
||||
D1(printk(KERN_DEBUG "Removing deletion dirent for \"%s\" from dir ino #%u\n",
|
||||
fd->name, dead_f->inocache->ino));
|
||||
}
|
||||
jffs2_mark_node_obsolete(c, fd->raw);
|
||||
jffs2_free_full_dirent(fd);
|
||||
}
|
||||
jffs2_mark_node_obsolete(c, fd->raw);
|
||||
jffs2_free_full_dirent(fd);
|
||||
}
|
||||
|
||||
dead_f->inocache->nlink--;
|
||||
|
|
|
|||
|
|
@ -25,36 +25,6 @@
|
|||
#include "jfs_metapage.h"
|
||||
#include "jfs_debug.h"
|
||||
|
||||
/*
|
||||
* Debug code for double-checking block map
|
||||
*/
|
||||
/* #define _JFS_DEBUG_DMAP 1 */
|
||||
|
||||
#ifdef _JFS_DEBUG_DMAP
|
||||
#define DBINITMAP(size,ipbmap,results) \
|
||||
DBinitmap(size,ipbmap,results)
|
||||
#define DBALLOC(dbmap,mapsize,blkno,nblocks) \
|
||||
DBAlloc(dbmap,mapsize,blkno,nblocks)
|
||||
#define DBFREE(dbmap,mapsize,blkno,nblocks) \
|
||||
DBFree(dbmap,mapsize,blkno,nblocks)
|
||||
#define DBALLOCCK(dbmap,mapsize,blkno,nblocks) \
|
||||
DBAllocCK(dbmap,mapsize,blkno,nblocks)
|
||||
#define DBFREECK(dbmap,mapsize,blkno,nblocks) \
|
||||
DBFreeCK(dbmap,mapsize,blkno,nblocks)
|
||||
|
||||
static void DBinitmap(s64, struct inode *, u32 **);
|
||||
static void DBAlloc(uint *, s64, s64, s64);
|
||||
static void DBFree(uint *, s64, s64, s64);
|
||||
static void DBAllocCK(uint *, s64, s64, s64);
|
||||
static void DBFreeCK(uint *, s64, s64, s64);
|
||||
#else
|
||||
#define DBINITMAP(size,ipbmap,results)
|
||||
#define DBALLOC(dbmap, mapsize, blkno, nblocks)
|
||||
#define DBFREE(dbmap, mapsize, blkno, nblocks)
|
||||
#define DBALLOCCK(dbmap, mapsize, blkno, nblocks)
|
||||
#define DBFREECK(dbmap, mapsize, blkno, nblocks)
|
||||
#endif /* _JFS_DEBUG_DMAP */
|
||||
|
||||
/*
|
||||
* SERIALIZATION of the Block Allocation Map.
|
||||
*
|
||||
|
|
@ -242,7 +212,6 @@ int dbMount(struct inode *ipbmap)
|
|||
JFS_SBI(ipbmap->i_sb)->bmap = bmp;
|
||||
|
||||
memset(bmp->db_active, 0, sizeof(bmp->db_active));
|
||||
DBINITMAP(bmp->db_mapsize, ipbmap, &bmp->db_DBmap);
|
||||
|
||||
/*
|
||||
* allocate/initialize the bmap lock
|
||||
|
|
@ -407,16 +376,12 @@ int dbFree(struct inode *ip, s64 blkno, s64 nblocks)
|
|||
*/
|
||||
nb = min(rem, BPERDMAP - (blkno & (BPERDMAP - 1)));
|
||||
|
||||
DBALLOCCK(bmp->db_DBmap, bmp->db_mapsize, blkno, nb);
|
||||
|
||||
/* free the blocks. */
|
||||
if ((rc = dbFreeDmap(bmp, dp, blkno, nb))) {
|
||||
release_metapage(mp);
|
||||
IREAD_UNLOCK(ipbmap);
|
||||
return (rc);
|
||||
}
|
||||
|
||||
DBFREE(bmp->db_DBmap, bmp->db_mapsize, blkno, nb);
|
||||
}
|
||||
|
||||
/* write the last buffer. */
|
||||
|
|
@ -775,10 +740,6 @@ int dbAlloc(struct inode *ip, s64 hint, s64 nblocks, s64 * results)
|
|||
IWRITE_LOCK(ipbmap);
|
||||
|
||||
rc = dbAllocAny(bmp, nblocks, l2nb, results);
|
||||
if (rc == 0) {
|
||||
DBALLOC(bmp->db_DBmap, bmp->db_mapsize, *results,
|
||||
nblocks);
|
||||
}
|
||||
|
||||
goto write_unlock;
|
||||
}
|
||||
|
|
@ -836,8 +797,6 @@ int dbAlloc(struct inode *ip, s64 hint, s64 nblocks, s64 * results)
|
|||
!= -ENOSPC) {
|
||||
if (rc == 0) {
|
||||
*results = blkno;
|
||||
DBALLOC(bmp->db_DBmap, bmp->db_mapsize,
|
||||
*results, nblocks);
|
||||
mark_metapage_dirty(mp);
|
||||
}
|
||||
|
||||
|
|
@ -863,11 +822,8 @@ int dbAlloc(struct inode *ip, s64 hint, s64 nblocks, s64 * results)
|
|||
if ((rc =
|
||||
dbAllocNear(bmp, dp, blkno, (int) nblocks, l2nb, results))
|
||||
!= -ENOSPC) {
|
||||
if (rc == 0) {
|
||||
DBALLOC(bmp->db_DBmap, bmp->db_mapsize,
|
||||
*results, nblocks);
|
||||
if (rc == 0)
|
||||
mark_metapage_dirty(mp);
|
||||
}
|
||||
|
||||
release_metapage(mp);
|
||||
goto read_unlock;
|
||||
|
|
@ -878,11 +834,8 @@ int dbAlloc(struct inode *ip, s64 hint, s64 nblocks, s64 * results)
|
|||
*/
|
||||
if ((rc = dbAllocDmapLev(bmp, dp, (int) nblocks, l2nb, results))
|
||||
!= -ENOSPC) {
|
||||
if (rc == 0) {
|
||||
DBALLOC(bmp->db_DBmap, bmp->db_mapsize,
|
||||
*results, nblocks);
|
||||
if (rc == 0)
|
||||
mark_metapage_dirty(mp);
|
||||
}
|
||||
|
||||
release_metapage(mp);
|
||||
goto read_unlock;
|
||||
|
|
@ -896,13 +849,9 @@ int dbAlloc(struct inode *ip, s64 hint, s64 nblocks, s64 * results)
|
|||
* the same allocation group as the hint.
|
||||
*/
|
||||
IWRITE_LOCK(ipbmap);
|
||||
if ((rc = dbAllocAG(bmp, agno, nblocks, l2nb, results))
|
||||
!= -ENOSPC) {
|
||||
if (rc == 0)
|
||||
DBALLOC(bmp->db_DBmap, bmp->db_mapsize,
|
||||
*results, nblocks);
|
||||
if ((rc = dbAllocAG(bmp, agno, nblocks, l2nb, results)) != -ENOSPC)
|
||||
goto write_unlock;
|
||||
}
|
||||
|
||||
IWRITE_UNLOCK(ipbmap);
|
||||
|
||||
|
||||
|
|
@ -918,9 +867,6 @@ int dbAlloc(struct inode *ip, s64 hint, s64 nblocks, s64 * results)
|
|||
*/
|
||||
if ((rc = dbAllocAG(bmp, agno, nblocks, l2nb, results)) == -ENOSPC)
|
||||
rc = dbAllocAny(bmp, nblocks, l2nb, results);
|
||||
if (rc == 0) {
|
||||
DBALLOC(bmp->db_DBmap, bmp->db_mapsize, *results, nblocks);
|
||||
}
|
||||
|
||||
write_unlock:
|
||||
IWRITE_UNLOCK(ipbmap);
|
||||
|
|
@ -992,10 +938,9 @@ int dbAllocExact(struct inode *ip, s64 blkno, int nblocks)
|
|||
|
||||
IREAD_UNLOCK(ipbmap);
|
||||
|
||||
if (rc == 0) {
|
||||
DBALLOC(bmp->db_DBmap, bmp->db_mapsize, blkno, nblocks);
|
||||
if (rc == 0)
|
||||
mark_metapage_dirty(mp);
|
||||
}
|
||||
|
||||
release_metapage(mp);
|
||||
|
||||
return (rc);
|
||||
|
|
@ -1144,7 +1089,6 @@ static int dbExtend(struct inode *ip, s64 blkno, s64 nblocks, s64 addnblocks)
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
DBALLOCCK(bmp->db_DBmap, bmp->db_mapsize, blkno, nblocks);
|
||||
dp = (struct dmap *) mp->data;
|
||||
|
||||
/* try to allocate the blocks immediately following the
|
||||
|
|
@ -1155,11 +1099,9 @@ static int dbExtend(struct inode *ip, s64 blkno, s64 nblocks, s64 addnblocks)
|
|||
IREAD_UNLOCK(ipbmap);
|
||||
|
||||
/* were we successful ? */
|
||||
if (rc == 0) {
|
||||
DBALLOC(bmp->db_DBmap, bmp->db_mapsize, extblkno,
|
||||
addnblocks);
|
||||
if (rc == 0)
|
||||
write_metapage(mp);
|
||||
} else
|
||||
else
|
||||
/* we were not successful */
|
||||
release_metapage(mp);
|
||||
|
||||
|
|
@ -3185,16 +3127,12 @@ int dbAllocBottomUp(struct inode *ip, s64 blkno, s64 nblocks)
|
|||
*/
|
||||
nb = min(rem, BPERDMAP - (blkno & (BPERDMAP - 1)));
|
||||
|
||||
DBFREECK(bmp->db_DBmap, bmp->db_mapsize, blkno, nb);
|
||||
|
||||
/* allocate the blocks. */
|
||||
if ((rc = dbAllocDmapBU(bmp, dp, blkno, nb))) {
|
||||
release_metapage(mp);
|
||||
IREAD_UNLOCK(ipbmap);
|
||||
return (rc);
|
||||
}
|
||||
|
||||
DBALLOC(bmp->db_DBmap, bmp->db_mapsize, blkno, nb);
|
||||
}
|
||||
|
||||
/* write the last buffer. */
|
||||
|
|
@ -4041,223 +3979,3 @@ s64 dbMapFileSizeToMapSize(struct inode * ipbmap)
|
|||
|
||||
return (nblocks);
|
||||
}
|
||||
|
||||
|
||||
#ifdef _JFS_DEBUG_DMAP
|
||||
/*
|
||||
* DBinitmap()
|
||||
*/
|
||||
static void DBinitmap(s64 size, struct inode *ipbmap, u32 ** results)
|
||||
{
|
||||
int npages;
|
||||
u32 *dbmap, *d;
|
||||
int n;
|
||||
s64 lblkno, cur_block;
|
||||
struct dmap *dp;
|
||||
struct metapage *mp;
|
||||
|
||||
npages = size / 32768;
|
||||
npages += (size % 32768) ? 1 : 0;
|
||||
|
||||
dbmap = (u32 *) xmalloc(npages * 4096, L2PSIZE, kernel_heap);
|
||||
if (dbmap == NULL)
|
||||
BUG(); /* Not robust since this is only unused debug code */
|
||||
|
||||
for (n = 0, d = dbmap; n < npages; n++, d += 1024)
|
||||
bzero(d, 4096);
|
||||
|
||||
/* Need to initialize from disk map pages
|
||||
*/
|
||||
for (d = dbmap, cur_block = 0; cur_block < size;
|
||||
cur_block += BPERDMAP, d += LPERDMAP) {
|
||||
lblkno = BLKTODMAP(cur_block,
|
||||
JFS_SBI(ipbmap->i_sb)->bmap->
|
||||
db_l2nbperpage);
|
||||
mp = read_metapage(ipbmap, lblkno, PSIZE, 0);
|
||||
if (mp == NULL) {
|
||||
jfs_error(ipbmap->i_sb,
|
||||
"DBinitmap: could not read disk map page");
|
||||
continue;
|
||||
}
|
||||
dp = (struct dmap *) mp->data;
|
||||
|
||||
for (n = 0; n < LPERDMAP; n++)
|
||||
d[n] = le32_to_cpu(dp->wmap[n]);
|
||||
|
||||
release_metapage(mp);
|
||||
}
|
||||
|
||||
*results = dbmap;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* DBAlloc()
|
||||
*/
|
||||
void DBAlloc(uint * dbmap, s64 mapsize, s64 blkno, s64 nblocks)
|
||||
{
|
||||
int word, nb, bitno;
|
||||
u32 mask;
|
||||
|
||||
assert(blkno > 0 && blkno < mapsize);
|
||||
assert(nblocks > 0 && nblocks <= mapsize);
|
||||
|
||||
assert(blkno + nblocks <= mapsize);
|
||||
|
||||
dbmap += (blkno / 32);
|
||||
while (nblocks > 0) {
|
||||
bitno = blkno & (32 - 1);
|
||||
nb = min(nblocks, 32 - bitno);
|
||||
|
||||
mask = (0xffffffff << (32 - nb) >> bitno);
|
||||
assert((mask & *dbmap) == 0);
|
||||
*dbmap |= mask;
|
||||
|
||||
dbmap++;
|
||||
blkno += nb;
|
||||
nblocks -= nb;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* DBFree()
|
||||
*/
|
||||
static void DBFree(uint * dbmap, s64 mapsize, s64 blkno, s64 nblocks)
|
||||
{
|
||||
int word, nb, bitno;
|
||||
u32 mask;
|
||||
|
||||
assert(blkno > 0 && blkno < mapsize);
|
||||
assert(nblocks > 0 && nblocks <= mapsize);
|
||||
|
||||
assert(blkno + nblocks <= mapsize);
|
||||
|
||||
dbmap += (blkno / 32);
|
||||
while (nblocks > 0) {
|
||||
bitno = blkno & (32 - 1);
|
||||
nb = min(nblocks, 32 - bitno);
|
||||
|
||||
mask = (0xffffffff << (32 - nb) >> bitno);
|
||||
assert((mask & *dbmap) == mask);
|
||||
*dbmap &= ~mask;
|
||||
|
||||
dbmap++;
|
||||
blkno += nb;
|
||||
nblocks -= nb;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* DBAllocCK()
|
||||
*/
|
||||
static void DBAllocCK(uint * dbmap, s64 mapsize, s64 blkno, s64 nblocks)
|
||||
{
|
||||
int word, nb, bitno;
|
||||
u32 mask;
|
||||
|
||||
assert(blkno > 0 && blkno < mapsize);
|
||||
assert(nblocks > 0 && nblocks <= mapsize);
|
||||
|
||||
assert(blkno + nblocks <= mapsize);
|
||||
|
||||
dbmap += (blkno / 32);
|
||||
while (nblocks > 0) {
|
||||
bitno = blkno & (32 - 1);
|
||||
nb = min(nblocks, 32 - bitno);
|
||||
|
||||
mask = (0xffffffff << (32 - nb) >> bitno);
|
||||
assert((mask & *dbmap) == mask);
|
||||
|
||||
dbmap++;
|
||||
blkno += nb;
|
||||
nblocks -= nb;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* DBFreeCK()
|
||||
*/
|
||||
static void DBFreeCK(uint * dbmap, s64 mapsize, s64 blkno, s64 nblocks)
|
||||
{
|
||||
int word, nb, bitno;
|
||||
u32 mask;
|
||||
|
||||
assert(blkno > 0 && blkno < mapsize);
|
||||
assert(nblocks > 0 && nblocks <= mapsize);
|
||||
|
||||
assert(blkno + nblocks <= mapsize);
|
||||
|
||||
dbmap += (blkno / 32);
|
||||
while (nblocks > 0) {
|
||||
bitno = blkno & (32 - 1);
|
||||
nb = min(nblocks, 32 - bitno);
|
||||
|
||||
mask = (0xffffffff << (32 - nb) >> bitno);
|
||||
assert((mask & *dbmap) == 0);
|
||||
|
||||
dbmap++;
|
||||
blkno += nb;
|
||||
nblocks -= nb;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* dbPrtMap()
|
||||
*/
|
||||
static void dbPrtMap(struct bmap * bmp)
|
||||
{
|
||||
printk(" mapsize: %d%d\n", bmp->db_mapsize);
|
||||
printk(" nfree: %d%d\n", bmp->db_nfree);
|
||||
printk(" numag: %d\n", bmp->db_numag);
|
||||
printk(" agsize: %d%d\n", bmp->db_agsize);
|
||||
printk(" agl2size: %d\n", bmp->db_agl2size);
|
||||
printk(" agwidth: %d\n", bmp->db_agwidth);
|
||||
printk(" agstart: %d\n", bmp->db_agstart);
|
||||
printk(" agheigth: %d\n", bmp->db_agheigth);
|
||||
printk(" aglevel: %d\n", bmp->db_aglevel);
|
||||
printk(" maxlevel: %d\n", bmp->db_maxlevel);
|
||||
printk(" maxag: %d\n", bmp->db_maxag);
|
||||
printk(" agpref: %d\n", bmp->db_agpref);
|
||||
printk(" l2nbppg: %d\n", bmp->db_l2nbperpage);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* dbPrtCtl()
|
||||
*/
|
||||
static void dbPrtCtl(struct dmapctl * dcp)
|
||||
{
|
||||
int i, j, n;
|
||||
|
||||
printk(" height: %08x\n", le32_to_cpu(dcp->height));
|
||||
printk(" leafidx: %08x\n", le32_to_cpu(dcp->leafidx));
|
||||
printk(" budmin: %08x\n", dcp->budmin);
|
||||
printk(" nleafs: %08x\n", le32_to_cpu(dcp->nleafs));
|
||||
printk(" l2nleafs: %08x\n", le32_to_cpu(dcp->l2nleafs));
|
||||
|
||||
printk("\n Tree:\n");
|
||||
for (i = 0; i < CTLLEAFIND; i += 8) {
|
||||
n = min(8, CTLLEAFIND - i);
|
||||
|
||||
for (j = 0; j < n; j++)
|
||||
printf(" [%03x]: %02x", i + j,
|
||||
(char) dcp->stree[i + j]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
printk("\n Tree Leaves:\n");
|
||||
for (i = 0; i < LPERCTL; i += 8) {
|
||||
n = min(8, LPERCTL - i);
|
||||
|
||||
for (j = 0; j < n; j++)
|
||||
printf(" [%03x]: %02x",
|
||||
i + j,
|
||||
(char) dcp->stree[i + j + CTLLEAFIND]);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
#endif /* _JFS_DEBUG_DMAP */
|
||||
|
|
|
|||
|
|
@ -4554,202 +4554,3 @@ int dtModify(tid_t tid, struct inode *ip,
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef _JFS_DEBUG_DTREE
|
||||
/*
|
||||
* dtDisplayTree()
|
||||
*
|
||||
* function: traverse forward
|
||||
*/
|
||||
int dtDisplayTree(struct inode *ip)
|
||||
{
|
||||
int rc;
|
||||
struct metapage *mp;
|
||||
dtpage_t *p;
|
||||
s64 bn, pbn;
|
||||
int index, lastindex, v, h;
|
||||
pxd_t *xd;
|
||||
struct btstack btstack;
|
||||
struct btframe *btsp;
|
||||
struct btframe *parent;
|
||||
u8 *stbl;
|
||||
int psize = 256;
|
||||
|
||||
printk("display B+-tree.\n");
|
||||
|
||||
/* clear stack */
|
||||
btsp = btstack.stack;
|
||||
|
||||
/*
|
||||
* start with root
|
||||
*
|
||||
* root resides in the inode
|
||||
*/
|
||||
bn = 0;
|
||||
v = h = 0;
|
||||
|
||||
/*
|
||||
* first access of each page:
|
||||
*/
|
||||
newPage:
|
||||
DT_GETPAGE(ip, bn, mp, psize, p, rc);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* process entries forward from first index */
|
||||
index = 0;
|
||||
lastindex = p->header.nextindex - 1;
|
||||
|
||||
if (p->header.flag & BT_INTERNAL) {
|
||||
/*
|
||||
* first access of each internal page
|
||||
*/
|
||||
printf("internal page ");
|
||||
dtDisplayPage(ip, bn, p);
|
||||
|
||||
goto getChild;
|
||||
} else { /* (p->header.flag & BT_LEAF) */
|
||||
|
||||
/*
|
||||
* first access of each leaf page
|
||||
*/
|
||||
printf("leaf page ");
|
||||
dtDisplayPage(ip, bn, p);
|
||||
|
||||
/*
|
||||
* process leaf page entries
|
||||
*
|
||||
for ( ; index <= lastindex; index++)
|
||||
{
|
||||
}
|
||||
*/
|
||||
|
||||
/* unpin the leaf page */
|
||||
DT_PUTPAGE(mp);
|
||||
}
|
||||
|
||||
/*
|
||||
* go back up to the parent page
|
||||
*/
|
||||
getParent:
|
||||
/* pop/restore parent entry for the current child page */
|
||||
if ((parent = (btsp == btstack.stack ? NULL : --btsp)) == NULL)
|
||||
/* current page must have been root */
|
||||
return;
|
||||
|
||||
/*
|
||||
* parent page scan completed
|
||||
*/
|
||||
if ((index = parent->index) == (lastindex = parent->lastindex)) {
|
||||
/* go back up to the parent page */
|
||||
goto getParent;
|
||||
}
|
||||
|
||||
/*
|
||||
* parent page has entries remaining
|
||||
*/
|
||||
/* get back the parent page */
|
||||
bn = parent->bn;
|
||||
/* v = parent->level; */
|
||||
DT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* get next parent entry */
|
||||
index++;
|
||||
|
||||
/*
|
||||
* internal page: go down to child page of current entry
|
||||
*/
|
||||
getChild:
|
||||
/* push/save current parent entry for the child page */
|
||||
btsp->bn = pbn = bn;
|
||||
btsp->index = index;
|
||||
btsp->lastindex = lastindex;
|
||||
/* btsp->level = v; */
|
||||
/* btsp->node = h; */
|
||||
++btsp;
|
||||
|
||||
/* get current entry for the child page */
|
||||
stbl = DT_GETSTBL(p);
|
||||
xd = (pxd_t *) & p->slot[stbl[index]];
|
||||
|
||||
/*
|
||||
* first access of each internal entry:
|
||||
*/
|
||||
|
||||
/* get child page */
|
||||
bn = addressPXD(xd);
|
||||
psize = lengthPXD(xd) << ip->i_ipmnt->i_l2bsize;
|
||||
|
||||
printk("traverse down 0x%Lx[%d]->0x%Lx\n", pbn, index, bn);
|
||||
v++;
|
||||
h = index;
|
||||
|
||||
/* release parent page */
|
||||
DT_PUTPAGE(mp);
|
||||
|
||||
/* process the child page */
|
||||
goto newPage;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* dtDisplayPage()
|
||||
*
|
||||
* function: display page
|
||||
*/
|
||||
int dtDisplayPage(struct inode *ip, s64 bn, dtpage_t * p)
|
||||
{
|
||||
int rc;
|
||||
struct metapage *mp;
|
||||
struct ldtentry *lh;
|
||||
struct idtentry *ih;
|
||||
pxd_t *xd;
|
||||
int i, j;
|
||||
u8 *stbl;
|
||||
wchar_t name[JFS_NAME_MAX + 1];
|
||||
struct component_name key = { 0, name };
|
||||
int freepage = 0;
|
||||
|
||||
if (p == NULL) {
|
||||
freepage = 1;
|
||||
DT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* display page control */
|
||||
printk("bn:0x%Lx flag:0x%08x nextindex:%d\n",
|
||||
bn, p->header.flag, p->header.nextindex);
|
||||
|
||||
/* display entries */
|
||||
stbl = DT_GETSTBL(p);
|
||||
for (i = 0, j = 1; i < p->header.nextindex; i++, j++) {
|
||||
dtGetKey(p, i, &key, JFS_SBI(ip->i_sb)->mntflag);
|
||||
key.name[key.namlen] = '\0';
|
||||
if (p->header.flag & BT_LEAF) {
|
||||
lh = (struct ldtentry *) & p->slot[stbl[i]];
|
||||
printf("\t[%d] %s:%d", i, key.name,
|
||||
le32_to_cpu(lh->inumber));
|
||||
} else {
|
||||
ih = (struct idtentry *) & p->slot[stbl[i]];
|
||||
xd = (pxd_t *) ih;
|
||||
bn = addressPXD(xd);
|
||||
printf("\t[%d] %s:0x%Lx", i, key.name, bn);
|
||||
}
|
||||
|
||||
if (j == 4) {
|
||||
printf("\n");
|
||||
j = 0;
|
||||
}
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
if (freepage)
|
||||
DT_PUTPAGE(mp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* _JFS_DEBUG_DTREE */
|
||||
|
|
|
|||
|
|
@ -269,11 +269,4 @@ extern int dtModify(tid_t tid, struct inode *ip, struct component_name * key,
|
|||
ino_t * orig_ino, ino_t new_ino, int flag);
|
||||
|
||||
extern int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir);
|
||||
|
||||
#ifdef _JFS_DEBUG_DTREE
|
||||
extern int dtDisplayTree(struct inode *ip);
|
||||
|
||||
extern int dtDisplayPage(struct inode *ip, s64 bn, dtpage_t * p);
|
||||
#endif /* _JFS_DEBUG_DTREE */
|
||||
|
||||
#endif /* !_H_JFS_DTREE */
|
||||
|
|
|
|||
|
|
@ -86,25 +86,6 @@ static int diIAGRead(struct inomap * imap, int, struct metapage **);
|
|||
static int copy_from_dinode(struct dinode *, struct inode *);
|
||||
static void copy_to_dinode(struct dinode *, struct inode *);
|
||||
|
||||
/*
|
||||
* debug code for double-checking inode map
|
||||
*/
|
||||
/* #define _JFS_DEBUG_IMAP 1 */
|
||||
|
||||
#ifdef _JFS_DEBUG_IMAP
|
||||
#define DBG_DIINIT(imap) DBGdiInit(imap)
|
||||
#define DBG_DIALLOC(imap, ino) DBGdiAlloc(imap, ino)
|
||||
#define DBG_DIFREE(imap, ino) DBGdiFree(imap, ino)
|
||||
|
||||
static void *DBGdiInit(struct inomap * imap);
|
||||
static void DBGdiAlloc(struct inomap * imap, ino_t ino);
|
||||
static void DBGdiFree(struct inomap * imap, ino_t ino);
|
||||
#else
|
||||
#define DBG_DIINIT(imap)
|
||||
#define DBG_DIALLOC(imap, ino)
|
||||
#define DBG_DIFREE(imap, ino)
|
||||
#endif /* _JFS_DEBUG_IMAP */
|
||||
|
||||
/*
|
||||
* NAME: diMount()
|
||||
*
|
||||
|
|
@ -188,8 +169,6 @@ int diMount(struct inode *ipimap)
|
|||
imap->im_ipimap = ipimap;
|
||||
JFS_IP(ipimap)->i_imap = imap;
|
||||
|
||||
// DBG_DIINIT(imap);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
|
@ -1043,7 +1022,6 @@ int diFree(struct inode *ip)
|
|||
/* update the bitmap.
|
||||
*/
|
||||
iagp->wmap[extno] = cpu_to_le32(bitmap);
|
||||
DBG_DIFREE(imap, inum);
|
||||
|
||||
/* update the free inode counts at the iag, ag and
|
||||
* map level.
|
||||
|
|
@ -1231,7 +1209,6 @@ int diFree(struct inode *ip)
|
|||
jfs_error(ip->i_sb, "diFree: the pmap does not show inode free");
|
||||
}
|
||||
iagp->wmap[extno] = 0;
|
||||
DBG_DIFREE(imap, inum);
|
||||
PXDlength(&iagp->inoext[extno], 0);
|
||||
PXDaddress(&iagp->inoext[extno], 0);
|
||||
|
||||
|
|
@ -1350,7 +1327,6 @@ diInitInode(struct inode *ip, int iagno, int ino, int extno, struct iag * iagp)
|
|||
struct jfs_inode_info *jfs_ip = JFS_IP(ip);
|
||||
|
||||
ip->i_ino = (iagno << L2INOSPERIAG) + ino;
|
||||
DBG_DIALLOC(JFS_IP(ipimap)->i_imap, ip->i_ino);
|
||||
jfs_ip->ixpxd = iagp->inoext[extno];
|
||||
jfs_ip->agno = BLKTOAG(le64_to_cpu(iagp->agstart), sbi);
|
||||
jfs_ip->active_ag = -1;
|
||||
|
|
@ -3185,84 +3161,3 @@ static void copy_to_dinode(struct dinode * dip, struct inode *ip)
|
|||
if (S_ISCHR(ip->i_mode) || S_ISBLK(ip->i_mode))
|
||||
dip->di_rdev = cpu_to_le32(jfs_ip->dev);
|
||||
}
|
||||
|
||||
#ifdef _JFS_DEBUG_IMAP
|
||||
/*
|
||||
* DBGdiInit()
|
||||
*/
|
||||
static void *DBGdiInit(struct inomap * imap)
|
||||
{
|
||||
u32 *dimap;
|
||||
int size;
|
||||
size = 64 * 1024;
|
||||
if ((dimap = (u32 *) xmalloc(size, L2PSIZE, kernel_heap)) == NULL)
|
||||
assert(0);
|
||||
bzero((void *) dimap, size);
|
||||
imap->im_DBGdimap = dimap;
|
||||
}
|
||||
|
||||
/*
|
||||
* DBGdiAlloc()
|
||||
*/
|
||||
static void DBGdiAlloc(struct inomap * imap, ino_t ino)
|
||||
{
|
||||
u32 *dimap = imap->im_DBGdimap;
|
||||
int w, b;
|
||||
u32 m;
|
||||
w = ino >> 5;
|
||||
b = ino & 31;
|
||||
m = 0x80000000 >> b;
|
||||
assert(w < 64 * 256);
|
||||
if (dimap[w] & m) {
|
||||
printk("DEBUG diAlloc: duplicate alloc ino:0x%x\n", ino);
|
||||
}
|
||||
dimap[w] |= m;
|
||||
}
|
||||
|
||||
/*
|
||||
* DBGdiFree()
|
||||
*/
|
||||
static void DBGdiFree(struct inomap * imap, ino_t ino)
|
||||
{
|
||||
u32 *dimap = imap->im_DBGdimap;
|
||||
int w, b;
|
||||
u32 m;
|
||||
w = ino >> 5;
|
||||
b = ino & 31;
|
||||
m = 0x80000000 >> b;
|
||||
assert(w < 64 * 256);
|
||||
if ((dimap[w] & m) == 0) {
|
||||
printk("DEBUG diFree: duplicate free ino:0x%x\n", ino);
|
||||
}
|
||||
dimap[w] &= ~m;
|
||||
}
|
||||
|
||||
static void dump_cp(struct inomap * ipimap, char *function, int line)
|
||||
{
|
||||
printk("\n* ********* *\nControl Page %s %d\n", function, line);
|
||||
printk("FreeIAG %d\tNextIAG %d\n", ipimap->im_freeiag,
|
||||
ipimap->im_nextiag);
|
||||
printk("NumInos %d\tNumFree %d\n",
|
||||
atomic_read(&ipimap->im_numinos),
|
||||
atomic_read(&ipimap->im_numfree));
|
||||
printk("AG InoFree %d\tAG ExtFree %d\n",
|
||||
ipimap->im_agctl[0].inofree, ipimap->im_agctl[0].extfree);
|
||||
printk("AG NumInos %d\tAG NumFree %d\n",
|
||||
ipimap->im_agctl[0].numinos, ipimap->im_agctl[0].numfree);
|
||||
}
|
||||
|
||||
static void dump_iag(struct iag * iag, char *function, int line)
|
||||
{
|
||||
printk("\n* ********* *\nIAG %s %d\n", function, line);
|
||||
printk("IagNum %d\tIAG Free %d\n", le32_to_cpu(iag->iagnum),
|
||||
le32_to_cpu(iag->iagfree));
|
||||
printk("InoFreeFwd %d\tInoFreeBack %d\n",
|
||||
le32_to_cpu(iag->inofreefwd),
|
||||
le32_to_cpu(iag->inofreeback));
|
||||
printk("ExtFreeFwd %d\tExtFreeBack %d\n",
|
||||
le32_to_cpu(iag->extfreefwd),
|
||||
le32_to_cpu(iag->extfreeback));
|
||||
printk("NFreeInos %d\tNFreeExts %d\n", le32_to_cpu(iag->nfreeinos),
|
||||
le32_to_cpu(iag->nfreeexts));
|
||||
}
|
||||
#endif /* _JFS_DEBUG_IMAP */
|
||||
|
|
|
|||
|
|
@ -51,8 +51,9 @@ int jfs_strfromUCS_le(char *to, const __le16 * from,
|
|||
}
|
||||
} else {
|
||||
for (i = 0; (i < len) && from[i]; i++) {
|
||||
if (le16_to_cpu(from[i]) & 0xff00) {
|
||||
if (warn) {
|
||||
if (unlikely(le16_to_cpu(from[i]) & 0xff00)) {
|
||||
to[i] = '?';
|
||||
if (unlikely(warn)) {
|
||||
warn--;
|
||||
warn_again--;
|
||||
printk(KERN_ERR
|
||||
|
|
@ -61,7 +62,7 @@ int jfs_strfromUCS_le(char *to, const __le16 * from,
|
|||
printk(KERN_ERR
|
||||
"mount with iocharset=utf8 to access\n");
|
||||
}
|
||||
to[i] = '?';
|
||||
|
||||
}
|
||||
else
|
||||
to[i] = (char) (le16_to_cpu(from[i]));
|
||||
|
|
|
|||
|
|
@ -135,14 +135,6 @@ static int xtSearchNode(struct inode *ip,
|
|||
static int xtRelink(tid_t tid, struct inode *ip, xtpage_t * fp);
|
||||
#endif /* _STILL_TO_PORT */
|
||||
|
||||
/* External references */
|
||||
|
||||
/*
|
||||
* debug control
|
||||
*/
|
||||
/* #define _JFS_DEBUG_XTREE 1 */
|
||||
|
||||
|
||||
/*
|
||||
* xtLookup()
|
||||
*
|
||||
|
|
@ -4140,338 +4132,6 @@ s64 xtTruncate_pmap(tid_t tid, struct inode *ip, s64 committed_size)
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef _JFS_DEBUG_XTREE
|
||||
/*
|
||||
* xtDisplayTree()
|
||||
*
|
||||
* function: traverse forward
|
||||
*/
|
||||
int xtDisplayTree(struct inode *ip)
|
||||
{
|
||||
int rc = 0;
|
||||
struct metapage *mp;
|
||||
xtpage_t *p;
|
||||
s64 bn, pbn;
|
||||
int index, lastindex, v, h;
|
||||
xad_t *xad;
|
||||
struct btstack btstack;
|
||||
struct btframe *btsp;
|
||||
struct btframe *parent;
|
||||
|
||||
printk("display B+-tree.\n");
|
||||
|
||||
/* clear stack */
|
||||
btsp = btstack.stack;
|
||||
|
||||
/*
|
||||
* start with root
|
||||
*
|
||||
* root resides in the inode
|
||||
*/
|
||||
bn = 0;
|
||||
v = h = 0;
|
||||
|
||||
/*
|
||||
* first access of each page:
|
||||
*/
|
||||
getPage:
|
||||
XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* process entries forward from first index */
|
||||
index = XTENTRYSTART;
|
||||
lastindex = le16_to_cpu(p->header.nextindex) - 1;
|
||||
|
||||
if (p->header.flag & BT_INTERNAL) {
|
||||
/*
|
||||
* first access of each internal page
|
||||
*/
|
||||
goto getChild;
|
||||
} else { /* (p->header.flag & BT_LEAF) */
|
||||
|
||||
/*
|
||||
* first access of each leaf page
|
||||
*/
|
||||
printf("leaf page ");
|
||||
xtDisplayPage(ip, bn, p);
|
||||
|
||||
/* unpin the leaf page */
|
||||
XT_PUTPAGE(mp);
|
||||
}
|
||||
|
||||
/*
|
||||
* go back up to the parent page
|
||||
*/
|
||||
getParent:
|
||||
/* pop/restore parent entry for the current child page */
|
||||
if ((parent = (btsp == btstack.stack ? NULL : --btsp)) == NULL)
|
||||
/* current page must have been root */
|
||||
return;
|
||||
|
||||
/*
|
||||
* parent page scan completed
|
||||
*/
|
||||
if ((index = parent->index) == (lastindex = parent->lastindex)) {
|
||||
/* go back up to the parent page */
|
||||
goto getParent;
|
||||
}
|
||||
|
||||
/*
|
||||
* parent page has entries remaining
|
||||
*/
|
||||
/* get back the parent page */
|
||||
bn = parent->bn;
|
||||
/* v = parent->level; */
|
||||
XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* get next parent entry */
|
||||
index++;
|
||||
|
||||
/*
|
||||
* internal page: go down to child page of current entry
|
||||
*/
|
||||
getChild:
|
||||
/* push/save current parent entry for the child page */
|
||||
btsp->bn = pbn = bn;
|
||||
btsp->index = index;
|
||||
btsp->lastindex = lastindex;
|
||||
/* btsp->level = v; */
|
||||
/* btsp->node = h; */
|
||||
++btsp;
|
||||
|
||||
/* get child page */
|
||||
xad = &p->xad[index];
|
||||
bn = addressXAD(xad);
|
||||
|
||||
/*
|
||||
* first access of each internal entry:
|
||||
*/
|
||||
/* release parent page */
|
||||
XT_PUTPAGE(mp);
|
||||
|
||||
printk("traverse down 0x%lx[%d]->0x%lx\n", (ulong) pbn, index,
|
||||
(ulong) bn);
|
||||
v++;
|
||||
h = index;
|
||||
|
||||
/* process the child page */
|
||||
goto getPage;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* xtDisplayPage()
|
||||
*
|
||||
* function: display page
|
||||
*/
|
||||
int xtDisplayPage(struct inode *ip, s64 bn, xtpage_t * p)
|
||||
{
|
||||
int rc = 0;
|
||||
xad_t *xad;
|
||||
s64 xaddr, xoff;
|
||||
int xlen, i, j;
|
||||
|
||||
/* display page control */
|
||||
printf("bn:0x%lx flag:0x%x nextindex:%d\n",
|
||||
(ulong) bn, p->header.flag,
|
||||
le16_to_cpu(p->header.nextindex));
|
||||
|
||||
/* display entries */
|
||||
xad = &p->xad[XTENTRYSTART];
|
||||
for (i = XTENTRYSTART, j = 1; i < le16_to_cpu(p->header.nextindex);
|
||||
i++, xad++, j++) {
|
||||
xoff = offsetXAD(xad);
|
||||
xaddr = addressXAD(xad);
|
||||
xlen = lengthXAD(xad);
|
||||
printf("\t[%d] 0x%lx:0x%lx(0x%x)", i, (ulong) xoff,
|
||||
(ulong) xaddr, xlen);
|
||||
|
||||
if (j == 4) {
|
||||
printf("\n");
|
||||
j = 0;
|
||||
}
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
#endif /* _JFS_DEBUG_XTREE */
|
||||
|
||||
|
||||
#ifdef _JFS_WIP
|
||||
/*
|
||||
* xtGather()
|
||||
*
|
||||
* function:
|
||||
* traverse for allocation acquiring tlock at commit time
|
||||
* (vs at the time of update) logging backward top down
|
||||
*
|
||||
* note:
|
||||
* problem - establishing that all new allocation have been
|
||||
* processed both for append and random write in sparse file
|
||||
* at the current entry at the current subtree root page
|
||||
*
|
||||
*/
|
||||
int xtGather(btree_t *t)
|
||||
{
|
||||
int rc = 0;
|
||||
xtpage_t *p;
|
||||
u64 bn;
|
||||
int index;
|
||||
btentry_t *e;
|
||||
struct btstack btstack;
|
||||
struct btsf *parent;
|
||||
|
||||
/* clear stack */
|
||||
BT_CLR(&btstack);
|
||||
|
||||
/*
|
||||
* start with root
|
||||
*
|
||||
* root resides in the inode
|
||||
*/
|
||||
bn = 0;
|
||||
XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* new root is NOT pointed by a new entry
|
||||
if (p->header.flag & NEW)
|
||||
allocate new page lock;
|
||||
write a NEWPAGE log;
|
||||
*/
|
||||
|
||||
dopage:
|
||||
/*
|
||||
* first access of each page:
|
||||
*/
|
||||
/* process entries backward from last index */
|
||||
index = le16_to_cpu(p->header.nextindex) - 1;
|
||||
|
||||
if (p->header.flag & BT_LEAF) {
|
||||
/*
|
||||
* first access of each leaf page
|
||||
*/
|
||||
/* process leaf page entries backward */
|
||||
for (; index >= XTENTRYSTART; index--) {
|
||||
e = &p->xad[index];
|
||||
/*
|
||||
* if newpage, log NEWPAGE.
|
||||
*
|
||||
if (e->flag & XAD_NEW) {
|
||||
nfound =+ entry->length;
|
||||
update current page lock for the entry;
|
||||
newpage(entry);
|
||||
*
|
||||
* if moved, log move.
|
||||
*
|
||||
} else if (e->flag & XAD_MOVED) {
|
||||
reset flag;
|
||||
update current page lock for the entry;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/* unpin the leaf page */
|
||||
XT_PUTPAGE(mp);
|
||||
|
||||
/*
|
||||
* go back up to the parent page
|
||||
*/
|
||||
getParent:
|
||||
/* restore parent entry for the current child page */
|
||||
if ((parent = BT_POP(&btstack)) == NULL)
|
||||
/* current page must have been root */
|
||||
return 0;
|
||||
|
||||
if ((index = parent->index) == XTENTRYSTART) {
|
||||
/*
|
||||
* parent page scan completed
|
||||
*/
|
||||
/* go back up to the parent page */
|
||||
goto getParent;
|
||||
} else {
|
||||
/*
|
||||
* parent page has entries remaining
|
||||
*/
|
||||
/* get back the parent page */
|
||||
bn = parent->bn;
|
||||
XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
|
||||
if (rc)
|
||||
return -EIO;
|
||||
|
||||
/* first subroot page which
|
||||
* covers all new allocated blocks
|
||||
* itself not new/modified.
|
||||
* (if modified from split of descendent,
|
||||
* go down path of split page)
|
||||
|
||||
if (nfound == nnew &&
|
||||
!(p->header.flag & (NEW | MOD)))
|
||||
exit scan;
|
||||
*/
|
||||
|
||||
/* process parent page entries backward */
|
||||
index--;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* first access of each internal page
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
* internal page: go down to child page of current entry
|
||||
*/
|
||||
|
||||
/* save current parent entry for the child page */
|
||||
BT_PUSH(&btstack, bn, index);
|
||||
|
||||
/* get current entry for the child page */
|
||||
e = &p->xad[index];
|
||||
|
||||
/*
|
||||
* first access of each internal entry:
|
||||
*/
|
||||
/*
|
||||
* if new entry, log btree_tnewentry.
|
||||
*
|
||||
if (e->flag & XAD_NEW)
|
||||
update parent page lock for the entry;
|
||||
*/
|
||||
|
||||
/* release parent page */
|
||||
XT_PUTPAGE(mp);
|
||||
|
||||
/* get child page */
|
||||
bn = e->bn;
|
||||
XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/*
|
||||
* first access of each non-root page:
|
||||
*/
|
||||
/*
|
||||
* if new, log btree_newpage.
|
||||
*
|
||||
if (p->header.flag & NEW)
|
||||
allocate new page lock;
|
||||
write a NEWPAGE log (next, prev);
|
||||
*/
|
||||
|
||||
/* process the child page */
|
||||
goto dopage;
|
||||
|
||||
out:
|
||||
return 0;
|
||||
}
|
||||
#endif /* _JFS_WIP */
|
||||
|
||||
|
||||
#ifdef CONFIG_JFS_STATISTICS
|
||||
int jfs_xtstat_read(char *buffer, char **start, off_t offset, int length,
|
||||
int *eof, void *data)
|
||||
|
|
|
|||
|
|
@ -131,10 +131,4 @@ extern int xtRelocate(tid_t tid, struct inode *ip,
|
|||
extern int xtAppend(tid_t tid,
|
||||
struct inode *ip, int xflag, s64 xoff, int maxblocks,
|
||||
int *xlenp, s64 * xaddrp, int flag);
|
||||
|
||||
#ifdef _JFS_DEBUG_XTREE
|
||||
extern int xtDisplayTree(struct inode *ip);
|
||||
extern int xtDisplayPage(struct inode *ip, s64 bn, xtpage_t * p);
|
||||
#endif /* _JFS_DEBUG_XTREE */
|
||||
|
||||
#endif /* !_H_JFS_XTREE */
|
||||
|
|
|
|||
|
|
@ -781,7 +781,7 @@ static int can_set_xattr(struct inode *inode, const char *name,
|
|||
if (IS_RDONLY(inode))
|
||||
return -EROFS;
|
||||
|
||||
if (IS_IMMUTABLE(inode) || IS_APPEND(inode) || S_ISLNK(inode->i_mode))
|
||||
if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
|
||||
return -EPERM;
|
||||
|
||||
if(strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN) == 0)
|
||||
|
|
@ -790,12 +790,12 @@ static int can_set_xattr(struct inode *inode, const char *name,
|
|||
*/
|
||||
return can_set_system_xattr(inode, name, value, value_len);
|
||||
|
||||
if(strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) != 0)
|
||||
if(strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) == 0)
|
||||
return (capable(CAP_SYS_ADMIN) ? 0 : -EPERM);
|
||||
|
||||
#ifdef CONFIG_JFS_SECURITY
|
||||
if (strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN)
|
||||
!= 0)
|
||||
== 0)
|
||||
return 0; /* Leave it to the security module */
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -331,7 +331,7 @@ static ctl_table nlm_sysctls[] = {
|
|||
.ctl_name = CTL_UNNUMBERED,
|
||||
.procname = "nlm_grace_period",
|
||||
.data = &nlm_grace_period,
|
||||
.maxlen = sizeof(int),
|
||||
.maxlen = sizeof(unsigned long),
|
||||
.mode = 0644,
|
||||
.proc_handler = &proc_doulongvec_minmax,
|
||||
.extra1 = (unsigned long *) &nlm_grace_period_min,
|
||||
|
|
@ -341,7 +341,7 @@ static ctl_table nlm_sysctls[] = {
|
|||
.ctl_name = CTL_UNNUMBERED,
|
||||
.procname = "nlm_timeout",
|
||||
.data = &nlm_timeout,
|
||||
.maxlen = sizeof(int),
|
||||
.maxlen = sizeof(unsigned long),
|
||||
.mode = 0644,
|
||||
.proc_handler = &proc_doulongvec_minmax,
|
||||
.extra1 = (unsigned long *) &nlm_timeout_min,
|
||||
|
|
|
|||
|
|
@ -1276,7 +1276,7 @@ int fcntl_getlease(struct file *filp)
|
|||
*/
|
||||
static int __setlease(struct file *filp, long arg, struct file_lock **flp)
|
||||
{
|
||||
struct file_lock *fl, **before, **my_before = NULL, *lease = *flp;
|
||||
struct file_lock *fl, **before, **my_before = NULL, *lease;
|
||||
struct dentry *dentry = filp->f_dentry;
|
||||
struct inode *inode = dentry->d_inode;
|
||||
int error, rdlease_count = 0, wrlease_count = 0;
|
||||
|
|
@ -1287,6 +1287,8 @@ static int __setlease(struct file *filp, long arg, struct file_lock **flp)
|
|||
if (!flp || !(*flp) || !(*flp)->fl_lmops || !(*flp)->fl_lmops->fl_break)
|
||||
goto out;
|
||||
|
||||
lease = *flp;
|
||||
|
||||
error = -EAGAIN;
|
||||
if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0))
|
||||
goto out;
|
||||
|
|
|
|||
32
fs/namei.c
32
fs/namei.c
|
|
@ -21,7 +21,7 @@
|
|||
#include <linux/namei.h>
|
||||
#include <linux/quotaops.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/dnotify.h>
|
||||
#include <linux/fsnotify.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/personality.h>
|
||||
#include <linux/security.h>
|
||||
|
|
@ -314,7 +314,7 @@ void path_release(struct nameidata *nd)
|
|||
void path_release_on_umount(struct nameidata *nd)
|
||||
{
|
||||
dput(nd->dentry);
|
||||
_mntput(nd->mnt);
|
||||
mntput_no_expire(nd->mnt);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1312,7 +1312,7 @@ int vfs_create(struct inode *dir, struct dentry *dentry, int mode,
|
|||
DQUOT_INIT(dir);
|
||||
error = dir->i_op->create(dir, dentry, mode, nd);
|
||||
if (!error) {
|
||||
inode_dir_notify(dir, DN_CREATE);
|
||||
fsnotify_create(dir, dentry->d_name.name);
|
||||
security_inode_post_create(dir, dentry, mode);
|
||||
}
|
||||
return error;
|
||||
|
|
@ -1637,7 +1637,7 @@ int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
|
|||
DQUOT_INIT(dir);
|
||||
error = dir->i_op->mknod(dir, dentry, mode, dev);
|
||||
if (!error) {
|
||||
inode_dir_notify(dir, DN_CREATE);
|
||||
fsnotify_create(dir, dentry->d_name.name);
|
||||
security_inode_post_mknod(dir, dentry, mode, dev);
|
||||
}
|
||||
return error;
|
||||
|
|
@ -1710,7 +1710,7 @@ int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
|
|||
DQUOT_INIT(dir);
|
||||
error = dir->i_op->mkdir(dir, dentry, mode);
|
||||
if (!error) {
|
||||
inode_dir_notify(dir, DN_CREATE);
|
||||
fsnotify_mkdir(dir, dentry->d_name.name);
|
||||
security_inode_post_mkdir(dir,dentry, mode);
|
||||
}
|
||||
return error;
|
||||
|
|
@ -1801,7 +1801,7 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry)
|
|||
}
|
||||
up(&dentry->d_inode->i_sem);
|
||||
if (!error) {
|
||||
inode_dir_notify(dir, DN_DELETE);
|
||||
fsnotify_rmdir(dentry, dentry->d_inode, dir);
|
||||
d_delete(dentry);
|
||||
}
|
||||
dput(dentry);
|
||||
|
|
@ -1874,9 +1874,10 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry)
|
|||
|
||||
/* We don't d_delete() NFS sillyrenamed files--they still exist. */
|
||||
if (!error && !(dentry->d_flags & DCACHE_NFSFS_RENAMED)) {
|
||||
fsnotify_unlink(dentry, dir);
|
||||
d_delete(dentry);
|
||||
inode_dir_notify(dir, DN_DELETE);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
|
@ -1950,7 +1951,7 @@ int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname, i
|
|||
DQUOT_INIT(dir);
|
||||
error = dir->i_op->symlink(dir, dentry, oldname);
|
||||
if (!error) {
|
||||
inode_dir_notify(dir, DN_CREATE);
|
||||
fsnotify_create(dir, dentry->d_name.name);
|
||||
security_inode_post_symlink(dir, dentry, oldname);
|
||||
}
|
||||
return error;
|
||||
|
|
@ -2023,7 +2024,7 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de
|
|||
error = dir->i_op->link(old_dentry, dir, new_dentry);
|
||||
up(&old_dentry->d_inode->i_sem);
|
||||
if (!error) {
|
||||
inode_dir_notify(dir, DN_CREATE);
|
||||
fsnotify_create(dir, new_dentry->d_name.name);
|
||||
security_inode_post_link(old_dentry, dir, new_dentry);
|
||||
}
|
||||
return error;
|
||||
|
|
@ -2187,6 +2188,7 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|||
{
|
||||
int error;
|
||||
int is_dir = S_ISDIR(old_dentry->d_inode->i_mode);
|
||||
const char *old_name;
|
||||
|
||||
if (old_dentry->d_inode == new_dentry->d_inode)
|
||||
return 0;
|
||||
|
|
@ -2208,18 +2210,18 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|||
DQUOT_INIT(old_dir);
|
||||
DQUOT_INIT(new_dir);
|
||||
|
||||
old_name = fsnotify_oldname_init(old_dentry->d_name.name);
|
||||
|
||||
if (is_dir)
|
||||
error = vfs_rename_dir(old_dir,old_dentry,new_dir,new_dentry);
|
||||
else
|
||||
error = vfs_rename_other(old_dir,old_dentry,new_dir,new_dentry);
|
||||
if (!error) {
|
||||
if (old_dir == new_dir)
|
||||
inode_dir_notify(old_dir, DN_RENAME);
|
||||
else {
|
||||
inode_dir_notify(old_dir, DN_DELETE);
|
||||
inode_dir_notify(new_dir, DN_CREATE);
|
||||
}
|
||||
const char *new_name = old_dentry->d_name.name;
|
||||
fsnotify_move(old_dir, new_dir, old_name, new_name, is_dir);
|
||||
}
|
||||
fsnotify_oldname_free(old_name);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
|
|
|||
130
fs/namespace.c
130
fs/namespace.c
|
|
@ -61,7 +61,7 @@ struct vfsmount *alloc_vfsmnt(const char *name)
|
|||
INIT_LIST_HEAD(&mnt->mnt_child);
|
||||
INIT_LIST_HEAD(&mnt->mnt_mounts);
|
||||
INIT_LIST_HEAD(&mnt->mnt_list);
|
||||
INIT_LIST_HEAD(&mnt->mnt_fslink);
|
||||
INIT_LIST_HEAD(&mnt->mnt_expire);
|
||||
if (name) {
|
||||
int size = strlen(name)+1;
|
||||
char *newname = kmalloc(size, GFP_KERNEL);
|
||||
|
|
@ -165,8 +165,8 @@ clone_mnt(struct vfsmount *old, struct dentry *root)
|
|||
/* stick the duplicate mount on the same expiry list
|
||||
* as the original if that was on one */
|
||||
spin_lock(&vfsmount_lock);
|
||||
if (!list_empty(&old->mnt_fslink))
|
||||
list_add(&mnt->mnt_fslink, &old->mnt_fslink);
|
||||
if (!list_empty(&old->mnt_expire))
|
||||
list_add(&mnt->mnt_expire, &old->mnt_expire);
|
||||
spin_unlock(&vfsmount_lock);
|
||||
}
|
||||
return mnt;
|
||||
|
|
@ -345,12 +345,13 @@ static void umount_tree(struct vfsmount *mnt)
|
|||
for (p = mnt; p; p = next_mnt(p, mnt)) {
|
||||
list_del(&p->mnt_list);
|
||||
list_add(&p->mnt_list, &kill);
|
||||
p->mnt_namespace = NULL;
|
||||
}
|
||||
|
||||
while (!list_empty(&kill)) {
|
||||
mnt = list_entry(kill.next, struct vfsmount, mnt_list);
|
||||
list_del_init(&mnt->mnt_list);
|
||||
list_del_init(&mnt->mnt_fslink);
|
||||
list_del_init(&mnt->mnt_expire);
|
||||
if (mnt->mnt_parent == mnt) {
|
||||
spin_unlock(&vfsmount_lock);
|
||||
} else {
|
||||
|
|
@ -644,7 +645,7 @@ static int do_loopback(struct nameidata *nd, char *old_name, int recurse)
|
|||
if (mnt) {
|
||||
/* stop bind mounts from expiring */
|
||||
spin_lock(&vfsmount_lock);
|
||||
list_del_init(&mnt->mnt_fslink);
|
||||
list_del_init(&mnt->mnt_expire);
|
||||
spin_unlock(&vfsmount_lock);
|
||||
|
||||
err = graft_tree(mnt, nd);
|
||||
|
|
@ -743,7 +744,7 @@ static int do_move_mount(struct nameidata *nd, char *old_name)
|
|||
|
||||
/* if the mount is moved, it should no longer be expire
|
||||
* automatically */
|
||||
list_del_init(&old_nd.mnt->mnt_fslink);
|
||||
list_del_init(&old_nd.mnt->mnt_expire);
|
||||
out2:
|
||||
spin_unlock(&vfsmount_lock);
|
||||
out1:
|
||||
|
|
@ -807,12 +808,13 @@ int do_add_mount(struct vfsmount *newmnt, struct nameidata *nd,
|
|||
goto unlock;
|
||||
|
||||
newmnt->mnt_flags = mnt_flags;
|
||||
newmnt->mnt_namespace = current->namespace;
|
||||
err = graft_tree(newmnt, nd);
|
||||
|
||||
if (err == 0 && fslist) {
|
||||
/* add to the specified expiration list */
|
||||
spin_lock(&vfsmount_lock);
|
||||
list_add_tail(&newmnt->mnt_fslink, fslist);
|
||||
list_add_tail(&newmnt->mnt_expire, fslist);
|
||||
spin_unlock(&vfsmount_lock);
|
||||
}
|
||||
|
||||
|
|
@ -824,6 +826,54 @@ unlock:
|
|||
|
||||
EXPORT_SYMBOL_GPL(do_add_mount);
|
||||
|
||||
static void expire_mount(struct vfsmount *mnt, struct list_head *mounts)
|
||||
{
|
||||
spin_lock(&vfsmount_lock);
|
||||
|
||||
/*
|
||||
* Check if mount is still attached, if not, let whoever holds it deal
|
||||
* with the sucker
|
||||
*/
|
||||
if (mnt->mnt_parent == mnt) {
|
||||
spin_unlock(&vfsmount_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that it is still dead: the count should now be 2 - as
|
||||
* contributed by the vfsmount parent and the mntget above
|
||||
*/
|
||||
if (atomic_read(&mnt->mnt_count) == 2) {
|
||||
struct nameidata old_nd;
|
||||
|
||||
/* delete from the namespace */
|
||||
list_del_init(&mnt->mnt_list);
|
||||
mnt->mnt_namespace = NULL;
|
||||
detach_mnt(mnt, &old_nd);
|
||||
spin_unlock(&vfsmount_lock);
|
||||
path_release(&old_nd);
|
||||
|
||||
/*
|
||||
* Now lay it to rest if this was the last ref on the superblock
|
||||
*/
|
||||
if (atomic_read(&mnt->mnt_sb->s_active) == 1) {
|
||||
/* last instance - try to be smart */
|
||||
lock_kernel();
|
||||
DQUOT_OFF(mnt->mnt_sb);
|
||||
acct_auto_close(mnt->mnt_sb);
|
||||
unlock_kernel();
|
||||
}
|
||||
mntput(mnt);
|
||||
} else {
|
||||
/*
|
||||
* Someone brought it back to life whilst we didn't have any
|
||||
* locks held so return it to the expiration list
|
||||
*/
|
||||
list_add_tail(&mnt->mnt_expire, mounts);
|
||||
spin_unlock(&vfsmount_lock);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* process a list of expirable mountpoints with the intent of discarding any
|
||||
* mountpoints that aren't in use and haven't been touched since last we came
|
||||
|
|
@ -846,13 +896,13 @@ void mark_mounts_for_expiry(struct list_head *mounts)
|
|||
* - still marked for expiry (marked on the last call here; marks are
|
||||
* cleared by mntput())
|
||||
*/
|
||||
list_for_each_entry_safe(mnt, next, mounts, mnt_fslink) {
|
||||
list_for_each_entry_safe(mnt, next, mounts, mnt_expire) {
|
||||
if (!xchg(&mnt->mnt_expiry_mark, 1) ||
|
||||
atomic_read(&mnt->mnt_count) != 1)
|
||||
continue;
|
||||
|
||||
mntget(mnt);
|
||||
list_move(&mnt->mnt_fslink, &graveyard);
|
||||
list_move(&mnt->mnt_expire, &graveyard);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -862,61 +912,19 @@ void mark_mounts_for_expiry(struct list_head *mounts)
|
|||
* - dispose of the corpse
|
||||
*/
|
||||
while (!list_empty(&graveyard)) {
|
||||
mnt = list_entry(graveyard.next, struct vfsmount, mnt_fslink);
|
||||
list_del_init(&mnt->mnt_fslink);
|
||||
mnt = list_entry(graveyard.next, struct vfsmount, mnt_expire);
|
||||
list_del_init(&mnt->mnt_expire);
|
||||
|
||||
/* don't do anything if the namespace is dead - all the
|
||||
* vfsmounts from it are going away anyway */
|
||||
namespace = mnt->mnt_namespace;
|
||||
if (!namespace || atomic_read(&namespace->count) <= 0)
|
||||
if (!namespace || !namespace->root)
|
||||
continue;
|
||||
get_namespace(namespace);
|
||||
|
||||
spin_unlock(&vfsmount_lock);
|
||||
down_write(&namespace->sem);
|
||||
spin_lock(&vfsmount_lock);
|
||||
|
||||
/* check that it is still dead: the count should now be 2 - as
|
||||
* contributed by the vfsmount parent and the mntget above */
|
||||
if (atomic_read(&mnt->mnt_count) == 2) {
|
||||
struct vfsmount *xdmnt;
|
||||
struct dentry *xdentry;
|
||||
|
||||
/* delete from the namespace */
|
||||
list_del_init(&mnt->mnt_list);
|
||||
list_del_init(&mnt->mnt_child);
|
||||
list_del_init(&mnt->mnt_hash);
|
||||
mnt->mnt_mountpoint->d_mounted--;
|
||||
|
||||
xdentry = mnt->mnt_mountpoint;
|
||||
mnt->mnt_mountpoint = mnt->mnt_root;
|
||||
xdmnt = mnt->mnt_parent;
|
||||
mnt->mnt_parent = mnt;
|
||||
|
||||
spin_unlock(&vfsmount_lock);
|
||||
|
||||
mntput(xdmnt);
|
||||
dput(xdentry);
|
||||
|
||||
/* now lay it to rest if this was the last ref on the
|
||||
* superblock */
|
||||
if (atomic_read(&mnt->mnt_sb->s_active) == 1) {
|
||||
/* last instance - try to be smart */
|
||||
lock_kernel();
|
||||
DQUOT_OFF(mnt->mnt_sb);
|
||||
acct_auto_close(mnt->mnt_sb);
|
||||
unlock_kernel();
|
||||
}
|
||||
|
||||
mntput(mnt);
|
||||
} else {
|
||||
/* someone brought it back to life whilst we didn't
|
||||
* have any locks held so return it to the expiration
|
||||
* list */
|
||||
list_add_tail(&mnt->mnt_fslink, mounts);
|
||||
spin_unlock(&vfsmount_lock);
|
||||
}
|
||||
|
||||
expire_mount(mnt, mounts);
|
||||
up_write(&namespace->sem);
|
||||
|
||||
mntput(mnt);
|
||||
|
|
@ -1449,16 +1457,12 @@ void __init mnt_init(unsigned long mempages)
|
|||
|
||||
void __put_namespace(struct namespace *namespace)
|
||||
{
|
||||
struct vfsmount *mnt;
|
||||
|
||||
struct vfsmount *root = namespace->root;
|
||||
namespace->root = NULL;
|
||||
spin_unlock(&vfsmount_lock);
|
||||
down_write(&namespace->sem);
|
||||
spin_lock(&vfsmount_lock);
|
||||
|
||||
list_for_each_entry(mnt, &namespace->list, mnt_list) {
|
||||
mnt->mnt_namespace = NULL;
|
||||
}
|
||||
|
||||
umount_tree(namespace->root);
|
||||
umount_tree(root);
|
||||
spin_unlock(&vfsmount_lock);
|
||||
up_write(&namespace->sem);
|
||||
kfree(namespace);
|
||||
|
|
|
|||
|
|
@ -169,12 +169,6 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open
|
|||
(int)open->op_fname.len, open->op_fname.data,
|
||||
open->op_stateowner);
|
||||
|
||||
if (nfs4_in_grace() && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS)
|
||||
return nfserr_grace;
|
||||
|
||||
if (!nfs4_in_grace() && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
|
||||
return nfserr_no_grace;
|
||||
|
||||
/* This check required by spec. */
|
||||
if (open->op_create && open->op_claim_type != NFS4_OPEN_CLAIM_NULL)
|
||||
return nfserr_inval;
|
||||
|
|
|
|||
|
|
@ -119,25 +119,12 @@ out:
|
|||
return status;
|
||||
}
|
||||
|
||||
static int
|
||||
nfsd4_rec_fsync(struct dentry *dentry)
|
||||
static void
|
||||
nfsd4_sync_rec_dir(void)
|
||||
{
|
||||
struct file *filp;
|
||||
int status = nfs_ok;
|
||||
|
||||
dprintk("NFSD: nfs4_fsync_rec_dir\n");
|
||||
filp = dentry_open(dget(dentry), mntget(rec_dir.mnt), O_RDWR);
|
||||
if (IS_ERR(filp)) {
|
||||
status = PTR_ERR(filp);
|
||||
goto out;
|
||||
}
|
||||
if (filp->f_op && filp->f_op->fsync)
|
||||
status = filp->f_op->fsync(filp, filp->f_dentry, 0);
|
||||
fput(filp);
|
||||
out:
|
||||
if (status)
|
||||
printk("nfsd4: unable to sync recovery directory\n");
|
||||
return status;
|
||||
down(&rec_dir.dentry->d_inode->i_sem);
|
||||
nfsd_sync_dir(rec_dir.dentry);
|
||||
up(&rec_dir.dentry->d_inode->i_sem);
|
||||
}
|
||||
|
||||
int
|
||||
|
|
@ -176,7 +163,7 @@ out_unlock:
|
|||
up(&rec_dir.dentry->d_inode->i_sem);
|
||||
if (status == 0) {
|
||||
clp->cl_firststate = 1;
|
||||
status = nfsd4_rec_fsync(rec_dir.dentry);
|
||||
nfsd4_sync_rec_dir();
|
||||
}
|
||||
nfs4_reset_user(uid, gid);
|
||||
dprintk("NFSD: nfsd4_create_clid_dir returns %d\n", status);
|
||||
|
|
@ -302,7 +289,9 @@ nfsd4_unlink_clid_dir(char *name, int namlen)
|
|||
|
||||
dprintk("NFSD: nfsd4_unlink_clid_dir. name %.*s\n", namlen, name);
|
||||
|
||||
down(&rec_dir.dentry->d_inode->i_sem);
|
||||
dentry = lookup_one_len(name, rec_dir.dentry, namlen);
|
||||
up(&rec_dir.dentry->d_inode->i_sem);
|
||||
if (IS_ERR(dentry)) {
|
||||
status = PTR_ERR(dentry);
|
||||
return status;
|
||||
|
|
@ -327,11 +316,12 @@ nfsd4_remove_clid_dir(struct nfs4_client *clp)
|
|||
if (!rec_dir_init || !clp->cl_firststate)
|
||||
return;
|
||||
|
||||
clp->cl_firststate = 0;
|
||||
nfs4_save_user(&uid, &gid);
|
||||
status = nfsd4_unlink_clid_dir(clp->cl_recdir, HEXDIR_LEN-1);
|
||||
nfs4_reset_user(uid, gid);
|
||||
if (status == 0)
|
||||
status = nfsd4_rec_fsync(rec_dir.dentry);
|
||||
nfsd4_sync_rec_dir();
|
||||
if (status)
|
||||
printk("NFSD: Failed to remove expired client state directory"
|
||||
" %.*s\n", HEXDIR_LEN, clp->cl_recdir);
|
||||
|
|
@ -362,7 +352,7 @@ nfsd4_recdir_purge_old(void) {
|
|||
return;
|
||||
status = nfsd4_list_rec_dir(rec_dir.dentry, purge_old);
|
||||
if (status == 0)
|
||||
status = nfsd4_rec_fsync(rec_dir.dentry);
|
||||
nfsd4_sync_rec_dir();
|
||||
if (status)
|
||||
printk("nfsd4: failed to purge old clients from recovery"
|
||||
" directory %s\n", rec_dir.dentry->d_name.name);
|
||||
|
|
|
|||
|
|
@ -874,6 +874,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, struct nfsd4_setclientid_confi
|
|||
* change request correctly. */
|
||||
atomic_set(&conf->cl_callback.cb_set, 0);
|
||||
gen_confirm(conf);
|
||||
nfsd4_remove_clid_dir(unconf);
|
||||
expire_client(unconf);
|
||||
status = nfs_ok;
|
||||
|
||||
|
|
@ -1159,6 +1160,7 @@ init_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *
|
|||
stp->st_deny_bmap = 0;
|
||||
__set_bit(open->op_share_access, &stp->st_access_bmap);
|
||||
__set_bit(open->op_share_deny, &stp->st_deny_bmap);
|
||||
stp->st_openstp = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -1294,7 +1296,7 @@ nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type)
|
|||
fp = find_file(ino);
|
||||
if (!fp)
|
||||
return nfs_ok;
|
||||
ret = nfserr_share_denied;
|
||||
ret = nfserr_locked;
|
||||
/* Search for conflicting share reservations */
|
||||
list_for_each_entry(stp, &fp->fi_stateids, st_perfile) {
|
||||
if (test_bit(deny_type, &stp->st_deny_bmap) ||
|
||||
|
|
@ -1482,7 +1484,7 @@ nfsd4_process_open1(struct nfsd4_open *open)
|
|||
if (sop) {
|
||||
open->op_stateowner = sop;
|
||||
/* check for replay */
|
||||
if (open->op_seqid == sop->so_seqid){
|
||||
if (open->op_seqid == sop->so_seqid - 1){
|
||||
if (sop->so_replay.rp_buflen)
|
||||
return NFSERR_REPLAY_ME;
|
||||
else {
|
||||
|
|
@ -1497,7 +1499,7 @@ nfsd4_process_open1(struct nfsd4_open *open)
|
|||
goto renew;
|
||||
}
|
||||
} else if (sop->so_confirmed) {
|
||||
if (open->op_seqid == sop->so_seqid + 1)
|
||||
if (open->op_seqid == sop->so_seqid)
|
||||
goto renew;
|
||||
status = nfserr_bad_seqid;
|
||||
goto out;
|
||||
|
|
@ -1530,8 +1532,6 @@ renew:
|
|||
status = nfs_ok;
|
||||
renew_client(sop->so_client);
|
||||
out:
|
||||
if (status && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
|
||||
status = nfserr_reclaim_bad;
|
||||
return status;
|
||||
}
|
||||
|
||||
|
|
@ -1685,19 +1685,11 @@ nfs4_upgrade_open(struct svc_rqst *rqstp, struct svc_fh *cur_fh, struct nfs4_sta
|
|||
}
|
||||
|
||||
|
||||
/* decrement seqid on successful reclaim, it will be bumped in encode_open */
|
||||
static void
|
||||
nfs4_set_claim_prev(struct nfsd4_open *open, int *status)
|
||||
nfs4_set_claim_prev(struct nfsd4_open *open)
|
||||
{
|
||||
if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) {
|
||||
if (*status)
|
||||
*status = nfserr_reclaim_bad;
|
||||
else {
|
||||
open->op_stateowner->so_confirmed = 1;
|
||||
open->op_stateowner->so_client->cl_firststate = 1;
|
||||
open->op_stateowner->so_seqid--;
|
||||
}
|
||||
}
|
||||
open->op_stateowner->so_confirmed = 1;
|
||||
open->op_stateowner->so_client->cl_firststate = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1789,6 +1781,12 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
|
|||
struct nfs4_delegation *dp = NULL;
|
||||
int status;
|
||||
|
||||
if (nfs4_in_grace() && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS)
|
||||
return nfserr_grace;
|
||||
|
||||
if (!nfs4_in_grace() && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
|
||||
return nfserr_no_grace;
|
||||
|
||||
status = nfserr_inval;
|
||||
if (!TEST_ACCESS(open->op_share_access) || !TEST_DENY(open->op_share_deny))
|
||||
goto out;
|
||||
|
|
@ -1823,6 +1821,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
|
|||
status = nfs4_upgrade_open(rqstp, current_fh, stp, open);
|
||||
if (status)
|
||||
goto out;
|
||||
update_stateid(&stp->st_stateid);
|
||||
} else {
|
||||
/* Stateid was not found, this is a new OPEN */
|
||||
int flags = 0;
|
||||
|
|
@ -1856,8 +1855,8 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
|
|||
out:
|
||||
if (fp)
|
||||
put_nfs4_file(fp);
|
||||
/* CLAIM_PREVIOUS has different error returns */
|
||||
nfs4_set_claim_prev(open, &status);
|
||||
if (status == 0 && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
|
||||
nfs4_set_claim_prev(open);
|
||||
/*
|
||||
* To finish the open response, we just need to set the rflags.
|
||||
*/
|
||||
|
|
@ -1990,14 +1989,11 @@ laundromat_main(void *not_used)
|
|||
queue_delayed_work(laundry_wq, &laundromat_work, t*HZ);
|
||||
}
|
||||
|
||||
/* search ownerid_hashtbl[] and close_lru for stateid owner
|
||||
* (stateid->si_stateownerid)
|
||||
*/
|
||||
static struct nfs4_stateowner *
|
||||
find_openstateowner_id(u32 st_id, int flags) {
|
||||
search_close_lru(u32 st_id, int flags)
|
||||
{
|
||||
struct nfs4_stateowner *local = NULL;
|
||||
|
||||
dprintk("NFSD: find_openstateowner_id %d\n", st_id);
|
||||
if (flags & CLOSE_STATE) {
|
||||
list_for_each_entry(local, &close_lru, so_close_lru) {
|
||||
if (local->so_id == st_id)
|
||||
|
|
@ -2163,14 +2159,19 @@ out:
|
|||
return status;
|
||||
}
|
||||
|
||||
static inline int
|
||||
setlkflg (int type)
|
||||
{
|
||||
return (type == NFS4_READW_LT || type == NFS4_READ_LT) ?
|
||||
RD_STATE : WR_STATE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks for sequence id mutating operations.
|
||||
*/
|
||||
static int
|
||||
nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *stateid, int flags, struct nfs4_stateowner **sopp, struct nfs4_stateid **stpp, clientid_t *lockclid)
|
||||
nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *stateid, int flags, struct nfs4_stateowner **sopp, struct nfs4_stateid **stpp, struct nfsd4_lock *lock)
|
||||
{
|
||||
int status;
|
||||
struct nfs4_stateid *stp;
|
||||
struct nfs4_stateowner *sop;
|
||||
|
||||
|
|
@ -2178,53 +2179,65 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei
|
|||
"stateid = (%08x/%08x/%08x/%08x)\n", seqid,
|
||||
stateid->si_boot, stateid->si_stateownerid, stateid->si_fileid,
|
||||
stateid->si_generation);
|
||||
|
||||
|
||||
*stpp = NULL;
|
||||
*sopp = NULL;
|
||||
|
||||
status = nfserr_bad_stateid;
|
||||
if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) {
|
||||
printk("NFSD: preprocess_seqid_op: magic stateid!\n");
|
||||
goto out;
|
||||
return nfserr_bad_stateid;
|
||||
}
|
||||
|
||||
status = nfserr_stale_stateid;
|
||||
if (STALE_STATEID(stateid))
|
||||
goto out;
|
||||
return nfserr_stale_stateid;
|
||||
/*
|
||||
* We return BAD_STATEID if filehandle doesn't match stateid,
|
||||
* the confirmed flag is incorrecly set, or the generation
|
||||
* number is incorrect.
|
||||
* If there is no entry in the openfile table for this id,
|
||||
* we can't always return BAD_STATEID;
|
||||
* this might be a retransmitted CLOSE which has arrived after
|
||||
* the openfile has been released.
|
||||
*/
|
||||
if (!(stp = find_stateid(stateid, flags)))
|
||||
goto no_nfs4_stateid;
|
||||
stp = find_stateid(stateid, flags);
|
||||
if (stp == NULL) {
|
||||
/*
|
||||
* Also, we should make sure this isn't just the result of
|
||||
* a replayed close:
|
||||
*/
|
||||
sop = search_close_lru(stateid->si_stateownerid, flags);
|
||||
if (sop == NULL)
|
||||
return nfserr_bad_stateid;
|
||||
*sopp = sop;
|
||||
goto check_replay;
|
||||
}
|
||||
|
||||
status = nfserr_bad_stateid;
|
||||
|
||||
/* for new lock stateowners:
|
||||
* check that the lock->v.new.open_stateid
|
||||
* refers to an open stateowner
|
||||
*
|
||||
* check that the lockclid (nfs4_lock->v.new.clientid) is the same
|
||||
* as the open_stateid->st_stateowner->so_client->clientid
|
||||
*/
|
||||
if (lockclid) {
|
||||
if (lock) {
|
||||
struct nfs4_stateowner *sop = stp->st_stateowner;
|
||||
clientid_t *lockclid = &lock->v.new.clientid;
|
||||
struct nfs4_client *clp = sop->so_client;
|
||||
int lkflg = 0;
|
||||
int status;
|
||||
|
||||
lkflg = setlkflg(lock->lk_type);
|
||||
|
||||
if (lock->lk_is_new) {
|
||||
if (!sop->so_is_open_owner)
|
||||
return nfserr_bad_stateid;
|
||||
if (!cmp_clid(&clp->cl_clientid, lockclid))
|
||||
return nfserr_bad_stateid;
|
||||
/* stp is the open stateid */
|
||||
status = nfs4_check_openmode(stp, lkflg);
|
||||
if (status)
|
||||
return status;
|
||||
} else {
|
||||
/* stp is the lock stateid */
|
||||
status = nfs4_check_openmode(stp->st_openstp, lkflg);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
|
||||
if (!sop->so_is_open_owner)
|
||||
goto out;
|
||||
if (!cmp_clid(&clp->cl_clientid, lockclid))
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((flags & CHECK_FH) && nfs4_check_fh(current_fh, stp)) {
|
||||
printk("NFSD: preprocess_seqid_op: fh-stateid mismatch!\n");
|
||||
goto out;
|
||||
return nfserr_bad_stateid;
|
||||
}
|
||||
|
||||
*stpp = stp;
|
||||
|
|
@ -2235,63 +2248,41 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei
|
|||
* For the moment, we ignore the possibility of
|
||||
* generation number wraparound.
|
||||
*/
|
||||
if (seqid != sop->so_seqid + 1)
|
||||
if (seqid != sop->so_seqid)
|
||||
goto check_replay;
|
||||
|
||||
if (sop->so_confirmed) {
|
||||
if (flags & CONFIRM) {
|
||||
printk("NFSD: preprocess_seqid_op: expected unconfirmed stateowner!\n");
|
||||
goto out;
|
||||
}
|
||||
if (sop->so_confirmed && flags & CONFIRM) {
|
||||
printk("NFSD: preprocess_seqid_op: expected"
|
||||
" unconfirmed stateowner!\n");
|
||||
return nfserr_bad_stateid;
|
||||
}
|
||||
else {
|
||||
if (!(flags & CONFIRM)) {
|
||||
printk("NFSD: preprocess_seqid_op: stateowner not confirmed yet!\n");
|
||||
goto out;
|
||||
}
|
||||
if (!sop->so_confirmed && !(flags & CONFIRM)) {
|
||||
printk("NFSD: preprocess_seqid_op: stateowner not"
|
||||
" confirmed yet!\n");
|
||||
return nfserr_bad_stateid;
|
||||
}
|
||||
if (stateid->si_generation > stp->st_stateid.si_generation) {
|
||||
printk("NFSD: preprocess_seqid_op: future stateid?!\n");
|
||||
goto out;
|
||||
return nfserr_bad_stateid;
|
||||
}
|
||||
|
||||
status = nfserr_old_stateid;
|
||||
if (stateid->si_generation < stp->st_stateid.si_generation) {
|
||||
printk("NFSD: preprocess_seqid_op: old stateid!\n");
|
||||
goto out;
|
||||
return nfserr_old_stateid;
|
||||
}
|
||||
/* XXX renew the client lease here */
|
||||
status = nfs_ok;
|
||||
|
||||
out:
|
||||
return status;
|
||||
|
||||
no_nfs4_stateid:
|
||||
|
||||
/*
|
||||
* We determine whether this is a bad stateid or a replay,
|
||||
* starting by trying to look up the stateowner.
|
||||
* If stateowner is not found - stateid is bad.
|
||||
*/
|
||||
if (!(sop = find_openstateowner_id(stateid->si_stateownerid, flags))) {
|
||||
printk("NFSD: preprocess_seqid_op: no stateowner or nfs4_stateid!\n");
|
||||
status = nfserr_bad_stateid;
|
||||
goto out;
|
||||
}
|
||||
*sopp = sop;
|
||||
renew_client(sop->so_client);
|
||||
return nfs_ok;
|
||||
|
||||
check_replay:
|
||||
if (seqid == sop->so_seqid) {
|
||||
if (seqid == sop->so_seqid - 1) {
|
||||
printk("NFSD: preprocess_seqid_op: retransmission?\n");
|
||||
/* indicate replay to calling function */
|
||||
status = NFSERR_REPLAY_ME;
|
||||
} else {
|
||||
printk("NFSD: preprocess_seqid_op: bad seqid (expected %d, got %d\n", sop->so_seqid +1, seqid);
|
||||
|
||||
*sopp = NULL;
|
||||
status = nfserr_bad_seqid;
|
||||
return NFSERR_REPLAY_ME;
|
||||
}
|
||||
goto out;
|
||||
printk("NFSD: preprocess_seqid_op: bad seqid (expected %d, got %d)\n",
|
||||
sop->so_seqid, seqid);
|
||||
*sopp = NULL;
|
||||
return nfserr_bad_seqid;
|
||||
}
|
||||
|
||||
int
|
||||
|
|
@ -2609,7 +2600,6 @@ find_lockstateowner_str(struct inode *inode, clientid_t *clid,
|
|||
* occured.
|
||||
*
|
||||
* strhashval = lock_ownerstr_hashval
|
||||
* so_seqid = lock->lk_new_lock_seqid - 1: it gets bumped in encode
|
||||
*/
|
||||
|
||||
static struct nfs4_stateowner *
|
||||
|
|
@ -2634,7 +2624,7 @@ alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, str
|
|||
sop->so_is_open_owner = 0;
|
||||
sop->so_id = current_ownerid++;
|
||||
sop->so_client = clp;
|
||||
sop->so_seqid = lock->lk_new_lock_seqid - 1;
|
||||
sop->so_seqid = lock->lk_new_lock_seqid;
|
||||
sop->so_confirmed = 1;
|
||||
rp = &sop->so_replay;
|
||||
rp->rp_status = NFSERR_SERVERFAULT;
|
||||
|
|
@ -2669,6 +2659,7 @@ alloc_init_lock_stateid(struct nfs4_stateowner *sop, struct nfs4_file *fp, struc
|
|||
stp->st_vfs_file = open_stp->st_vfs_file; /* FIXME refcount?? */
|
||||
stp->st_access_bmap = open_stp->st_access_bmap;
|
||||
stp->st_deny_bmap = open_stp->st_deny_bmap;
|
||||
stp->st_openstp = open_stp;
|
||||
|
||||
out:
|
||||
return stp;
|
||||
|
|
@ -2699,22 +2690,17 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
|
|||
(long long) lock->lk_offset,
|
||||
(long long) lock->lk_length);
|
||||
|
||||
if (nfs4_in_grace() && !lock->lk_reclaim)
|
||||
return nfserr_grace;
|
||||
if (!nfs4_in_grace() && lock->lk_reclaim)
|
||||
return nfserr_no_grace;
|
||||
|
||||
if (check_lock_length(lock->lk_offset, lock->lk_length))
|
||||
return nfserr_inval;
|
||||
|
||||
nfs4_lock_state();
|
||||
|
||||
if (lock->lk_is_new) {
|
||||
/*
|
||||
* Client indicates that this is a new lockowner.
|
||||
* Use open owner and open stateid to create lock owner and lock
|
||||
* stateid.
|
||||
*/
|
||||
/*
|
||||
* Client indicates that this is a new lockowner.
|
||||
* Use open owner and open stateid to create lock owner and
|
||||
* lock stateid.
|
||||
*/
|
||||
struct nfs4_stateid *open_stp = NULL;
|
||||
struct nfs4_file *fp;
|
||||
|
||||
|
|
@ -2724,23 +2710,14 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
|
|||
goto out;
|
||||
}
|
||||
|
||||
/* is the new lock seqid presented by the client zero? */
|
||||
status = nfserr_bad_seqid;
|
||||
if (lock->v.new.lock_seqid != 0)
|
||||
goto out;
|
||||
|
||||
/* validate and update open stateid and open seqid */
|
||||
status = nfs4_preprocess_seqid_op(current_fh,
|
||||
lock->lk_new_open_seqid,
|
||||
&lock->lk_new_open_stateid,
|
||||
CHECK_FH | OPEN_STATE,
|
||||
&open_sop, &open_stp,
|
||||
&lock->v.new.clientid);
|
||||
if (status) {
|
||||
if (lock->lk_reclaim)
|
||||
status = nfserr_reclaim_bad;
|
||||
&open_sop, &open_stp, lock);
|
||||
if (status)
|
||||
goto out;
|
||||
}
|
||||
/* create lockowner and lock stateid */
|
||||
fp = open_stp->st_file;
|
||||
strhashval = lock_ownerstr_hashval(fp->fi_inode,
|
||||
|
|
@ -2766,7 +2743,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
|
|||
lock->lk_old_lock_seqid,
|
||||
&lock->lk_old_lock_stateid,
|
||||
CHECK_FH | LOCK_STATE,
|
||||
&lock->lk_stateowner, &lock_stp, NULL);
|
||||
&lock->lk_stateowner, &lock_stp, lock);
|
||||
if (status)
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -2778,6 +2755,13 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
|
|||
goto out;
|
||||
}
|
||||
|
||||
status = nfserr_grace;
|
||||
if (nfs4_in_grace() && !lock->lk_reclaim)
|
||||
goto out;
|
||||
status = nfserr_no_grace;
|
||||
if (!nfs4_in_grace() && lock->lk_reclaim)
|
||||
goto out;
|
||||
|
||||
locks_init_lock(&file_lock);
|
||||
switch (lock->lk_type) {
|
||||
case NFS4_READ_LT:
|
||||
|
|
@ -2844,10 +2828,10 @@ conflicting_lock:
|
|||
out_destroy_new_stateid:
|
||||
if (lock->lk_is_new) {
|
||||
dprintk("NFSD: nfsd4_lock: destroy new stateid!\n");
|
||||
/*
|
||||
* An error encountered after instantiation of the new
|
||||
* stateid has forced us to destroy it.
|
||||
*/
|
||||
/*
|
||||
* An error encountered after instantiation of the new
|
||||
* stateid has forced us to destroy it.
|
||||
*/
|
||||
if (!seqid_mutating_err(status))
|
||||
open_sop->so_seqid--;
|
||||
|
||||
|
|
@ -3083,7 +3067,12 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner *
|
|||
* of the lockowner state released; so don't release any until all
|
||||
* have been checked. */
|
||||
status = nfs_ok;
|
||||
list_for_each_entry(sop, &matches, so_perclient) {
|
||||
while (!list_empty(&matches)) {
|
||||
sop = list_entry(matches.next, struct nfs4_stateowner,
|
||||
so_perclient);
|
||||
/* unhash_stateowner deletes so_perclient only
|
||||
* for openowners. */
|
||||
list_del(&sop->so_perclient);
|
||||
release_stateowner(sop);
|
||||
}
|
||||
out:
|
||||
|
|
|
|||
|
|
@ -1210,16 +1210,15 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
|
|||
save = resp->p;
|
||||
|
||||
/*
|
||||
* Routine for encoding the result of a
|
||||
* "seqid-mutating" NFSv4 operation. This is
|
||||
* where seqids are incremented, and the
|
||||
* replay cache is filled.
|
||||
* Routine for encoding the result of a "seqid-mutating" NFSv4 operation. This
|
||||
* is where sequence id's are incremented, and the replay cache is filled.
|
||||
* Note that we increment sequence id's here, at the last moment, so we're sure
|
||||
* we know whether the error to be returned is a sequence id mutating error.
|
||||
*/
|
||||
|
||||
#define ENCODE_SEQID_OP_TAIL(stateowner) do { \
|
||||
if (seqid_mutating_err(nfserr) && stateowner) { \
|
||||
if (stateowner->so_confirmed) \
|
||||
stateowner->so_seqid++; \
|
||||
stateowner->so_seqid++; \
|
||||
stateowner->so_replay.rp_status = nfserr; \
|
||||
stateowner->so_replay.rp_buflen = \
|
||||
(((char *)(resp)->p - (char *)save)); \
|
||||
|
|
@ -1367,9 +1366,9 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
|
|||
if ((buflen -= 4) < 0)
|
||||
goto out_resource;
|
||||
if (exp->ex_flags & NFSEXP_NOSUBTREECHECK)
|
||||
WRITE32(NFS4_FH_VOLATILE_ANY);
|
||||
WRITE32(NFS4_FH_PERSISTENT);
|
||||
else
|
||||
WRITE32(NFS4_FH_VOLATILE_ANY|NFS4_FH_VOL_RENAME);
|
||||
WRITE32(NFS4_FH_PERSISTENT|NFS4_FH_VOL_RENAME);
|
||||
}
|
||||
if (bmval0 & FATTR4_WORD0_CHANGE) {
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@
|
|||
#endif /* CONFIG_NFSD_V3 */
|
||||
#include <linux/nfsd/nfsfh.h>
|
||||
#include <linux/quotaops.h>
|
||||
#include <linux/dnotify.h>
|
||||
#include <linux/fsnotify.h>
|
||||
#include <linux/posix_acl.h>
|
||||
#include <linux/posix_acl_xattr.h>
|
||||
#ifdef CONFIG_NFSD_V4
|
||||
|
|
@ -733,7 +733,7 @@ nfsd_sync(struct file *filp)
|
|||
up(&inode->i_sem);
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
nfsd_sync_dir(struct dentry *dp)
|
||||
{
|
||||
nfsd_dosync(NULL, dp, dp->d_inode->i_fop);
|
||||
|
|
@ -860,7 +860,7 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
|
|||
nfsdstats.io_read += err;
|
||||
*count = err;
|
||||
err = 0;
|
||||
dnotify_parent(file->f_dentry, DN_ACCESS);
|
||||
fsnotify_access(file->f_dentry);
|
||||
} else
|
||||
err = nfserrno(err);
|
||||
out:
|
||||
|
|
@ -916,7 +916,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
|
|||
set_fs(oldfs);
|
||||
if (err >= 0) {
|
||||
nfsdstats.io_write += cnt;
|
||||
dnotify_parent(file->f_dentry, DN_MODIFY);
|
||||
fsnotify_modify(file->f_dentry);
|
||||
}
|
||||
|
||||
/* clear setuid/setgid flag after write */
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
#include <linux/file.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/quotaops.h>
|
||||
#include <linux/dnotify.h>
|
||||
#include <linux/fsnotify.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/tty.h>
|
||||
|
|
@ -951,6 +951,7 @@ asmlinkage long sys_open(const char __user * filename, int flags, int mode)
|
|||
put_unused_fd(fd);
|
||||
fd = PTR_ERR(f);
|
||||
} else {
|
||||
fsnotify_open(f->f_dentry);
|
||||
fd_install(fd, f);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
#include <linux/file.h>
|
||||
#include <linux/uio.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/dnotify.h>
|
||||
#include <linux/fsnotify.h>
|
||||
#include <linux/security.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/syscalls.h>
|
||||
|
|
@ -252,7 +252,7 @@ ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
|
|||
else
|
||||
ret = do_sync_read(file, buf, count, pos);
|
||||
if (ret > 0) {
|
||||
dnotify_parent(file->f_dentry, DN_ACCESS);
|
||||
fsnotify_access(file->f_dentry);
|
||||
current->rchar += ret;
|
||||
}
|
||||
current->syscr++;
|
||||
|
|
@ -303,7 +303,7 @@ ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_
|
|||
else
|
||||
ret = do_sync_write(file, buf, count, pos);
|
||||
if (ret > 0) {
|
||||
dnotify_parent(file->f_dentry, DN_MODIFY);
|
||||
fsnotify_modify(file->f_dentry);
|
||||
current->wchar += ret;
|
||||
}
|
||||
current->syscw++;
|
||||
|
|
@ -539,9 +539,12 @@ static ssize_t do_readv_writev(int type, struct file *file,
|
|||
out:
|
||||
if (iov != iovstack)
|
||||
kfree(iov);
|
||||
if ((ret + (type == READ)) > 0)
|
||||
dnotify_parent(file->f_dentry,
|
||||
(type == READ) ? DN_ACCESS : DN_MODIFY);
|
||||
if ((ret + (type == READ)) > 0) {
|
||||
if (type == READ)
|
||||
fsnotify_access(file->f_dentry);
|
||||
else
|
||||
fsnotify_modify(file->f_dentry);
|
||||
}
|
||||
return ret;
|
||||
Efault:
|
||||
ret = -EFAULT;
|
||||
|
|
|
|||
1836
fs/reiserfs/bitmap.c
1836
fs/reiserfs/bitmap.c
File diff suppressed because it is too large
Load diff
|
|
@ -12,264 +12,286 @@
|
|||
#include <linux/buffer_head.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
extern struct reiserfs_key MIN_KEY;
|
||||
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) ;
|
||||
static int reiserfs_readdir(struct file *, void *, filldir_t);
|
||||
static int reiserfs_dir_fsync(struct file *filp, struct dentry *dentry,
|
||||
int datasync);
|
||||
|
||||
struct file_operations reiserfs_dir_operations = {
|
||||
.read = generic_read_dir,
|
||||
.readdir = reiserfs_readdir,
|
||||
.fsync = reiserfs_dir_fsync,
|
||||
.ioctl = reiserfs_ioctl,
|
||||
.read = generic_read_dir,
|
||||
.readdir = reiserfs_readdir,
|
||||
.fsync = reiserfs_dir_fsync,
|
||||
.ioctl = reiserfs_ioctl,
|
||||
};
|
||||
|
||||
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;
|
||||
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)
|
||||
static int reiserfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
||||
{
|
||||
struct inode *inode = filp->f_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;
|
||||
struct inode *inode = filp->f_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_write_lock(inode->i_sb);
|
||||
|
||||
reiserfs_check_lock_depth(inode->i_sb, "readdir") ;
|
||||
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);
|
||||
/* 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);*/
|
||||
/* 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_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 = reiserfs_kmalloc(d_reclen, GFP_NOFS, inode->i_sb) ;
|
||||
if (!local_buf) {
|
||||
pathrelse (&path_to_entry);
|
||||
ret = -ENOMEM ;
|
||||
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;
|
||||
}
|
||||
if (item_moved (&tmp_ih, &path_to_entry)) {
|
||||
reiserfs_kfree(local_buf, d_reclen, inode->i_sb) ;
|
||||
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) {
|
||||
reiserfs_kfree(local_buf, d_reclen, inode->i_sb) ;
|
||||
}
|
||||
goto end;
|
||||
}
|
||||
if (local_buf != small_buf) {
|
||||
reiserfs_kfree(local_buf, d_reclen, inode->i_sb) ;
|
||||
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_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 =
|
||||
reiserfs_kmalloc(d_reclen, GFP_NOFS,
|
||||
inode->i_sb);
|
||||
if (!local_buf) {
|
||||
pathrelse(&path_to_entry);
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
if (item_moved(&tmp_ih, &path_to_entry)) {
|
||||
reiserfs_kfree(local_buf,
|
||||
d_reclen,
|
||||
inode->i_sb);
|
||||
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) {
|
||||
reiserfs_kfree(local_buf,
|
||||
d_reclen,
|
||||
inode->i_sb);
|
||||
}
|
||||
goto end;
|
||||
}
|
||||
if (local_buf != small_buf) {
|
||||
reiserfs_kfree(local_buf, d_reclen,
|
||||
inode->i_sb);
|
||||
}
|
||||
// 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 */
|
||||
}
|
||||
|
||||
// next entry should be looked for with such offset
|
||||
next_pos = deh_offset (deh) + 1;
|
||||
if (item_num != B_NR_ITEMS(bh) - 1)
|
||||
// end of directory has been reached
|
||||
goto end;
|
||||
|
||||
if (item_moved (&tmp_ih, &path_to_entry)) {
|
||||
goto research;
|
||||
/* 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;
|
||||
}
|
||||
} /* for */
|
||||
}
|
||||
|
||||
if (item_num != B_NR_ITEMS (bh) - 1)
|
||||
// end of directory has been reached
|
||||
goto end;
|
||||
if (COMP_SHORT_KEYS(rkey, &pos_key)) {
|
||||
// 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;
|
||||
}
|
||||
/* directory continues in the right neighboring block */
|
||||
set_cpu_key_k_offset(&pos_key,
|
||||
le_key_k_offset(KEY_FORMAT_3_5, rkey));
|
||||
|
||||
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 */
|
||||
|
||||
} /* 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;
|
||||
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)
|
||||
void make_empty_dir_item_v1(char *body, __le32 dirid, __le32 objid,
|
||||
__le32 par_dirid, __le32 par_objid)
|
||||
{
|
||||
struct reiserfs_de_head * deh;
|
||||
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]));
|
||||
memset(body, 0, EMPTY_DIR_SIZE_V1);
|
||||
deh = (struct reiserfs_de_head *)body;
|
||||
|
||||
/* copy ".." and "." */
|
||||
memcpy (body + deh_location( &(deh[0]) ), ".", 1);
|
||||
memcpy (body + deh_location( &(deh[1]) ), "..", 2);
|
||||
/* 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)
|
||||
void make_empty_dir_item(char *body, __le32 dirid, __le32 objid,
|
||||
__le32 par_dirid, __le32 par_objid)
|
||||
{
|
||||
struct reiserfs_de_head * deh;
|
||||
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]));
|
||||
memset(body, 0, EMPTY_DIR_SIZE);
|
||||
deh = (struct reiserfs_de_head *)body;
|
||||
|
||||
/* copy ".." and "." */
|
||||
memcpy (body + deh_location( &(deh[0]) ), ".", 1);
|
||||
memcpy (body + deh_location( &(deh[1]) ), "..", 2);
|
||||
/* direntry header of "." */
|
||||
put_deh_offset(&(deh[0]), DOT_OFFSET);
|
||||
/* these two are from make_le_item_head, and are are LE */
|
||||
deh[0].deh_dir_id = dirid;
|
||||
deh[0].deh_objectid = objid;
|
||||
deh[0].deh_state = 0; /* Endian safe if 0 */
|
||||
put_deh_location(&(deh[0]), EMPTY_DIR_SIZE - ROUND_UP(strlen(".")));
|
||||
mark_de_visible(&(deh[0]));
|
||||
|
||||
/* direntry header of ".." */
|
||||
put_deh_offset(&(deh[1]), DOT_DOT_OFFSET);
|
||||
/* key of ".." for the root directory */
|
||||
/* these two are from the inode, and are are LE */
|
||||
deh[1].deh_dir_id = par_dirid;
|
||||
deh[1].deh_objectid = par_objid;
|
||||
deh[1].deh_state = 0; /* Endian safe if 0 */
|
||||
put_deh_location(&(deh[1]),
|
||||
deh_location(&(deh[0])) - ROUND_UP(strlen("..")));
|
||||
mark_de_visible(&(deh[1]));
|
||||
|
||||
/* copy ".." and "." */
|
||||
memcpy(body + deh_location(&(deh[0])), ".", 1);
|
||||
memcpy(body + deh_location(&(deh[1])), "..", 2);
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
2476
fs/reiserfs/file.c
2476
fs/reiserfs/file.c
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -22,7 +22,6 @@
|
|||
#include <asm/types.h>
|
||||
#include <asm/bug.h>
|
||||
|
||||
|
||||
#define DELTA 0x9E3779B9
|
||||
#define FULLROUNDS 10 /* 32 is overkill, 16 is strong crypto */
|
||||
#define PARTROUNDS 6 /* 6 gets complete mixing */
|
||||
|
|
@ -48,105 +47,75 @@
|
|||
h1 += b1; \
|
||||
} while(0)
|
||||
|
||||
|
||||
u32 keyed_hash(const signed char *msg, int len)
|
||||
{
|
||||
u32 k[] = { 0x9464a485, 0x542e1a94, 0x3e846bff, 0xb75bcfc3};
|
||||
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);
|
||||
// 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;
|
||||
|
||||
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;
|
||||
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++)
|
||||
{
|
||||
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;
|
||||
} 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++)
|
||||
{
|
||||
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;
|
||||
} 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++)
|
||||
{
|
||||
for (i = 4; i < len; i++) {
|
||||
b <<= 8;
|
||||
b |= msg[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
a = b = c = d = pad;
|
||||
for(i = 0; i < len; i++)
|
||||
{
|
||||
for (i = 0; i < len; i++) {
|
||||
a <<= 8;
|
||||
a |= msg[i];
|
||||
}
|
||||
|
|
@ -155,55 +124,59 @@ u32 keyed_hash(const signed char *msg, int len)
|
|||
TEACORE(FULLROUNDS);
|
||||
|
||||
/* return 0;*/
|
||||
return h0^h1;
|
||||
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)
|
||||
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;
|
||||
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 r5_hash(const signed char *msg, int len)
|
||||
{
|
||||
u32 a=0;
|
||||
while(*msg) {
|
||||
a += *msg << 4;
|
||||
a += *msg >> 4;
|
||||
a *= 11;
|
||||
msg++;
|
||||
}
|
||||
return a;
|
||||
u32 a = 0;
|
||||
while (*msg) {
|
||||
a += *msg << 4;
|
||||
a += *msg >> 4;
|
||||
a *= 11;
|
||||
msg++;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
4683
fs/reiserfs/inode.c
4683
fs/reiserfs/inode.c
File diff suppressed because it is too large
Load diff
|
|
@ -9,7 +9,7 @@
|
|||
#include <linux/pagemap.h>
|
||||
#include <linux/smp_lock.h>
|
||||
|
||||
static int reiserfs_unpack (struct inode * inode, struct file * filp);
|
||||
static int reiserfs_unpack(struct inode *inode, struct file *filp);
|
||||
|
||||
/*
|
||||
** reiserfs_ioctl - handler for ioctl for inode
|
||||
|
|
@ -19,69 +19,72 @@ static int reiserfs_unpack (struct inode * inode, struct file * filp);
|
|||
** 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)
|
||||
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);
|
||||
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) */
|
||||
/* 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))
|
||||
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;
|
||||
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 (IS_RDONLY(inode))
|
||||
return -EROFS;
|
||||
|
||||
if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
|
||||
return -EPERM;
|
||||
if ((current->fsuid != inode->i_uid)
|
||||
&& !capable(CAP_FOWNER))
|
||||
return -EPERM;
|
||||
|
||||
if (get_user(flags, (int __user *) arg))
|
||||
return -EFAULT;
|
||||
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 ) ) {
|
||||
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 )
|
||||
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;
|
||||
}
|
||||
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);
|
||||
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;
|
||||
if (get_user(inode->i_generation, (int __user *)arg))
|
||||
return -EFAULT;
|
||||
inode->i_ctime = CURRENT_TIME_SEC;
|
||||
mark_inode_dirty(inode);
|
||||
return 0;
|
||||
|
|
@ -95,63 +98,65 @@ int reiserfs_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
|
|||
** 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)
|
||||
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 ;
|
||||
}
|
||||
reiserfs_write_lock(inode->i_sb);
|
||||
int retval = 0;
|
||||
int index;
|
||||
struct page *page;
|
||||
struct address_space *mapping;
|
||||
unsigned long write_from;
|
||||
unsigned long blocksize = inode->i_sb->s_blocksize;
|
||||
|
||||
/* we need to make sure nobody is changing the file size beneath
|
||||
** us
|
||||
*/
|
||||
down(&inode->i_sem) ;
|
||||
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;
|
||||
}
|
||||
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) {
|
||||
/* we need to make sure nobody is changing the file size beneath
|
||||
** us
|
||||
*/
|
||||
down(&inode->i_sem);
|
||||
|
||||
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;
|
||||
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 ;
|
||||
out_unlock:
|
||||
unlock_page(page);
|
||||
page_cache_release(page);
|
||||
|
||||
/* 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:
|
||||
up(&inode->i_sem) ;
|
||||
reiserfs_write_unlock(inode->i_sb);
|
||||
return retval;
|
||||
out:
|
||||
up(&inode->i_sem);
|
||||
reiserfs_write_unlock(inode->i_sb);
|
||||
return retval;
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
2496
fs/reiserfs/namei.c
2496
fs/reiserfs/namei.c
File diff suppressed because it is too large
Load diff
|
|
@ -14,24 +14,24 @@
|
|||
(__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)
|
||||
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]));
|
||||
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
|
||||
// FIXME: add something else here
|
||||
}
|
||||
|
||||
#else
|
||||
static void check_objectid_map (struct super_block * s, __le32 * map)
|
||||
{;}
|
||||
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
|
||||
|
|
@ -46,161 +46,162 @@ static void check_objectid_map (struct super_block * s, __le32 * map)
|
|||
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)
|
||||
__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;
|
||||
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);
|
||||
BUG_ON(!th->t_trans_id);
|
||||
|
||||
check_objectid_map (s, map);
|
||||
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;
|
||||
}
|
||||
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);
|
||||
/* 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 );
|
||||
}
|
||||
/* 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;
|
||||
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)
|
||||
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;
|
||||
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);
|
||||
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));
|
||||
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);
|
||||
/* 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 );
|
||||
/* 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;
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
/* 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 ;
|
||||
/* finally, zero out the unused chunk of the new super */
|
||||
memset(disk_sb->s_unused, 0, sizeof(disk_sb->s_unused));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -33,28 +33,27 @@
|
|||
static int show_version(struct seq_file *m, struct super_block *sb)
|
||||
{
|
||||
char *format;
|
||||
|
||||
if ( REISERFS_SB(sb)->s_properties & (1 << REISERFS_3_6) ) {
|
||||
|
||||
if (REISERFS_SB(sb)->s_properties & (1 << REISERFS_3_6)) {
|
||||
format = "3.6";
|
||||
} else if ( REISERFS_SB(sb)->s_properties & (1 << REISERFS_3_5) ) {
|
||||
} 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,
|
||||
seq_printf(m, "%s format\twith checks %s\n", format,
|
||||
#if defined( CONFIG_REISERFS_CHECK )
|
||||
"on"
|
||||
"on"
|
||||
#else
|
||||
"off"
|
||||
"off"
|
||||
#endif
|
||||
);
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int reiserfs_global_version_in_proc( char *buffer, char **start, off_t offset,
|
||||
int count, int *eof, void *data )
|
||||
int reiserfs_global_version_in_proc(char *buffer, char **start, off_t offset,
|
||||
int count, int *eof, void *data)
|
||||
{
|
||||
*start = buffer;
|
||||
*eof = 1;
|
||||
|
|
@ -79,87 +78,68 @@ int reiserfs_global_version_in_proc( char *buffer, char **start, off_t offset,
|
|||
|
||||
#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 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_kmallocs: \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_kmallocs ),
|
||||
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 ) );
|
||||
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_kmallocs: \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_kmallocs),
|
||||
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;
|
||||
}
|
||||
|
|
@ -169,61 +149,55 @@ 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"
|
||||
|
||||
);
|
||||
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 )
|
||||
);
|
||||
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;
|
||||
}
|
||||
|
|
@ -232,31 +206,30 @@ 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 ) );
|
||||
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;
|
||||
}
|
||||
|
|
@ -264,46 +237,42 @@ static int show_bitmap(struct seq_file *m, struct super_block *sb)
|
|||
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 );
|
||||
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));
|
||||
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;
|
||||
}
|
||||
|
|
@ -311,131 +280,122 @@ static int show_on_disk_super(struct seq_file *m, struct super_block *sb)
|
|||
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 );
|
||||
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 ) {
|
||||
for (i = 0; i < mapsize; ++i) {
|
||||
__u32 right;
|
||||
|
||||
right = ( i == mapsize - 1 ) ? MAX_KEY_OBJECTID : MAP( i + 1 );
|
||||
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 );
|
||||
(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 ) ) {
|
||||
if (sb_info->oidmap.use_file && (sb_info->oidmap.mapf != NULL)) {
|
||||
loff_t size = sb_info->oidmap.mapf->f_dentry->d_inode->i_size;
|
||||
total_used += size / sizeof( reiserfs_oidinterval_d_t );
|
||||
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);
|
||||
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 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 )
|
||||
);
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -450,7 +410,7 @@ static int set_sb(struct super_block *sb, void *data)
|
|||
return -ENOENT;
|
||||
}
|
||||
|
||||
static void *r_start(struct seq_file *m, loff_t *pos)
|
||||
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;
|
||||
|
|
@ -472,7 +432,7 @@ static void *r_start(struct seq_file *m, loff_t *pos)
|
|||
return s;
|
||||
}
|
||||
|
||||
static void *r_next(struct seq_file *m, void *v, loff_t *pos)
|
||||
static void *r_next(struct seq_file *m, void *v, loff_t * pos)
|
||||
{
|
||||
++*pos;
|
||||
if (v)
|
||||
|
|
@ -489,7 +449,7 @@ static void r_stop(struct seq_file *m, void *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;
|
||||
int (*show) (struct seq_file *, struct super_block *) = de->data;
|
||||
return show(m, v);
|
||||
}
|
||||
|
||||
|
|
@ -512,17 +472,17 @@ static int r_open(struct inode *inode, struct file *file)
|
|||
}
|
||||
|
||||
static struct file_operations r_file_operations = {
|
||||
.open = r_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = seq_release,
|
||||
.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 *))
|
||||
int (*func) (struct seq_file *, struct super_block *))
|
||||
{
|
||||
struct proc_dir_entry *de;
|
||||
de = create_proc_entry(name, 0, REISERFS_SB(sb)->procdir);
|
||||
|
|
@ -532,11 +492,12 @@ static void add_file(struct super_block *sb, char *name,
|
|||
}
|
||||
}
|
||||
|
||||
int reiserfs_proc_info_init( struct super_block *sb )
|
||||
int reiserfs_proc_info_init(struct super_block *sb)
|
||||
{
|
||||
spin_lock_init( & __PINFO( sb ).lock );
|
||||
REISERFS_SB(sb)->procdir = proc_mkdir(reiserfs_bdevname (sb), proc_info_root);
|
||||
if( REISERFS_SB(sb)->procdir ) {
|
||||
spin_lock_init(&__PINFO(sb).lock);
|
||||
REISERFS_SB(sb)->procdir =
|
||||
proc_mkdir(reiserfs_bdevname(sb), 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);
|
||||
|
|
@ -549,11 +510,11 @@ int reiserfs_proc_info_init( struct super_block *sb )
|
|||
return 0;
|
||||
}
|
||||
reiserfs_warning(sb, "reiserfs: cannot create /proc/%s/%s",
|
||||
proc_info_root_name, reiserfs_bdevname (sb) );
|
||||
proc_info_root_name, reiserfs_bdevname(sb));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int reiserfs_proc_info_done( struct super_block *sb )
|
||||
int reiserfs_proc_info_done(struct super_block *sb)
|
||||
{
|
||||
struct proc_dir_entry *de = REISERFS_SB(sb)->procdir;
|
||||
if (de) {
|
||||
|
|
@ -565,48 +526,48 @@ int reiserfs_proc_info_done( struct super_block *sb )
|
|||
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( reiserfs_bdevname (sb), proc_info_root );
|
||||
spin_lock(&__PINFO(sb).lock);
|
||||
__PINFO(sb).exiting = 1;
|
||||
spin_unlock(&__PINFO(sb).lock);
|
||||
if (proc_info_root) {
|
||||
remove_proc_entry(reiserfs_bdevname(sb), proc_info_root);
|
||||
REISERFS_SB(sb)->procdir = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct proc_dir_entry *reiserfs_proc_register_global( char *name,
|
||||
read_proc_t *func )
|
||||
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;
|
||||
return (proc_info_root) ? create_proc_read_entry(name, 0,
|
||||
proc_info_root,
|
||||
func, NULL) : NULL;
|
||||
}
|
||||
|
||||
void reiserfs_proc_unregister_global( const char *name )
|
||||
void reiserfs_proc_unregister_global(const char *name)
|
||||
{
|
||||
remove_proc_entry( name, proc_info_root );
|
||||
remove_proc_entry(name, proc_info_root);
|
||||
}
|
||||
|
||||
int reiserfs_proc_info_global_init( void )
|
||||
int reiserfs_proc_info_global_init(void)
|
||||
{
|
||||
if( proc_info_root == NULL ) {
|
||||
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;
|
||||
if (proc_info_root) {
|
||||
proc_info_root->owner = THIS_MODULE;
|
||||
} else {
|
||||
reiserfs_warning (NULL,
|
||||
"reiserfs: cannot create /proc/%s",
|
||||
proc_info_root_name );
|
||||
reiserfs_warning(NULL,
|
||||
"reiserfs: cannot create /proc/%s",
|
||||
proc_info_root_name);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int reiserfs_proc_info_global_done( void )
|
||||
int reiserfs_proc_info_global_done(void)
|
||||
{
|
||||
if ( proc_info_root != NULL ) {
|
||||
if (proc_info_root != NULL) {
|
||||
proc_info_root = NULL;
|
||||
remove_proc_entry(proc_info_root_name, NULL);
|
||||
}
|
||||
|
|
@ -616,22 +577,40 @@ int reiserfs_proc_info_global_done( void )
|
|||
/* 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; }
|
||||
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; }
|
||||
struct proc_dir_entry *reiserfs_proc_register_global(char *name,
|
||||
read_proc_t * func)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void reiserfs_proc_unregister_global( const char *name ) {;}
|
||||
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_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; }
|
||||
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
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Written by Alexander Zarochentcev.
|
||||
*
|
||||
|
|
@ -17,23 +17,23 @@
|
|||
#include <linux/reiserfs_fs_sb.h>
|
||||
#include <linux/buffer_head.h>
|
||||
|
||||
int reiserfs_resize (struct super_block * s, unsigned long block_count_new)
|
||||
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;
|
||||
int err = 0;
|
||||
struct reiserfs_super_block *sb;
|
||||
struct reiserfs_bitmap_info *bitmap;
|
||||
struct reiserfs_bitmap_info *old_bitmap = SB_AP_BITMAP(s);
|
||||
struct buffer_head * bh;
|
||||
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 *jb;
|
||||
struct reiserfs_list_bitmap jbitmap[JOURNAL_NUM_BITMAPS];
|
||||
|
||||
|
||||
unsigned long int block_count, free_blocks;
|
||||
int i;
|
||||
int copy_size ;
|
||||
int copy_size;
|
||||
|
||||
sb = SB_DISK_SUPER_BLOCK(s);
|
||||
|
||||
|
|
@ -47,136 +47,145 @@ int reiserfs_resize (struct super_block * s, unsigned long block_count_new)
|
|||
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");
|
||||
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;
|
||||
|
||||
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 );
|
||||
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)
|
||||
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);
|
||||
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) ;
|
||||
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];
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* 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++) {
|
||||
bitmap[i].bh = sb_getblk(s, i * s->s_blocksize * 8);
|
||||
memset(bitmap[i].bh->b_data, 0, sb_blocksize(sb));
|
||||
reiserfs_test_and_set_le_bit(0, bitmap[i].bh->b_data);
|
||||
/* 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];
|
||||
|
||||
set_buffer_uptodate(bitmap[i].bh);
|
||||
mark_buffer_dirty(bitmap[i].bh) ;
|
||||
sync_dirty_buffer(bitmap[i].bh);
|
||||
// update bitmap_info stuff
|
||||
bitmap[i].first_zero_hint=1;
|
||||
bitmap[i].free_count = sb_blocksize(sb) * 8 - 1;
|
||||
}
|
||||
/* free old bitmap blocks array */
|
||||
SB_AP_BITMAP(s) = bitmap;
|
||||
vfree (old_bitmap);
|
||||
/* 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++) {
|
||||
bitmap[i].bh = sb_getblk(s, i * s->s_blocksize * 8);
|
||||
memset(bitmap[i].bh->b_data, 0, sb_blocksize(sb));
|
||||
reiserfs_test_and_set_le_bit(0, bitmap[i].bh->b_data);
|
||||
|
||||
set_buffer_uptodate(bitmap[i].bh);
|
||||
mark_buffer_dirty(bitmap[i].bh);
|
||||
sync_dirty_buffer(bitmap[i].bh);
|
||||
// update bitmap_info stuff
|
||||
bitmap[i].first_zero_hint = 1;
|
||||
bitmap[i].free_count = sb_blocksize(sb) * 8 - 1;
|
||||
}
|
||||
/* 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;
|
||||
return err;
|
||||
|
||||
/* correct last bitmap blocks in old and new disk layout */
|
||||
reiserfs_prepare_for_journal(s, SB_AP_BITMAP(s)[bmap_nr - 1].bh, 1);
|
||||
for (i = block_r; i < s->s_blocksize * 8; i++)
|
||||
reiserfs_test_and_clear_le_bit(i,
|
||||
SB_AP_BITMAP(s)[bmap_nr - 1].bh->b_data);
|
||||
reiserfs_test_and_clear_le_bit(i,
|
||||
SB_AP_BITMAP(s)[bmap_nr -
|
||||
1].bh->b_data);
|
||||
SB_AP_BITMAP(s)[bmap_nr - 1].free_count += s->s_blocksize * 8 - block_r;
|
||||
if ( !SB_AP_BITMAP(s)[bmap_nr - 1].first_zero_hint)
|
||||
SB_AP_BITMAP(s)[bmap_nr - 1].first_zero_hint = block_r;
|
||||
if (!SB_AP_BITMAP(s)[bmap_nr - 1].first_zero_hint)
|
||||
SB_AP_BITMAP(s)[bmap_nr - 1].first_zero_hint = block_r;
|
||||
|
||||
journal_mark_dirty(&th, s, SB_AP_BITMAP(s)[bmap_nr - 1].bh);
|
||||
|
||||
reiserfs_prepare_for_journal(s, SB_AP_BITMAP(s)[bmap_nr_new - 1].bh, 1);
|
||||
for (i = block_r_new; i < s->s_blocksize * 8; i++)
|
||||
reiserfs_test_and_set_le_bit(i,
|
||||
SB_AP_BITMAP(s)[bmap_nr_new - 1].bh->b_data);
|
||||
reiserfs_test_and_set_le_bit(i,
|
||||
SB_AP_BITMAP(s)[bmap_nr_new -
|
||||
1].bh->b_data);
|
||||
journal_mark_dirty(&th, s, SB_AP_BITMAP(s)[bmap_nr_new - 1].bh);
|
||||
|
||||
SB_AP_BITMAP(s)[bmap_nr_new - 1].free_count -= s->s_blocksize * 8 - block_r_new;
|
||||
|
||||
SB_AP_BITMAP(s)[bmap_nr_new - 1].free_count -=
|
||||
s->s_blocksize * 8 - block_r_new;
|
||||
/* Extreme case where last bitmap is the only valid block in itself. */
|
||||
if ( !SB_AP_BITMAP(s)[bmap_nr_new - 1].free_count )
|
||||
SB_AP_BITMAP(s)[bmap_nr_new - 1].first_zero_hint = 0;
|
||||
/* update super */
|
||||
reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ;
|
||||
if (!SB_AP_BITMAP(s)[bmap_nr_new - 1].free_count)
|
||||
SB_AP_BITMAP(s)[bmap_nr_new - 1].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_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);
|
||||
}
|
||||
|
|
|
|||
3255
fs/reiserfs/stree.c
3255
fs/reiserfs/stree.c
File diff suppressed because it is too large
Load diff
3487
fs/reiserfs/super.c
3487
fs/reiserfs/super.c
File diff suppressed because it is too large
Load diff
|
|
@ -11,156 +11,159 @@
|
|||
/* 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 path * path, struct buffer_head * unbh,
|
||||
loff_t tail_offset)
|
||||
int direct2indirect(struct reiserfs_transaction_handle *th, struct inode *inode,
|
||||
struct path *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. */
|
||||
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);
|
||||
BUG_ON(!th->t_trans_id);
|
||||
|
||||
REISERFS_SB(sb)->s_direct2indirect ++;
|
||||
REISERFS_SB(sb)->s_direct2indirect++;
|
||||
|
||||
n_blk_size = sb->s_blocksize;
|
||||
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);
|
||||
/* 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);
|
||||
/* 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 ;
|
||||
// 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;
|
||||
}
|
||||
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;
|
||||
p_le_ih = PATH_PITEM_HEAD(path);
|
||||
|
||||
}
|
||||
/* 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);
|
||||
}
|
||||
unfm_ptr = cpu_to_le32(unbh->b_blocknr);
|
||||
|
||||
REISERFS_I(inode)->i_first_direct_byte = U32_MAX;
|
||||
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.
|
||||
|
||||
return 0;
|
||||
/* 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) ;
|
||||
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),
|
||||
|
|
@ -169,108 +172,108 @@ void reiserfs_unmap_buffer(struct buffer_head *bh) {
|
|||
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 path * 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)
|
||||
int indirect2direct(struct reiserfs_transaction_handle *th, struct inode *p_s_inode, struct page *page, struct path *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;
|
||||
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);
|
||||
BUG_ON(!th->t_trans_id);
|
||||
|
||||
REISERFS_SB(p_s_sb)->s_indirect2direct ++;
|
||||
REISERFS_SB(p_s_sb)->s_indirect2direct++;
|
||||
|
||||
*p_c_mode = M_SKIP_BALANCING;
|
||||
*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_sem. 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);
|
||||
/* 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_sem. 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");
|
||||
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 */ );
|
||||
|
||||
/* 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));
|
||||
|
||||
/* 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)++;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
1971
fs/reiserfs/xattr.c
1971
fs/reiserfs/xattr.c
File diff suppressed because it is too large
Load diff
|
|
@ -9,7 +9,8 @@
|
|||
#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 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)
|
||||
|
|
@ -34,14 +35,13 @@ xattr_set_acl(struct inode *inode, int type, const void *value, size_t size)
|
|||
} else
|
||||
acl = NULL;
|
||||
|
||||
error = reiserfs_set_acl (inode, type, acl);
|
||||
error = reiserfs_set_acl(inode, type, acl);
|
||||
|
||||
release_and_out:
|
||||
release_and_out:
|
||||
posix_acl_release(acl);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
xattr_get_acl(struct inode *inode, int type, void *buffer, size_t size)
|
||||
{
|
||||
|
|
@ -51,7 +51,7 @@ xattr_get_acl(struct inode *inode, int type, void *buffer, size_t size)
|
|||
if (!reiserfs_posixacl(inode->i_sb))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
acl = reiserfs_get_acl (inode, type);
|
||||
acl = reiserfs_get_acl(inode, type);
|
||||
if (IS_ERR(acl))
|
||||
return PTR_ERR(acl);
|
||||
if (acl == NULL)
|
||||
|
|
@ -62,12 +62,10 @@ xattr_get_acl(struct inode *inode, int type, void *buffer, size_t size)
|
|||
return error;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Convert from filesystem to in-memory representation.
|
||||
*/
|
||||
static struct posix_acl *
|
||||
posix_acl_from_disk(const void *value, size_t size)
|
||||
static struct posix_acl *posix_acl_from_disk(const void *value, size_t size)
|
||||
{
|
||||
const char *end = (char *)value + size;
|
||||
int n, count;
|
||||
|
|
@ -76,8 +74,8 @@ posix_acl_from_disk(const void *value, size_t size)
|
|||
if (!value)
|
||||
return NULL;
|
||||
if (size < sizeof(reiserfs_acl_header))
|
||||
return ERR_PTR(-EINVAL);
|
||||
if (((reiserfs_acl_header *)value)->a_version !=
|
||||
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);
|
||||
|
|
@ -89,41 +87,39 @@ posix_acl_from_disk(const void *value, size_t size)
|
|||
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;
|
||||
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_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;
|
||||
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:
|
||||
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:
|
||||
fail:
|
||||
posix_acl_release(acl);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
|
@ -131,46 +127,46 @@ fail:
|
|||
/*
|
||||
* Convert from in-memory to filesystem representation.
|
||||
*/
|
||||
static void *
|
||||
posix_acl_to_disk(const struct posix_acl *acl, size_t *size)
|
||||
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 = (reiserfs_acl_header *)kmalloc(sizeof(reiserfs_acl_header) +
|
||||
acl->a_count * sizeof(reiserfs_acl_entry), GFP_NOFS);
|
||||
ext_acl = (reiserfs_acl_header *) 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);
|
||||
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;
|
||||
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;
|
||||
case ACL_USER_OBJ:
|
||||
case ACL_GROUP_OBJ:
|
||||
case ACL_MASK:
|
||||
case ACL_OTHER:
|
||||
e += sizeof(reiserfs_acl_entry_short);
|
||||
break;
|
||||
|
||||
default:
|
||||
goto fail;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
return (char *)ext_acl;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
kfree(ext_acl);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
|
@ -181,59 +177,58 @@ fail:
|
|||
* inode->i_sem: down
|
||||
* BKL held [before 2.5.x]
|
||||
*/
|
||||
struct posix_acl *
|
||||
reiserfs_get_acl(struct inode *inode, int type)
|
||||
struct posix_acl *reiserfs_get_acl(struct inode *inode, int type)
|
||||
{
|
||||
char *name, *value;
|
||||
struct posix_acl *acl, **p_acl;
|
||||
size_t size;
|
||||
int retval;
|
||||
struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode);
|
||||
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);
|
||||
}
|
||||
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);
|
||||
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 ((int)size < 0) {
|
||||
if (size == -ENODATA || size == -ENOSYS) {
|
||||
*p_acl = ERR_PTR (-ENODATA);
|
||||
return NULL;
|
||||
}
|
||||
return ERR_PTR (size);
|
||||
}
|
||||
size = reiserfs_xattr_get(inode, name, NULL, 0);
|
||||
if ((int)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);
|
||||
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) {
|
||||
*p_acl = ERR_PTR(-ENODATA);
|
||||
} else if (retval < 0) {
|
||||
acl = ERR_PTR(retval);
|
||||
} else {
|
||||
acl = posix_acl_from_disk(value, retval);
|
||||
*p_acl = posix_acl_dup (acl);
|
||||
}
|
||||
*p_acl = posix_acl_dup(acl);
|
||||
}
|
||||
|
||||
kfree(value);
|
||||
return acl;
|
||||
|
|
@ -248,72 +243,72 @@ reiserfs_get_acl(struct inode *inode, int type)
|
|||
static int
|
||||
reiserfs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
|
||||
{
|
||||
char *name;
|
||||
char *name;
|
||||
void *value = NULL;
|
||||
struct posix_acl **p_acl;
|
||||
size_t size;
|
||||
int error;
|
||||
struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode);
|
||||
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;
|
||||
}
|
||||
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);
|
||||
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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (value)
|
||||
kfree(value);
|
||||
|
||||
if (!error) {
|
||||
/* Release the old one */
|
||||
if (!IS_ERR (*p_acl) && *p_acl)
|
||||
posix_acl_release (*p_acl);
|
||||
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);
|
||||
}
|
||||
if (acl == NULL)
|
||||
*p_acl = ERR_PTR(-ENODATA);
|
||||
else
|
||||
*p_acl = posix_acl_dup(acl);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
|
@ -321,192 +316,190 @@ reiserfs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
|
|||
/* dir->i_sem: down,
|
||||
* inode is new and not released into the wild yet */
|
||||
int
|
||||
reiserfs_inherit_default_acl (struct inode *dir, struct dentry *dentry, struct inode *inode)
|
||||
reiserfs_inherit_default_acl(struct inode *dir, struct dentry *dentry,
|
||||
struct inode *inode)
|
||||
{
|
||||
struct posix_acl *acl;
|
||||
int err = 0;
|
||||
struct posix_acl *acl;
|
||||
int err = 0;
|
||||
|
||||
/* ACLs only get applied to files and directories */
|
||||
if (S_ISLNK (inode->i_mode))
|
||||
return 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;
|
||||
/* 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;
|
||||
}
|
||||
/* 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);
|
||||
}
|
||||
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;
|
||||
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;
|
||||
}
|
||||
/* 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;
|
||||
}
|
||||
/* 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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
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 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 ? 1 : 0;
|
||||
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;
|
||||
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 ? 1 : 0;
|
||||
posix_acl_release(acl);
|
||||
}
|
||||
|
||||
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;
|
||||
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)
|
||||
void *buffer, size_t size)
|
||||
{
|
||||
if (strlen(name) != sizeof(POSIX_ACL_XATTR_ACCESS)-1)
|
||||
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)
|
||||
const void *value, size_t size, int flags)
|
||||
{
|
||||
if (strlen(name) != sizeof(POSIX_ACL_XATTR_ACCESS)-1)
|
||||
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)
|
||||
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);
|
||||
}
|
||||
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;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
posix_acl_access_list (struct inode *inode, const char *name, int namelen, char *out)
|
||||
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);
|
||||
int len = namelen;
|
||||
if (!reiserfs_posixacl(inode->i_sb))
|
||||
return 0;
|
||||
if (out)
|
||||
memcpy(out, name, len);
|
||||
|
||||
return len;
|
||||
return len;
|
||||
}
|
||||
|
||||
struct reiserfs_xattr_handler posix_acl_access_handler = {
|
||||
|
|
@ -518,48 +511,48 @@ struct reiserfs_xattr_handler posix_acl_access_handler = {
|
|||
};
|
||||
|
||||
static int
|
||||
posix_acl_default_get (struct inode *inode, const char *name,
|
||||
void *buffer, size_t size)
|
||||
posix_acl_default_get(struct inode *inode, const char *name,
|
||||
void *buffer, size_t size)
|
||||
{
|
||||
if (strlen(name) != sizeof(POSIX_ACL_XATTR_DEFAULT)-1)
|
||||
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)
|
||||
const void *value, size_t size, int flags)
|
||||
{
|
||||
if (strlen(name) != sizeof(POSIX_ACL_XATTR_DEFAULT)-1)
|
||||
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)
|
||||
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);
|
||||
}
|
||||
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;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
posix_acl_default_list (struct inode *inode, const char *name, int namelen, char *out)
|
||||
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);
|
||||
int len = namelen;
|
||||
if (!reiserfs_posixacl(inode->i_sb))
|
||||
return 0;
|
||||
if (out)
|
||||
memcpy(out, name, len);
|
||||
|
||||
return len;
|
||||
return len;
|
||||
}
|
||||
|
||||
struct reiserfs_xattr_handler posix_acl_default_handler = {
|
||||
|
|
|
|||
|
|
@ -9,57 +9,55 @@
|
|||
#define XATTR_SECURITY_PREFIX "security."
|
||||
|
||||
static int
|
||||
security_get (struct inode *inode, const char *name, void *buffer, size_t size)
|
||||
security_get(struct inode *inode, const char *name, void *buffer, size_t size)
|
||||
{
|
||||
if (strlen(name) < sizeof(XATTR_SECURITY_PREFIX))
|
||||
return -EINVAL;
|
||||
if (strlen(name) < sizeof(XATTR_SECURITY_PREFIX))
|
||||
return -EINVAL;
|
||||
|
||||
if (is_reiserfs_priv_object(inode))
|
||||
return -EPERM;
|
||||
if (is_reiserfs_priv_object(inode))
|
||||
return -EPERM;
|
||||
|
||||
return reiserfs_xattr_get (inode, name, buffer, size);
|
||||
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)
|
||||
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 (strlen(name) < sizeof(XATTR_SECURITY_PREFIX))
|
||||
return -EINVAL;
|
||||
|
||||
if (is_reiserfs_priv_object(inode))
|
||||
return -EPERM;
|
||||
if (is_reiserfs_priv_object(inode))
|
||||
return -EPERM;
|
||||
|
||||
return reiserfs_xattr_set (inode, name, buffer, size, flags);
|
||||
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_del (struct inode *inode, const char *name)
|
||||
security_list(struct inode *inode, const char *name, int namelen, char *out)
|
||||
{
|
||||
if (strlen(name) < sizeof(XATTR_SECURITY_PREFIX))
|
||||
return -EINVAL;
|
||||
int len = namelen;
|
||||
|
||||
if (is_reiserfs_priv_object(inode))
|
||||
return -EPERM;
|
||||
if (is_reiserfs_priv_object(inode))
|
||||
return 0;
|
||||
|
||||
return 0;
|
||||
if (out)
|
||||
memcpy(out, name, len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -9,69 +9,67 @@
|
|||
#define XATTR_TRUSTED_PREFIX "trusted."
|
||||
|
||||
static int
|
||||
trusted_get (struct inode *inode, const char *name, void *buffer, size_t size)
|
||||
trusted_get(struct inode *inode, const char *name, void *buffer, size_t size)
|
||||
{
|
||||
if (strlen(name) < sizeof(XATTR_TRUSTED_PREFIX))
|
||||
return -EINVAL;
|
||||
if (strlen(name) < sizeof(XATTR_TRUSTED_PREFIX))
|
||||
return -EINVAL;
|
||||
|
||||
if (!reiserfs_xattrs (inode->i_sb))
|
||||
return -EOPNOTSUPP;
|
||||
if (!reiserfs_xattrs(inode->i_sb))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!(capable(CAP_SYS_ADMIN) || is_reiserfs_priv_object(inode)))
|
||||
return -EPERM;
|
||||
if (!(capable(CAP_SYS_ADMIN) || is_reiserfs_priv_object(inode)))
|
||||
return -EPERM;
|
||||
|
||||
return reiserfs_xattr_get (inode, name, buffer, size);
|
||||
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)
|
||||
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 (strlen(name) < sizeof(XATTR_TRUSTED_PREFIX))
|
||||
return -EINVAL;
|
||||
|
||||
if (!reiserfs_xattrs (inode->i_sb))
|
||||
return -EOPNOTSUPP;
|
||||
if (!reiserfs_xattrs(inode->i_sb))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!(capable(CAP_SYS_ADMIN) || is_reiserfs_priv_object(inode)))
|
||||
return -EPERM;
|
||||
if (!(capable(CAP_SYS_ADMIN) || is_reiserfs_priv_object(inode)))
|
||||
return -EPERM;
|
||||
|
||||
return reiserfs_xattr_set (inode, name, buffer, size, flags);
|
||||
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_del (struct inode *inode, const char *name)
|
||||
trusted_list(struct inode *inode, const char *name, int namelen, char *out)
|
||||
{
|
||||
if (strlen(name) < sizeof(XATTR_TRUSTED_PREFIX))
|
||||
return -EINVAL;
|
||||
int len = namelen;
|
||||
|
||||
if (!reiserfs_xattrs (inode->i_sb))
|
||||
return -EOPNOTSUPP;
|
||||
if (!reiserfs_xattrs(inode->i_sb))
|
||||
return 0;
|
||||
|
||||
if (!(capable(CAP_SYS_ADMIN) || is_reiserfs_priv_object(inode)))
|
||||
return -EPERM;
|
||||
if (!(capable(CAP_SYS_ADMIN) || is_reiserfs_priv_object(inode)))
|
||||
return 0;
|
||||
|
||||
return 0;
|
||||
if (out)
|
||||
memcpy(out, name, len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -13,81 +13,80 @@
|
|||
#define XATTR_USER_PREFIX "user."
|
||||
|
||||
static int
|
||||
user_get (struct inode *inode, const char *name, void *buffer, size_t size)
|
||||
user_get(struct inode *inode, const char *name, void *buffer, size_t size)
|
||||
{
|
||||
|
||||
int error;
|
||||
int error;
|
||||
|
||||
if (strlen(name) < sizeof(XATTR_USER_PREFIX))
|
||||
return -EINVAL;
|
||||
if (strlen(name) < sizeof(XATTR_USER_PREFIX))
|
||||
return -EINVAL;
|
||||
|
||||
if (!reiserfs_xattrs_user (inode->i_sb))
|
||||
return -EOPNOTSUPP;
|
||||
if (!reiserfs_xattrs_user(inode->i_sb))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
error = reiserfs_permission_locked (inode, MAY_READ, NULL);
|
||||
if (error)
|
||||
return error;
|
||||
error = reiserfs_permission_locked(inode, MAY_READ, NULL);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
return reiserfs_xattr_get (inode, name, buffer, size);
|
||||
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)
|
||||
user_set(struct inode *inode, const char *name, const void *buffer,
|
||||
size_t size, int flags)
|
||||
{
|
||||
|
||||
int error;
|
||||
int error;
|
||||
|
||||
if (strlen(name) < sizeof(XATTR_USER_PREFIX))
|
||||
return -EINVAL;
|
||||
if (strlen(name) < sizeof(XATTR_USER_PREFIX))
|
||||
return -EINVAL;
|
||||
|
||||
if (!reiserfs_xattrs_user (inode->i_sb))
|
||||
return -EOPNOTSUPP;
|
||||
if (!reiserfs_xattrs_user(inode->i_sb))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!S_ISREG (inode->i_mode) &&
|
||||
(!S_ISDIR (inode->i_mode) || inode->i_mode & S_ISVTX))
|
||||
return -EPERM;
|
||||
if (!S_ISREG(inode->i_mode) &&
|
||||
(!S_ISDIR(inode->i_mode) || inode->i_mode & S_ISVTX))
|
||||
return -EPERM;
|
||||
|
||||
error = reiserfs_permission_locked (inode, MAY_WRITE, NULL);
|
||||
if (error)
|
||||
return error;
|
||||
error = reiserfs_permission_locked(inode, MAY_WRITE, NULL);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
return reiserfs_xattr_set (inode, name, buffer, size, flags);
|
||||
return reiserfs_xattr_set(inode, name, buffer, size, flags);
|
||||
}
|
||||
|
||||
static int user_del(struct inode *inode, const char *name)
|
||||
{
|
||||
int error;
|
||||
|
||||
if (strlen(name) < sizeof(XATTR_USER_PREFIX))
|
||||
return -EINVAL;
|
||||
|
||||
if (!reiserfs_xattrs_user(inode->i_sb))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!S_ISREG(inode->i_mode) &&
|
||||
(!S_ISDIR(inode->i_mode) || inode->i_mode & S_ISVTX))
|
||||
return -EPERM;
|
||||
|
||||
error = reiserfs_permission_locked(inode, MAY_WRITE, NULL);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
user_del (struct inode *inode, const char *name)
|
||||
user_list(struct inode *inode, const char *name, int namelen, char *out)
|
||||
{
|
||||
int error;
|
||||
int len = namelen;
|
||||
if (!reiserfs_xattrs_user(inode->i_sb))
|
||||
return 0;
|
||||
|
||||
if (strlen(name) < sizeof(XATTR_USER_PREFIX))
|
||||
return -EINVAL;
|
||||
if (out)
|
||||
memcpy(out, name, len);
|
||||
|
||||
if (!reiserfs_xattrs_user (inode->i_sb))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!S_ISREG (inode->i_mode) &&
|
||||
(!S_ISDIR (inode->i_mode) || inode->i_mode & S_ISVTX))
|
||||
return -EPERM;
|
||||
|
||||
error = reiserfs_permission_locked (inode, MAY_WRITE, NULL);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
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;
|
||||
return len;
|
||||
}
|
||||
|
||||
struct reiserfs_xattr_handler user_handler = {
|
||||
|
|
|
|||
|
|
@ -840,7 +840,6 @@ do_kern_mount(const char *fstype, int flags, const char *name, void *data)
|
|||
mnt->mnt_root = dget(sb->s_root);
|
||||
mnt->mnt_mountpoint = sb->s_root;
|
||||
mnt->mnt_parent = mnt;
|
||||
mnt->mnt_namespace = current->namespace;
|
||||
up_write(&sb->s_umount);
|
||||
free_secdata(secdata);
|
||||
put_filesystem(type);
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/dnotify.h>
|
||||
#include <linux/fsnotify.h>
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/namei.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
|
@ -391,9 +391,6 @@ int sysfs_create_file(struct kobject * kobj, const struct attribute * attr)
|
|||
* sysfs_update_file - update the modified timestamp on an object attribute.
|
||||
* @kobj: object we're acting for.
|
||||
* @attr: attribute descriptor.
|
||||
*
|
||||
* Also call dnotify for the dentry, which lots of userspace programs
|
||||
* use.
|
||||
*/
|
||||
int sysfs_update_file(struct kobject * kobj, const struct attribute * attr)
|
||||
{
|
||||
|
|
@ -408,7 +405,7 @@ int sysfs_update_file(struct kobject * kobj, const struct attribute * attr)
|
|||
if (victim->d_inode &&
|
||||
(victim->d_parent->d_inode == dir->d_inode)) {
|
||||
victim->d_inode->i_mtime = CURRENT_TIME;
|
||||
dnotify_parent(victim, DN_MODIFY);
|
||||
fsnotify_modify(victim);
|
||||
|
||||
/**
|
||||
* Drop reference from initial sysfs_get_dentry().
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
#include <linux/security.h>
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/fsnotify.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
/*
|
||||
|
|
@ -57,8 +58,10 @@ setxattr(struct dentry *d, char __user *name, void __user *value,
|
|||
if (error)
|
||||
goto out;
|
||||
error = d->d_inode->i_op->setxattr(d, kname, kvalue, size, flags);
|
||||
if (!error)
|
||||
if (!error) {
|
||||
fsnotify_xattr(d);
|
||||
security_inode_post_setxattr(d, kname, kvalue, size, flags);
|
||||
}
|
||||
out:
|
||||
up(&d->d_inode->i_sem);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue