error = -ENOMEM;
if (!clone)
goto cleanup;
-
+
mode = inode->i_mode;
error = posix_acl_create_masq(clone, &mode);
if (error >= 0) {
return NULL;
}
-
+
group_desc = block_group / EXT3_DESC_PER_BLOCK(sb);
desc = block_group % EXT3_DESC_PER_BLOCK(sb);
if (!EXT3_SB(sb)->s_group_desc[group_desc]) {
block_group, group_desc, desc);
return NULL;
}
-
+
gdp = (struct ext3_group_desc *)
EXT3_SB(sb)->s_group_desc[group_desc]->b_data;
if (bh)
{
struct ext3_group_desc * desc;
struct buffer_head * bh = NULL;
-
+
desc = ext3_get_group_desc (sb, block_group, NULL);
if (!desc)
goto error_out;
err = ext3_journal_get_undo_access(handle, bitmap_bh, NULL);
if (err)
goto error_return;
-
+
/*
* We are about to modify some metadata. Call the journal APIs
* to unshare ->b_data if a currently-committing transaction is
* using it
*/
BUFFER_TRACE(gd_bh, "get_write_access");
- err = ext3_journal_get_write_access(handle, gd_bh);
+ err = ext3_journal_get_write_access(handle, gd_bh);
if (err)
goto error_return;
jbd_lock_bh_state(bitmap_bh);
-
+
for (i = 0; i < count; i++) {
/*
* An HJ special. This is expensive...
{
int here, next;
char *p, *r;
-
+
if (start > 0) {
/*
* The goal was occupied; search forward for a free
if (here < end_goal &&
ext3_test_allocatable(here, bh, have_access))
return here;
-
+
ext3_debug ("Bit not found near goal\n");
-
}
-
+
here = start;
if (here < 0)
here = 0;
-
+
/*
* There has been no free block found in the near vicinity of
* the goal: do a search forward through the block groups,
p = ((char *) bh->b_data) + (here >> 3);
r = memscan(p, 0, (maxblocks - here + 7) >> 3);
next = (r - ((char *) bh->b_data)) << 3;
-
+
if (next < maxblocks && ext3_test_allocatable(next, bh, have_access))
return next;
-
+
/* The bitmap search --- search forward alternately
* through the actual bitmap and the last-committed copy
* until we find a bit free in both. */
EXT3_BLOCKS_PER_GROUP(sb));
bitmap_bh = read_block_bitmap(sb, group_no);
if (!bitmap_bh)
- goto io_error;
+ goto io_error;
ret_block = ext3_try_to_allocate(sb, handle, group_no,
bitmap_bh, ret_block, &fatal);
if (fatal)
if (ret_block >= 0)
goto allocated;
}
-
+
/*
* Now search the rest of the groups. We assume that
* i and gdp correctly point to the last group visited.
*errp = 0;
brelse(bitmap_bh);
return ret_block;
-
+
io_error:
*errp = -EIO;
out:
DQUOT_FREE_BLOCK(inode, 1);
brelse(bitmap_bh);
return 0;
-
}
unsigned long ext3_count_free_blocks(struct super_block *sb)
struct ext3_super_block *es;
unsigned long bitmap_count, x;
struct buffer_head *bitmap_bh = NULL;
-
+
lock_super(sb);
es = EXT3_SB(sb)->s_es;
desc_count = 0;
bitmap_bh = read_block_bitmap(sb, i);
if (bitmap_bh == NULL)
continue;
-
+
x = ext3_count_free(bitmap_bh, sb->s_blocksize);
printk("group %d: stored = %d, counted = %lu\n",
i, le16_to_cpu(gdp->bg_free_blocks_count), x);
{
unsigned int i;
unsigned long sum = 0;
-
+
if (!map)
return (0);
for (i = 0; i < numchars; i++)
brelse (bha[i]);
}
}
-
+
revalidate:
/* If the dir block has changed since the last call to
* readdir(2), then we might be pointing to an invalid
| offset;
filp->f_version = inode->i_version;
}
-
+
while (!error && filp->f_pos < inode->i_size
&& offset < sb->s_blocksize) {
de = (struct ext3_dir_entry_2 *) (bh->b_data + offset);
free_rb_tree_fname(&p->root);
kfree(p);
}
-
+
/*
* Given a directory entry, enter it into the fname rb tree.
*/
new_fn->file_type = dirent->file_type;
memcpy(new_fn->name, dirent->name, dirent->name_len);
new_fn->name[dirent->name_len] = 0;
-
+
while (*p) {
parent = *p;
fname = rb_entry(parent, struct fname, rb_hash);
fname->next = new_fn;
return 0;
}
-
+
if (new_fn->hash < fname->hash)
p = &(*p)->rb_left;
else if (new_fn->hash > fname->hash)
int error;
sb = inode->i_sb;
-
+
if (!fname) {
printk("call_filldir: called with null fname?!?\n");
return 0;
*/
if (ret <= 0)
return ret;
-
+
/*
* If the inode is IS_SYNC, or is O_SYNC and we are doing data
* journalling then we need to make sure that we force the transaction
*/
if (!IS_SYNC(inode))
return ret;
-
+
/*
* Open question #2 --- should we force data to disk here too? If we
* don't, the only impact is that data=writeback filesystems won't
* flush data to disk automatically on IS_SYNC, only metadata (but
* historically, that is what ext2 has done.)
*/
-
+
force_commit:
err = ext3_force_commit(inode->i_sb);
if (err)
__u32 a = in[0], b = in[1], c = in[2], d = in[3];
int n = 16;
- do {
- sum += DELTA;
- b0 += ((b1 << 4)+a) ^ (b1+sum) ^ ((b1 >> 5)+b);
- b1 += ((b0 << 4)+c) ^ (b0+sum) ^ ((b0 >> 5)+d);
+ do {
+ sum += DELTA;
+ b0 += ((b1 << 4)+a) ^ (b1+sum) ^ ((b1 >> 5)+b);
+ b1 += ((b0 << 4)+c) ^ (b0+sum) ^ ((b0 >> 5)+d);
} while(--n);
buf[0] += b0;
__u32 hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9;
while (len--) {
__u32 hash = hash1 + (hash0 ^ (*name++ * 7152373));
-
+
if (hash & 0x80000000) hash -= 0x7fffffff;
hash1 = hash0;
hash0 = hash;
if (i < 4)
memcpy(buf, hinfo->seed, sizeof(buf));
}
-
+
switch (hinfo->hash_version) {
case DX_HASH_LEGACY:
hash = dx_hack_hash(name, len);
for (i = 0; i < sbi->s_groups_count; i++) {
gdp = ext3_get_group_desc(sb, group, &bh2);
-
+
err = -EIO;
brelse(bitmap_bh);
bitmap_bh = read_inode_bitmap(sb, group);
if (!bitmap_bh)
goto fail;
-
+
ino = ext3_find_first_zero_bit((unsigned long *)
bitmap_bh->b_data, EXT3_INODES_PER_GROUP(sb));
if (ino < EXT3_INODES_PER_GROUP(sb)) {
BUFFER_TRACE(bh2, "call ext3_journal_dirty_metadata");
err = ext3_journal_dirty_metadata(handle, bh2);
if (err) goto fail;
-
+
percpu_counter_dec(&sbi->s_freeinodes_counter);
if (S_ISDIR(mode))
percpu_counter_inc(&sbi->s_dirs_counter);
ei->i_prealloc_count = 0;
#endif
ei->i_block_group = group;
-
+
ext3_set_inode_flags(inode);
if (IS_DIRSYNC(inode))
handle->h_sync = 1;
"data mode %lx\n",
bh, is_metadata, inode->i_mode,
test_opt(inode->i_sb, DATA_FLAGS));
-
+
/* Never use the revoke function if we are doing full data
* journaling: there is no need to, and a V1 superblock won't
* support it. Otherwise, only skip the revoke on un-journaled
static unsigned long blocks_for_truncate(struct inode *inode)
{
unsigned long needed;
-
+
needed = inode->i_blocks >> (inode->i_sb->s_blocksize_bits - 9);
/* Give ourselves just enough room to cope with inodes in which
return EXT3_DATA_TRANS_BLOCKS + needed;
}
-
+
/*
* Truncate transactions can be complex and absolutely huge. So we need to
* be able to restart the transaction at a conventient checkpoint to make
static handle_t *start_transaction(struct inode *inode)
{
handle_t *result;
-
+
result = ext3_journal_start(inode, blocks_for_truncate(inode));
if (!IS_ERR(result))
return result;
-
+
ext3_std_error(inode->i_sb, PTR_ERR(result));
return result;
}
void ext3_delete_inode (struct inode * inode)
{
handle_t *handle;
-
+
if (is_bad_inode(inode))
goto no_delete;
ext3_std_error(inode->i_sb, PTR_ERR(handle));
goto no_delete;
}
-
+
if (IS_SYNC(inode))
handle->h_sync = 1;
inode->i_size = 0;
break;
branch[n].key = cpu_to_le32(nr);
keys = n+1;
-
+
/*
* Get buffer_head for parent block, zero it out
* and set the pointer to new one, then send
err = ext3_journal_dirty_metadata(handle, bh);
if (err)
break;
-
+
parent = nr;
}
}
*/
jbd_debug(1, "the chain changed: try again\n");
err = -EAGAIN;
-
+
err_out:
for (i = 1; i < num; i++) {
BUFFER_TRACE(where[i].bh, "call journal_forget");
{
struct buffer_head dummy;
int fatal = 0, err;
-
+
J_ASSERT(handle != NULL || create == 0);
dummy.b_state = 0;
struct inode *inode = mapping->host;
journal_t *journal;
int err;
-
+
if (EXT3_I(inode)->i_state & EXT3_STATE_JDATA) {
/*
* This is a REALLY heavyweight approach, but the use of
* hasn't yet been flushed to disk, they deserve
* everything they get.
*/
-
+
EXT3_I(inode)->i_state &= ~EXT3_STATE_JDATA;
journal = EXT3_JOURNAL(inode);
journal_lock_updates(journal);
err = journal_flush(journal);
journal_unlock_updates(journal);
-
+
if (err)
return 0;
}
-
+
return generic_block_bmap(mapping,block,ext3_get_block);
}
int err;
J_ASSERT(PageLocked(page));
-
+
/*
* We give up here if we're reentered, because it might be for a
* different filesystem.
goto out_fail;
handle = ext3_journal_start(inode, ext3_writepage_trans_blocks(inode));
-
+
if (IS_ERR(handle)) {
ret = PTR_ERR(handle);
goto out_fail;
if (is_handle_aborted(handle))
return;
-
+
if (depth--) {
struct buffer_head *bh;
int addr_per_block = EXT3_ADDR_PER_BLOCK(inode->i_sb);
>> EXT3_BLOCK_SIZE_BITS(inode->i_sb);
ext3_block_truncate_page(handle, inode->i_mapping, inode->i_size);
-
n = ext3_block_to_path(inode, last_block, offsets, NULL);
if (n == 0)
unsigned long desc;
unsigned long offset;
struct ext3_group_desc * gdp;
-
+
if ((inode->i_ino != EXT3_ROOT_INO &&
inode->i_ino != EXT3_JOURNAL_INO &&
inode->i_ino < EXT3_FIRST_INO(inode->i_sb)) ||
iloc->bh = bh;
iloc->raw_inode = (struct ext3_inode *) (bh->b_data + offset);
iloc->block_group = block_group;
-
+
return 0;
-
+
bad_inode:
return -EIO;
}
struct ext3_inode_info *ei = EXT3_I(inode);
struct buffer_head *bh;
int block;
-
+
#ifdef CONFIG_EXT3_FS_POSIX_ACL
ei->i_acl = EXT3_ACL_NOT_CACHED;
ei->i_default_acl = EXT3_ACL_NOT_CACHED;
}
ext3_set_inode_flags(inode);
return;
-
+
bad_inode:
make_bad_inode(inode);
return;
if (!wait)
return;
- ext3_force_commit(inode->i_sb);
+ ext3_force_commit(inode->i_sb);
}
/*
error = PTR_ERR(handle);
goto err_out;
}
-
+
error = ext3_orphan_add(handle, inode);
EXT3_I(inode)->i_disksize = attr->ia_size;
rc = ext3_mark_inode_dirty(handle, inode);
error = rc;
ext3_journal_stop(handle);
}
-
+
rc = inode_setattr(inode, attr);
/* If inode_setattr's call to ext3_truncate failed to get a
int bpp = ext3_journal_blocks_per_page(inode);
int indirects = (EXT3_NDIR_BLOCKS % bpp) ? 5 : 3;
int ret;
-
+
if (ext3_should_journal_data(inode))
ret = 3 * (bpp + indirects) + 2;
else
ext3_pin_inode(handle_t *handle, struct inode *inode)
{
struct ext3_iloc iloc;
-
+
int err = 0;
if (handle) {
err = ext3_get_inode_loc(inode, &iloc);
journal = EXT3_JOURNAL(inode);
if (is_journal_aborted(journal) || IS_RDONLY(inode))
return -EROFS;
-
+
journal_lock_updates(journal);
journal_flush(journal);
handle->h_sync = 1;
ext3_journal_stop(handle);
ext3_std_error(inode->i_sb, err);
-
+
return err;
}
if (!capable(CAP_LINUX_IMMUTABLE))
return -EPERM;
}
-
+
/*
* The JOURNAL_DATA flag can only be changed by
* the relevant capability.
err = ext3_reserve_inode_write(handle, inode, &iloc);
if (err)
goto flags_err;
-
+
flags = flags & EXT3_FL_USER_MODIFIABLE;
flags |= oldflags & ~EXT3_FL_USER_MODIFIABLE;
ei->i_flags = flags;
ext3_journal_stop(handle);
if (err)
return err;
-
+
if ((jflag ^ oldflags) & (EXT3_JOURNAL_DATA_FL))
err = ext3_change_inode_journal_flag(inode, jflag);
return err;
unsigned names = 0, space = 0;
char *base = (char *) de;
struct dx_hash_info h = *hinfo;
-
+
printk("names: ");
while ((char *) de < base + size)
{
dxtrace(printk("In htree dirblock_to_tree: block %d\n", block));
if (!(bh = ext3_bread (NULL, dir, block, 0, &err)))
return err;
-
+
de = (struct ext3_dir_entry_2 *) bh->b_data;
top = (struct ext3_dir_entry_2 *) ((char *) de +
dir->i_sb->s_blocksize -
int count = 0;
int ret;
__u32 hashval;
-
+
dxtrace(printk("In htree_fill_tree, start hash: %x:%x\n", start_hash,
start_minor_hash));
dir = dir_file->f_dentry->d_inode;
- if (!(EXT3_I(dir)->i_flags & EXT3_INDEX_FL)) {
+ if (!(EXT3_I(dir)->i_flags & EXT3_INDEX_FL)) {
hinfo.hash_version = EXT3_SB(dir->i_sb)->s_def_hash_version;
hinfo.seed = EXT3_SB(dir->i_sb)->s_hash_seed;
count = htree_dirblock_to_tree(dir_file, dir, 0, &hinfo,
int count = 0;
char *base = (char *) de;
struct dx_hash_info h = *hinfo;
-
+
while ((char *) de < base + size)
{
if (de->name_len && de->inode) {
* The returned buffer_head has ->b_count elevated. The caller is expected
* to brelse() it when appropriate.
*/
-
-
static struct buffer_head * ext3_find_entry (struct dentry *dentry,
struct ext3_dir_entry_2 ** res_dir)
{
start = 0;
goto restart;
}
-
+
cleanup_and_exit:
/* Clean up the read-ahead blocks */
for (; ra_ptr < ra_max; ra_ptr++)
int namelen = dentry->d_name.len;
const u8 *name = dentry->d_name.name;
struct inode *dir = dentry->d_parent->d_inode;
-
+
sb = dir->i_sb;
if (!(frame = dx_probe (dentry, 0, &hinfo, frames, err)))
return NULL;
goto errout;
}
} while (retval == 1);
-
+
*err = -ENOENT;
errout:
dxtrace(printk("%s not found\n", name));
unsigned short reclen;
int nlen, rlen, err;
char *top;
-
+
reclen = EXT3_DIR_REC_LEN(namelen);
if (!de) {
de = (struct ext3_dir_entry_2 *)bh->b_data;
brelse(bh);
return err;
}
-
+
/* By now the buffer is marked for journaling */
nlen = EXT3_DIR_REC_LEN(de->name_len);
rlen = le16_to_cpu(de->rec_len);
unsigned blocksize;
struct dx_hash_info hinfo;
u32 block;
-
+
blocksize = dir->i_sb->s_blocksize;
dxtrace(printk("Creating index\n"));
retval = ext3_journal_get_write_access(handle, bh);
return retval;
}
root = (struct dx_root *) bh->b_data;
-
+
EXT3_I(dir)->i_flags |= EXT3_INDEX_FL;
bh2 = ext3_append (handle, dir, &block, &retval);
if (!(bh2)) {
unsigned icount1 = icount/2, icount2 = icount - icount1;
unsigned hash2 = dx_get_hash(entries + icount1);
dxtrace(printk("Split index %i/%i\n", icount1, icount2));
-
+
BUFFER_TRACE(frame->bh, "get_write_access"); /* index root */
err = ext3_journal_get_write_access(handle,
frames[0].bh);
if (err)
goto journal_error;
-
+
memcpy ((char *) entries2, (char *) (entries + icount1),
icount2 * sizeof(struct dx_entry));
dx_set_count (entries, icount1);
err = add_dirent_to_buf(handle, dentry, inode, de, bh);
bh = 0;
goto cleanup;
-
+
journal_error:
ext3_std_error(dir->i_sb, err);
cleanup:
struct super_block *sb = inode->i_sb;
struct ext3_iloc iloc;
int err = 0, rc;
-
+
lock_super(sb);
if (!list_empty(&EXT3_I(inode)->i_orphan))
goto out_unlock;
err = ext3_journal_get_write_access(handle, EXT3_SB(sb)->s_sbh);
if (err)
goto out_unlock;
-
+
err = ext3_reserve_inode_write(handle, inode, &iloc);
if (err)
goto out_unlock;
retval = -EIO;
if (le32_to_cpu(de->inode) != inode->i_ino)
goto end_unlink;
-
+
if (!inode->i_nlink) {
ext3_warning (inode->i_sb, "ext3_unlink",
"Deleting nonexistent file (%lu), %d",
*/
struct buffer_head *old_bh2;
struct ext3_dir_entry_2 *old_de2;
-
+
old_bh2 = ext3_find_entry(old_dentry, &old_de2);
if (old_bh2) {
retval = ext3_delete_entry(handle, old_dir,
.mknod = ext3_mknod,
.rename = ext3_rename,
.setattr = ext3_setattr,
- .setxattr = ext3_setxattr,
- .getxattr = ext3_getxattr,
- .listxattr = ext3_listxattr,
+ .setxattr = ext3_setxattr,
+ .getxattr = ext3_getxattr,
+ .listxattr = ext3_listxattr,
.removexattr = ext3_removexattr,
.permission = ext3_permission,
};
handle_t *ext3_journal_start(struct inode *inode, int nblocks)
{
journal_t *journal;
-
+
if (inode->i_sb->s_flags & MS_RDONLY)
return ERR_PTR(-EROFS);
"Detected aborted journal");
return ERR_PTR(-EROFS);
}
-
+
return journal_start(journal, nblocks);
}
{
char nbuf[16];
const char *errstr = ext3_decode_error(NULL, err, nbuf);
-
+
printk(KERN_ERR "%s: aborting transaction: %s in %s",
caller, errstr, err_fn);
const char *ext3_decode_error(struct super_block * sb, int errno, char nbuf[16])
{
char *errstr = NULL;
-
+
switch (errno) {
case -EIO:
errstr = "IO failure";
if (snprintf(nbuf, 16, "error %d", -errno) >= 0)
errstr = nbuf;
}
-
break;
}
printk (KERN_CRIT "EXT3-fs error (device %s) in %s: %s\n",
sb->s_id, function, errstr);
-
+
ext3_handle_error(sb);
}
if (sb->s_flags & MS_RDONLY)
return;
-
+
printk (KERN_CRIT "Remounting filesystem read-only\n");
EXT3_SB(sb)->s_mount_state |= EXT3_ERROR_FS;
sb->s_flags |= MS_RDONLY;
static void dump_orphan_list(struct super_block *sb, struct ext3_sb_info *sbi)
{
struct list_head *l;
-
+
printk(KERN_ERR "sb orphan head is %d\n",
le32_to_cpu(sbi->s_es->s_last_orphan));
-
+
printk(KERN_ERR "sb_info orphan list:\n");
list_for_each(l, &sbi->s_orphan) {
struct inode *inode = orphan_list_entry(l);
struct ext3_sb_info *sbi = EXT3_SB(sb);
unsigned long bg, first_data_block, first_meta_bg;
int has_super = 0;
-
+
first_data_block = le32_to_cpu(sbi->s_es->s_first_data_block);
first_meta_bg = le32_to_cpu(sbi->s_es->s_first_meta_bg);
sb->s_id);
goto failed_mount;
}
-
+
/* Set defaults before we parse the mount options */
def_mount_opts = le32_to_cpu(es->s_default_mount_opts);
if (def_mount_opts & EXT3_DEFM_DEBUG)
set_opt(sbi->s_mount_opt, ERRORS_PANIC);
else if (le16_to_cpu(sbi->s_es->s_errors) == EXT3_ERRORS_RO)
set_opt(sbi->s_mount_opt, ERRORS_RO);
-
+
sbi->s_resuid = le16_to_cpu(es->s_def_resuid);
sbi->s_resgid = le16_to_cpu(es->s_def_resgid);
"EXT3-fs: blocksize too small for journal device.\n");
goto out_bdev;
}
-
+
sb_block = EXT3_MIN_BLOCK_SIZE / blocksize;
offset = EXT3_MIN_BLOCK_SIZE % blocksize;
set_blocksize(bdev, blocksize);
journal_t *journal;
int j_errno;
const char *errstr;
-
+
journal = EXT3_SB(sb)->s_journal;
/*
j_errno = journal_errno(journal);
if (j_errno) {
char nbuf[16];
-
+
errstr = ext3_decode_error(sb, j_errno, nbuf);
ext3_warning(sb, __FUNCTION__, "Filesystem error recorded "
"from previous mount: %s", errstr);
ext3_warning(sb, __FUNCTION__, "Marking fs in need of "
"filesystem check.");
-
+
EXT3_SB(sb)->s_mount_state |= EXT3_ERROR_FS;
es->s_state |= cpu_to_le16(EXT3_ERROR_FS);
ext3_commit_super (sb, es, 1);
es = sbi->s_es;
ext3_init_journal_params(sbi, sbi->s_journal);
-
+
if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY)) {
if (sbi->s_mount_opt & EXT3_MOUNT_ABORT)
return -EROFS;
unsigned int name_len;
int min_offs = sb->s_blocksize, not_found = 1, free, error;
char *end;
-
+
/*
* header -- Points either into bh, or to a temporarily
* allocated buffer.
* towards the end of the block).
* end -- Points right after the block pointed to by header.
*/
-
+
ea_idebug(inode, "name=%d.%s, value=%p, value_len=%ld",
name_index, name, value, (long)value_len);
ea_bdebug(new_bh, "%s block %ld",
(old_bh == new_bh) ? "keeping" : "reusing",
new_bh->b_blocknr);
-
+
error = -EDQUOT;
if (DQUOT_ALLOC_BLOCK(inode, 1))
goto cleanup;
-
+
error = ext3_journal_get_write_access(handle, new_bh);
if (error)
goto cleanup;
set_buffer_uptodate(new_bh);
unlock_buffer(new_bh);
ext3_xattr_cache_insert(new_bh);
-
+
ext3_xattr_update_super_block(handle, sb);
}
error = ext3_journal_dirty_metadata(handle, new_bh);
{
struct ext3_xattr_entry *here;
__u32 hash = 0;
-
+
ext3_xattr_hash_entry(header, entry);
here = ENTRY(header+1);
while (!IS_LAST_ENTRY(here)) {
init_ext3_xattr(void)
{
int err;
-
+
err = ext3_xattr_register(EXT3_XATTR_INDEX_USER,
&ext3_xattr_user_handler);
if (err)
return;
spin_unlock(&journal->j_state_lock);
down(&journal->j_checkpoint_sem);
-
+
/*
* Test again, another process may have checkpointed while we
* were waiting for the checkpoint lock
if (buffer_dirty(bh) && !buffer_locked(bh) && jh->b_jlist == BJ_None) {
J_ASSERT_JH(jh, jh->b_transaction == NULL);
-
+
/*
* Important: we are about to write the buffer, and
* possibly block, while still holding the journal lock.
return ret;
}
-
/*
* Perform an actual checkpoint. We don't write out only enough to
* satisfy the current blocked requests: rather we submit a reasonably
result = cleanup_journal_tail(journal);
if (result < 0)
return result;
-
+
return 0;
}
journal_t *journal;
JBUFFER_TRACE(jh, "entry");
-
+
if ((transaction = jh->b_cp_transaction) == NULL) {
JBUFFER_TRACE(jh, "not on transaction");
goto out;
commit_transaction->t_log_start = journal->j_head;
wake_up(&journal->j_wait_transaction_locked);
spin_unlock(&journal->j_state_lock);
-
+
jbd_debug (3, "JBD: commit phase 2\n");
/*
__journal_abort_hard(journal);
continue;
}
-
+
bh = jh2bh(descriptor);
jbd_debug(4, "JBD: got buffer %llu (%p)\n",
(unsigned long long)bh->b_blocknr, bh->b_data);
if (err)
__journal_abort_hard(journal);
-
+
/*
* Call any callbacks that had been registered for handles in this
* transaction. It is up to the callback to free any allocated
clear_buffer_freed(bh);
clear_buffer_jbddirty(bh);
}
-
+
if (buffer_jbddirty(bh)) {
JBUFFER_TRACE(jh, "add to new checkpointing trans");
__journal_insert_checkpoint(jh, commit_transaction);
spin_unlock(&journal->j_state_lock);
refrigerator(PF_IOTHREAD);
spin_lock(&journal->j_state_lock);
- jbd_debug(1, "Resuming kjournald\n");
} else {
/*
* We assume on resume that commits are already there,
int should_sleep = 1;
prepare_to_wait(&journal->j_wait_commit, &wait,
- TASK_INTERRUPTIBLE);
+ TASK_INTERRUPTIBLE);
if (journal->j_commit_sequence != journal->j_commit_request)
should_sleep = 0;
transaction = journal->j_running_transaction;
kfree(journal);
return NULL;
}
-
+
bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize);
J_ASSERT(bh != NULL);
journal->j_sb_buffer = bh;
struct buffer_head *bh;
journal_superblock_t *sb;
int err = -EIO;
-
+
bh = journal->j_sb_buffer;
J_ASSERT(bh != NULL);
sb = journal->j_superblock;
err = -EINVAL;
-
+
if (sb->s_header.h_magic != htonl(JFS_MAGIC_NUMBER) ||
sb->s_blocksize != htonl(journal->j_blocksize)) {
printk(KERN_WARNING "JBD: no valid journal superblock found\n");
unsigned long old_tail;
spin_lock(&journal->j_state_lock);
-
+
/* Force everything buffered to the log... */
if (journal->j_running_transaction) {
transaction = journal->j_running_transaction;
*/
void * __jbd_kmalloc (const char *where, size_t size, int flags, int retry)
{
- return kmalloc(size, flags | (retry ? __GFP_NOFAIL : 0));
+ return kmalloc(size, flags | (retry ? __GFP_NOFAIL : 0));
}
/*
*/
struct recovery_info
{
- tid_t start_transaction;
+ tid_t start_transaction;
tid_t end_transaction;
-
+
int nr_replays;
int nr_revokes;
int nr_revoke_hits;
unsigned int max, nbufs, next;
unsigned long blocknr;
struct buffer_head *bh;
-
+
struct buffer_head * bufs[MAXBUF];
-
+
/* Do up to 128K of readahead */
max = start + (128 * 1024 / journal->j_blocksize);
if (max > journal->j_maxlen)
/* Do the readahead itself. We'll submit MAXBUF buffer_heads at
* a time to the block device IO layer. */
-
+
nbufs = 0;
-
+
for (next = start; next < max; next++) {
err = journal_bmap(journal, next, &blocknr);
ll_rw_block(READ, nbufs, bufs);
err = 0;
-failed:
+failed:
if (nbufs)
journal_brelse_array(bufs, nbufs);
return err;
*bhp = NULL;
J_ASSERT (offset < journal->j_maxlen);
-
+
err = journal_bmap(journal, offset, &blocknr);
if (err) {
journal_superblock_t * sb;
struct recovery_info info;
-
+
memset(&info, 0, sizeof(info));
sb = journal->j_superblock;
-
+
/*
* The journal superblock's s_start field (the current log head)
* is always zero if, and only if, the journal was cleanly
journal->j_transaction_sequence = ntohl(sb->s_sequence) + 1;
return 0;
}
-
err = do_one_pass(journal, &info, PASS_SCAN);
if (!err)
/* Restart the log at the next transaction ID, thus invalidating
* any existing commit records in the log. */
journal->j_transaction_sequence = ++info.end_transaction;
-
+
journal_clear_revoke(journal);
sync_blockdev(journal->j_fs_dev);
return err;
journal_superblock_t * sb;
struct recovery_info info;
-
+
memset (&info, 0, sizeof(info));
sb = journal->j_superblock;
-
+
err = do_one_pass(journal, &info, PASS_SCAN);
if (err) {
#ifdef CONFIG_JBD_DEBUG
int dropped = info.end_transaction - ntohl(sb->s_sequence);
#endif
-
jbd_debug(0,
"JBD: ignoring %d transaction%s from the journal.\n",
dropped, (dropped == 1) ? "" : "s");
}
journal->j_tail = 0;
-
return err;
}
static int do_one_pass(journal_t *journal,
struct recovery_info *info, enum passtype pass)
{
-
unsigned int first_commit_ID, next_commit_ID;
unsigned long next_log_block;
int err, success = 0;
struct buffer_head * bh;
unsigned int sequence;
int blocktype;
-
+
/* Precompute the maximum metadata descriptors in a descriptor block */
int MAX_BLOCKS_PER_DESC;
MAX_BLOCKS_PER_DESC = ((journal->j_blocksize-sizeof(journal_header_t))
journal_block_tag_t * tag;
struct buffer_head * obh;
struct buffer_head * nbh;
-
+
/* If we already know where to stop the log traversal,
* check right now that we haven't gone past the end of
* the log. */
-
+
if (pass != PASS_SCAN)
if (tid_geq(next_commit_ID, info->end_transaction))
break;
/* Skip over each chunk of the transaction looking
* either the next descriptor block or the final commit
* record. */
-
+
jbd_debug(3, "JBD: checking block %ld\n", next_log_block);
err = jread(&bh, journal, next_log_block);
if (err)
next_log_block++;
wrap(journal, next_log_block);
-
+
/* What kind of buffer is it?
*
* If it is a descriptor block, check that it has the
* here. */
tmp = (journal_header_t *)bh->b_data;
-
+
if (tmp->h_magic != htonl(JFS_MAGIC_NUMBER)) {
brelse(bh);
break;
sequence = ntohl(tmp->h_sequence);
jbd_debug(3, "Found magic %d, sequence %d\n",
blocktype, sequence);
-
+
if (sequence != next_commit_ID) {
brelse(bh);
break;
}
-
+
/* OK, we have a valid descriptor block which matches
* all of the sequence number checks. What are we going
* to do with it? That depends on the pass... */
tag = (journal_block_tag_t *) tagp;
flags = ntohl(tag->t_flags);
-
+
io_block = next_log_block++;
wrap(journal, next_log_block);
err = jread(&obh, journal, io_block);
err, io_block);
} else {
unsigned long blocknr;
-
+
J_ASSERT(obh != NULL);
blocknr = ntohl(tag->t_blocknr);
++info->nr_revoke_hits;
goto skip_write;
}
-
+
/* Find a buffer for the new
* data being restored */
nbh = __getblk(journal->j_fs_dev,
brelse(obh);
brelse(nbh);
}
-
+
skip_write:
tagp += sizeof(journal_block_tag_t);
if (!(flags & JFS_FLAG_SAME_UUID))
if (flags & JFS_FLAG_LAST_TAG)
break;
}
-
+
brelse(bh);
continue;
* log. If the latter happened, then we know that the "current"
* transaction marks the end of the valid log.
*/
-
+
if (pass == PASS_SCAN)
info->end_transaction = next_commit_ID;
else {
header = (journal_revoke_header_t *) bh->b_data;
offset = sizeof(journal_revoke_header_t);
max = ntohl(header->r_count);
-
+
while (offset < max) {
unsigned long blocknr;
int err;
-
+
blocknr = ntohl(* ((unsigned int *) (bh->b_data+offset)));
offset += 4;
err = journal_set_revoke(journal, blocknr, sequence);
{
struct list_head hash;
tid_t sequence; /* Used for recovery only */
- unsigned long blocknr;
+ unsigned long blocknr;
};
{
struct jbd_revoke_table_s *table = journal->j_revoke;
int hash_shift = table->hash_shift;
-
+
return ((block << (hash_shift - 6)) ^
(block >> 13) ^
(block << (hash_shift - 12))) & (table->hash_size - 1);
{
struct list_head *hash_list;
struct jbd_revoke_record_s *record;
-
+
hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)];
spin_lock(&journal->j_revoke_lock);
}
record = (struct jbd_revoke_record_s *) record->hash.next;
}
- spin_unlock(&journal->j_revoke_lock);
+ spin_unlock(&journal->j_revoke_lock);
return NULL;
}
return -ENOMEM;
}
return 0;
-}
+}
void journal_destroy_revoke_caches(void)
{
int journal_init_revoke(journal_t *journal, int hash_size)
{
int shift, tmp;
-
+
J_ASSERT (journal->j_revoke_table[0] == NULL);
-
+
shift = 0;
tmp = hash_size;
while((tmp >>= 1UL) != 0UL)
if (!journal->j_revoke_table[0])
return -ENOMEM;
journal->j_revoke = journal->j_revoke_table[0];
-
+
/* Check that the hash_size is a power of two */
J_ASSERT ((hash_size & (hash_size-1)) == 0);
journal->j_revoke = NULL;
return -ENOMEM;
}
-
+
for (tmp = 0; tmp < hash_size; tmp++)
INIT_LIST_HEAD(&journal->j_revoke->hash_table[tmp]);
-
+
journal->j_revoke_table[1] = kmem_cache_alloc(revoke_table_cache, GFP_KERNEL);
if (!journal->j_revoke_table[1]) {
kfree(journal->j_revoke_table[0]->hash_table);
kmem_cache_free(revoke_table_cache, journal->j_revoke_table[0]);
return -ENOMEM;
}
-
+
journal->j_revoke = journal->j_revoke_table[1];
-
+
/* Check that the hash_size is a power of two */
J_ASSERT ((hash_size & (hash_size-1)) == 0);
journal->j_revoke = NULL;
return -ENOMEM;
}
-
+
for (tmp = 0; tmp < hash_size; tmp++)
INIT_LIST_HEAD(&journal->j_revoke->hash_table[tmp]);
struct jbd_revoke_table_s *table;
struct list_head *hash_list;
int i;
-
+
table = journal->j_revoke_table[0];
if (!table)
return;
-
+
for (i=0; i<table->hash_size; i++) {
hash_list = &table->hash_table[i];
J_ASSERT (list_empty(hash_list));
}
-
+
kfree(table->hash_table);
kmem_cache_free(revoke_table_cache, table);
journal->j_revoke = NULL;
table = journal->j_revoke_table[1];
if (!table)
return;
-
+
for (i=0; i<table->hash_size; i++) {
hash_list = &table->hash_table[i];
J_ASSERT (list_empty(hash_list));
}
-
+
kfree(table->hash_table);
kmem_cache_free(revoke_table_cache, table);
journal->j_revoke = NULL;
int need_cancel;
int did_revoke = 0; /* akpm: debug */
struct buffer_head *bh = jh2bh(jh);
-
+
jbd_debug(4, "journal_head %p, cancelling revoke\n", jh);
/* Is the existing Revoke bit valid? If so, we trust it, and
__brelse(bh2);
}
}
-
return did_revoke;
}
journal->j_revoke = journal->j_revoke_table[1];
else
journal->j_revoke = journal->j_revoke_table[0];
-
+
for (i = 0; i < journal->j_revoke->hash_size; i++)
INIT_LIST_HEAD(&journal->j_revoke->hash_table[i]);
}
descriptor = NULL;
offset = 0;
count = 0;
-
+
/* select revoke table for committing transaction */
revoke = journal->j_revoke == journal->j_revoke_table[0] ?
journal->j_revoke_table[1] : journal->j_revoke_table[0];
-
+
for (i = 0; i < revoke->hash_size; i++) {
hash_list = &revoke->hash_table[i];
descriptor = NULL;
}
}
-
+
if (!descriptor) {
descriptor = journal_get_descriptor_buffer(journal);
if (!descriptor)
offset = sizeof(journal_revoke_header_t);
*descriptorp = descriptor;
}
-
+
* ((unsigned int *)(&jh2bh(descriptor)->b_data[offset])) =
htonl(record->blocknr);
offset += 4;
__brelse(jh2bh(descriptor));
return;
}
-
+
header = (journal_revoke_header_t *) jh2bh(descriptor)->b_data;
header->r_count = htonl(offset);
set_bit(BH_JWrite, &jh2bh(descriptor)->b_state);
tid_t sequence)
{
struct jbd_revoke_record_s *record;
-
+
record = find_revoke_record(journal, blocknr);
if (record) {
/* If we have multiple occurrences, only record the
tid_t sequence)
{
struct jbd_revoke_record_s *record;
-
+
record = find_revoke_record(journal, blocknr);
if (!record)
return 0;
struct list_head *hash_list;
struct jbd_revoke_record_s *record;
struct jbd_revoke_table_s *revoke;
-
+
revoke = journal->j_revoke;
-
+
for (i = 0; i < revoke->hash_size; i++) {
hash_list = &revoke->hash_table[i];
while (!list_empty(hash_list)) {
}
}
}
-
/* Set up the commit timer for the new transaction. */
journal->j_commit_timer->expires = transaction->t_expires;
add_timer(journal->j_commit_timer);
-
+
J_ASSERT(journal->j_running_transaction == NULL);
journal->j_running_transaction = transaction;
journal->j_barrier_count == 0);
goto repeat;
}
-
+
if (!journal->j_running_transaction) {
if (!new_transaction) {
spin_unlock(&journal->j_state_lock);
transaction->t_state != T_LOCKED);
goto repeat;
}
-
+
/*
* If there is not enough space left in the log to write all potential
* buffers requested by this operation, we need to stall pending a log
if (journal->j_committing_transaction)
needed += journal->j_committing_transaction->
t_outstanding_credits;
-
+
if (__log_space_left(journal) < needed) {
jbd_debug(2, "Handle %p waiting for checkpoint...\n", handle);
spin_unlock(&transaction->t_handle_lock);
{
handle_t *handle = journal_current_handle();
int err;
-
+
if (!journal)
return ERR_PTR(-EROFS);
spin_lock(&transaction->t_handle_lock);
wanted = transaction->t_outstanding_credits + nblocks;
-
+
if (wanted > journal->j_max_transaction_buffers) {
jbd_debug(3, "denied handle %p %d blocks: "
"transaction too large\n", handle, nblocks);
"insufficient log space\n", handle, nblocks);
goto unlock;
}
-
+
handle->h_buffer_credits += nblocks;
transaction->t_outstanding_credits += nblocks;
result = 0;
* actually doing the restart! */
if (is_handle_aborted(handle))
return 0;
-
+
/*
* First unlink the handle from its current transaction, and start the
* commit on that.
{
struct buffer_head *bh = jh2bh(jh);
int jlist;
-
+
if (buffer_dirty(bh)) {
/* If this buffer is one which might reasonably be dirty
* --- ie. data, or not part of this journal --- then
* move the dirty bit to the journal's own internal
* JBDDirty bit. */
jlist = jh->b_jlist;
-
+
if (jlist == BJ_Metadata || jlist == BJ_Reserved ||
jlist == BJ_Shadow || jlist == BJ_Forget) {
if (test_clear_buffer_dirty(jh2bh(jh))) {
(*credits)++;
goto done_locked;
}
-
+
/* Is there data here we need to preserve? */
if (jh->b_transaction && jh->b_transaction != transaction) {
wait_event(*wqh, (jh->b_jlist != BJ_Shadow));
goto repeat;
}
-
+
/* Only do the copy if the currently-owning transaction
* still needs it. If it is on the Forget list, the
* committing transaction is past that stage. The
JBUFFER_TRACE(jh, "file as BJ_Reserved");
__journal_file_buffer(jh, transaction, BJ_Reserved);
}
-
+
done_locked:
spin_unlock(&journal->j_list_lock);
if (need_copy) {
journal_t *journal = transaction->t_journal;
struct journal_head *jh = journal_add_journal_head(bh);
int err;
-
+
jbd_debug(5, "journal_head %p\n", jh);
err = -EROFS;
if (is_handle_aborted(handle))
goto out;
err = 0;
-
+
JBUFFER_TRACE(jh, "entry");
/*
* The buffer may already belong to this transaction due to pre-zeroing
if (is_handle_aborted(handle))
return 0;
-
+
jh = journal_add_journal_head(bh);
JBUFFER_TRACE(jh, "entry");
JBUFFER_TRACE(jh, "entry");
if (is_handle_aborted(handle))
goto out;
-
+
jbd_lock_bh_state(bh);
/*
set_buffer_jbddirty(bh);
J_ASSERT_JH(jh, jh->b_transaction != NULL);
-
+
/*
* Metadata already on the current transaction list doesn't
* need to be filed. Metadata on another transaction's list must
return;
}
}
-
} else if (jh->b_transaction) {
J_ASSERT_JH(jh, (jh->b_transaction ==
journal->j_committing_transaction));
transaction_t *transaction = handle->h_transaction;
journal_t *journal = transaction->t_journal;
int old_handle_count, err;
-
+
if (!handle)
return 0;
J_ASSERT(transaction->t_updates > 0);
J_ASSERT(journal_current_handle() == handle);
-
+
if (is_handle_aborted(handle))
err = -EIO;
else
err = 0;
-
+
if (--handle->h_ref > 0) {
jbd_debug(4, "h_ref %d -> %d\n", handle->h_ref + 1,
handle->h_ref);
* completes the commit thread, it just doesn't write
* anything to disk. */
tid_t tid = transaction->t_tid;
-
+
spin_unlock(&transaction->t_handle_lock);
jbd_debug(2, "transaction too old, requesting commit for "
"handle %p\n", handle);
list = &transaction->t_reserved_list;
break;
}
-
+
__blist_del_buffer(list, jh);
jh->b_jlist = BJ_None;
if (test_clear_buffer_jbddirty(bh))
JBUFFER_TRACE(jh, "not on any transaction: zap");
goto zap_buffer;
}
-
+
if (!buffer_dirty(bh)) {
/* bdflush has written it. We can drop it now */
goto zap_buffer;
struct buffer_head *head, *bh, *next;
unsigned int curr_off = 0;
int may_free = 1;
-
+
if (!PageLocked(page))
BUG();
if (!page_has_buffers(page))
if (jh->b_transaction && jh->b_jlist == jlist)
return;
-
+
/* The following list of buffer states needs to be consistent
* with __jbd_unexpected_dirty_buffer()'s handling of dirty
* state. */
jh->b_transaction = NULL;
return;
}
-
+
/*
* It has been modified by a later transaction: add it to the new
* transaction's metadata list.
struct posix_acl *i_acl;
struct posix_acl *i_default_acl;
#endif
-
+
struct list_head i_orphan; /* unlinked but open inodes */
/*