#include <linux/config.h>
#include <linux/time.h>
+#include <linux/fs.h>
#include <linux/reiserfs_fs.h>
+#include <linux/reiserfs_acl.h>
+#include <linux/reiserfs_xattr.h>
#include <linux/smp_lock.h>
#include <linux/pagemap.h>
#include <linux/highmem.h>
#include <linux/buffer_head.h>
#include <linux/mpage.h>
#include <linux/writeback.h>
+#include <linux/quotaops.h>
#include <linux/vserver/xid.h>
extern int reiserfs_default_io_size; /* default io size devuned in super.c */
-/* args for the create parameter of reiserfs_get_block */
-#define GET_BLOCK_NO_CREATE 0 /* don't create new blocks or convert tails */
-#define GET_BLOCK_CREATE 1 /* add anything you need to find block */
-#define GET_BLOCK_NO_HOLE 2 /* return -ENOENT for file holes */
-#define GET_BLOCK_READ_DIRECT 4 /* read the tail if indirect item not found */
-#define GET_BLOCK_NO_ISEM 8 /* i_sem is not held, don't preallocate */
-#define GET_BLOCK_NO_DANGLE 16 /* don't leave any transactions running */
-
-static int reiserfs_get_block (struct inode * inode, sector_t block,
- struct buffer_head * bh_result, int create);
static int reiserfs_commit_write(struct file *f, struct page *page,
unsigned from, unsigned to);
+static int reiserfs_prepare_write(struct file *f, struct page *page,
+ unsigned from, unsigned to);
void reiserfs_delete_inode (struct inode * inode)
{
- int jbegin_count = JOURNAL_PER_BALANCE_CNT * 2;
+ /* We need blocks for transaction + (user+group) quota update (possibly delete) */
+ int jbegin_count = JOURNAL_PER_BALANCE_CNT * 2 + 2 * REISERFS_QUOTA_INIT_BLOCKS;
struct reiserfs_transaction_handle th ;
reiserfs_write_lock(inode->i_sb);
if (!(inode->i_state & I_NEW) && INODE_PKEY(inode)->k_objectid != 0) { /* also handles bad_inode case */
down (&inode->i_sem);
- journal_begin(&th, inode->i_sb, jbegin_count) ;
+ reiserfs_delete_xattrs (inode);
+
+ if (journal_begin(&th, inode->i_sb, jbegin_count)) {
+ up (&inode->i_sem);
+ goto out;
+ }
reiserfs_update_inode_transaction(inode) ;
- reiserfs_delete_object (&th, inode);
+ if (reiserfs_delete_object (&th, inode)) {
+ up (&inode->i_sem);
+ goto out;
+ }
- journal_end(&th, inode->i_sb, jbegin_count) ;
+ /* Do quota update inside a transaction for journaled quotas. We must do that
+ * after delete_object so that quota updates go into the same transaction as
+ * stat data deletion */
+ DQUOT_FREE_INODE(inode);
+
+ if (journal_end(&th, inode->i_sb, jbegin_count)) {
+ up (&inode->i_sem);
+ goto out;
+ }
up (&inode->i_sem);
/* all items of file are deleted, so we can remove "save" link */
- remove_save_link (inode, 0/* not truncate */);
+ remove_save_link (inode, 0/* not truncate */); /* we can't do anything
+ * about an error here */
} else {
/* no object items are in the tree */
;
}
+out:
clear_inode (inode); /* note this must go after the journal_end to prevent deadlock */
inode->i_blocks = 0;
reiserfs_write_unlock(inode->i_sb);
return 0;
}
-/*static*/ void restart_transaction(struct reiserfs_transaction_handle *th,
+/*static*/ int restart_transaction(struct reiserfs_transaction_handle *th,
struct inode *inode, struct path *path) {
struct super_block *s = th->t_super ;
int len = th->t_blocks_allocated ;
+ int err;
+
+ BUG_ON (!th->t_trans_id);
+ BUG_ON (!th->t_refcount);
/* we cannot restart while nested */
if (th->t_refcount > 1) {
- return ;
+ return 0 ;
}
pathrelse(path) ;
reiserfs_update_sd(th, inode) ;
- journal_end(th, s, len) ;
- journal_begin(th, s, JOURNAL_PER_BALANCE_CNT * 6) ;
- reiserfs_update_inode_transaction(inode) ;
+ err = journal_end(th, s, len) ;
+ if (!err) {
+ err = journal_begin(th, s, JOURNAL_PER_BALANCE_CNT * 6) ;
+ if (!err)
+ reiserfs_update_inode_transaction(inode) ;
+ }
+ return err;
}
// it is called by get_block when create == 0. Returns block number
// this is called to create file map. So, _get_block_create_0 will not
// read direct item
-int reiserfs_bmap (struct inode * inode, sector_t block,
- struct buffer_head * bh_result, int create)
+static int reiserfs_bmap (struct inode * inode, sector_t block,
+ struct buffer_head * bh_result, int create)
{
if (!file_capable (inode, block))
return -EFBIG;
ret = reiserfs_get_block(inode, iblock, bh_result,
create | GET_BLOCK_NO_DANGLE) ;
+ if (ret)
+ goto out;
/* don't allow direct io onto tail pages */
- if (ret == 0 && buffer_mapped(bh_result) && bh_result->b_blocknr == 0) {
+ if (buffer_mapped(bh_result) && bh_result->b_blocknr == 0) {
/* make sure future calls to the direct io funcs for this offset
** in the file fail by unmapping the buffer
*/
/* Possible unpacked tail. Flush the data before pages have
disappeared */
if (REISERFS_I(inode)->i_flags & i_pack_on_close_mask) {
+ int err;
lock_kernel();
- reiserfs_commit_for_inode(inode);
+ err = reiserfs_commit_for_inode(inode);
REISERFS_I(inode)->i_flags &= ~i_pack_on_close_mask;
unlock_kernel();
+ if (err < 0)
+ ret = err;
}
+out:
return ret ;
}
b_blocknr_t *allocated_block_nr,
struct path * path,
int flags) {
+ BUG_ON (!th->t_trans_id);
#ifdef REISERFS_PREALLOCATE
if (!(flags & GET_BLOCK_NO_ISEM)) {
int reiserfs_get_block (struct inode * inode, sector_t block,
struct buffer_head * bh_result, int create)
{
- int repeat, retval;
+ int repeat, retval = 0;
b_blocknr_t allocated_block_nr = 0;// b_blocknr_t is (unsigned) 32 bit int
INITIALIZE_PATH(path);
int pos_in_item;
struct cpu_key key;
- struct buffer_head * bh, * unbh = 0;
+ struct buffer_head * bh, * unbh = NULL;
struct item_head * ih, tmp_ih;
__u32 * item;
int done;
. 3 balancings in direct->indirect conversion
. 1 block involved into reiserfs_update_sd()
XXX in practically impossible worst case direct2indirect()
- can incur (much) more that 3 balancings. */
- int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 1;
+ can incur (much) more than 3 balancings.
+ quota update for user, group */
+ int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 1 + 2 * REISERFS_QUOTA_TRANS_BLOCKS;
int version;
int dangle = 1;
loff_t new_offset = (((loff_t)block) << inode->i_sb->s_blocksize_bits) + 1 ;
repeat = _allocate_block(th, block, inode, &allocated_block_nr, &path, create);
- if (repeat == NO_DISK_SPACE) {
+ if (repeat == NO_DISK_SPACE || repeat == QUOTA_EXCEEDED) {
/* restart the transaction to give the journal a chance to free
** some blocks. releases the path, so we have to go back to
** research if we succeed on the second try
*/
SB_JOURNAL(inode->i_sb)->j_next_async_flush = 1;
- restart_transaction(th, inode, &path) ;
+ retval = restart_transaction(th, inode, &path) ;
+ if (retval)
+ goto failure;
repeat = _allocate_block(th, block, inode, &allocated_block_nr, NULL, create);
- if (repeat != NO_DISK_SPACE) {
+ if (repeat != NO_DISK_SPACE && repeat != QUOTA_EXCEEDED) {
goto research ;
}
- retval = -ENOSPC;
+ if (repeat == QUOTA_EXCEEDED)
+ retval = -EDQUOT;
+ else
+ retval = -ENOSPC;
goto failure;
}
put_block_num(item, pos_in_item, allocated_block_nr) ;
unfm_ptr = allocated_block_nr;
journal_mark_dirty (th, inode->i_sb, bh);
- inode->i_blocks += (inode->i_sb->s_blocksize / 512) ;
reiserfs_update_sd(th, inode) ;
}
set_block_dev_mapped(bh_result, unfm_ptr, inode);
pathrelse (&path);
+ retval = 0;
if (!dangle && th)
- reiserfs_end_persistent_transaction(th);
+ retval = reiserfs_end_persistent_transaction(th);
reiserfs_write_unlock(inode->i_sb);
** there is no need to make sure the inode is updated with this
** transaction
*/
- return 0;
+ return retval;
}
if (!th) {
set_cpu_key_k_offset (&tmp_key, 1);
PATH_LAST_POSITION(&path) ++;
- retval = reiserfs_insert_item (th, &path, &tmp_key, &tmp_ih, (char *)&unp);
+ retval = reiserfs_insert_item (th, &path, &tmp_key, &tmp_ih, inode, (char *)&unp);
if (retval) {
- reiserfs_free_block (th, allocated_block_nr);
- goto failure; // retval == -ENOSPC or -EIO or -EEXIST
+ reiserfs_free_block (th, inode, allocated_block_nr, 1);
+ goto failure; // retval == -ENOSPC, -EDQUOT or -EIO or -EEXIST
}
- if (unp)
- inode->i_blocks += inode->i_sb->s_blocksize / 512;
//mark_tail_converted (inode);
} else if (is_direct_le_ih (ih)) {
/* direct item has to be converted */
* ugly, but we can only end the transaction if
* we aren't nested
*/
+ BUG_ON (!th->t_refcount);
if (th->t_refcount == 1) {
- reiserfs_end_persistent_transaction(th);
+ retval = reiserfs_end_persistent_transaction(th);
th = NULL;
+ if (retval)
+ goto failure;
}
retval = convert_tail_for_hole(inode, bh_result, tail_offset) ;
if (retval) {
if ( retval != -ENOSPC )
- printk("clm-6004: convert tail failed inode %lu, error %d\n", inode->i_ino, retval) ;
+ reiserfs_warning (inode->i_sb, "clm-6004: convert tail failed inode %lu, error %d", inode->i_ino, retval) ;
if (allocated_block_nr) {
/* the bitmap, the super, and the stat data == 3 */
if (!th)
th = reiserfs_persistent_transaction(inode->i_sb,3);
if (th)
- reiserfs_free_block (th, allocated_block_nr);
+ reiserfs_free_block (th,inode,allocated_block_nr,1);
}
goto failure ;
}
retval = direct2indirect (th, inode, &path, unbh, tail_offset);
if (retval) {
reiserfs_unmap_buffer(unbh);
- reiserfs_free_block (th, allocated_block_nr);
+ reiserfs_free_block (th, inode, allocated_block_nr, 1);
goto failure;
}
/* it is important the set_buffer_uptodate is done after
*/
mark_buffer_dirty(unbh) ;
}
-
- //inode->i_blocks += inode->i_sb->s_blocksize / 512;
- //mark_tail_converted (inode);
} else {
/* append indirect item with holes if needed, when appending
pointer to 'block'-th block use block, which is already
only have space for one block */
blocks_needed=max_to_insert?max_to_insert:1;
}
- retval = reiserfs_paste_into_item (th, &path, &tmp_key, (char *)un, UNFM_P_SIZE * blocks_needed);
+ retval = reiserfs_paste_into_item (th, &path, &tmp_key, inode, (char *)un, UNFM_P_SIZE * blocks_needed);
if (blocks_needed != 1)
kfree(un);
if (retval) {
- reiserfs_free_block (th, allocated_block_nr);
+ reiserfs_free_block (th, inode, allocated_block_nr, 1);
goto failure;
}
- if (done) {
- inode->i_blocks += inode->i_sb->s_blocksize / 512;
- } else {
+ if (!done) {
/* We need to mark new file size in case this function will be
interrupted/aborted later on. And we may do this only for
holes. */
inode->i_size += inode->i_sb->s_blocksize * blocks_needed;
}
- //mark_tail_converted (inode);
}
if (done == 1)
** ending their transaction will be able to continue.
*/
if (journal_transaction_should_end(th, th->t_blocks_allocated)) {
- restart_transaction(th, inode, &path) ;
+ retval = restart_transaction(th, inode, &path) ;
+ if (retval)
+ goto failure;
}
/* inserting indirect pointers for a hole can take a
** long time. reschedule if needed
goto failure;
}
if (retval == POSITION_FOUND) {
- reiserfs_warning ("vs-825: reiserfs_get_block: "
- "%K should not be found\n", &key);
+ reiserfs_warning (inode->i_sb, "vs-825: reiserfs_get_block: "
+ "%K should not be found", &key);
retval = -EEXIST;
if (allocated_block_nr)
- reiserfs_free_block (th, allocated_block_nr);
+ reiserfs_free_block (th, inode, allocated_block_nr, 1);
pathrelse(&path) ;
goto failure;
}
retval = 0;
failure:
- if (th && !dangle) {
- reiserfs_update_sd(th, inode) ;
- reiserfs_end_persistent_transaction(th);
+ if (th && (!dangle || (retval && !th->t_trans_id))) {
+ int err;
+ if (th->t_trans_id)
+ reiserfs_update_sd(th, inode);
+ err = reiserfs_end_persistent_transaction(th);
+ if (err)
+ retval = err;
}
+
reiserfs_write_unlock(inode->i_sb);
reiserfs_check_path(&path) ;
return retval;
return mpage_readpages(mapping, pages, nr_pages, reiserfs_get_block);
}
+/* Compute real number of used bytes by file
+ * Following three functions can go away when we'll have enough space in stat item
+ */
+static int real_space_diff(struct inode *inode, int sd_size)
+{
+ int bytes;
+ loff_t blocksize = inode->i_sb->s_blocksize ;
+
+ if (S_ISLNK(inode->i_mode) || S_ISDIR(inode->i_mode))
+ return sd_size ;
+
+ /* End of file is also in full block with indirect reference, so round
+ ** up to the next block.
+ **
+ ** there is just no way to know if the tail is actually packed
+ ** on the file, so we have to assume it isn't. When we pack the
+ ** tail, we add 4 bytes to pretend there really is an unformatted
+ ** node pointer
+ */
+ bytes = ((inode->i_size + (blocksize-1)) >> inode->i_sb->s_blocksize_bits) * UNFM_P_SIZE + sd_size;
+ return bytes ;
+}
+
+static inline loff_t to_real_used_space(struct inode *inode, ulong blocks,
+ int sd_size)
+{
+ if (S_ISLNK(inode->i_mode) || S_ISDIR(inode->i_mode)) {
+ return inode->i_size + (loff_t)(real_space_diff(inode, sd_size)) ;
+ }
+ return ((loff_t)real_space_diff(inode, sd_size)) + (((loff_t)blocks) << 9);
+}
+
+/* Compute number of blocks used by file in ReiserFS counting */
+static inline ulong to_fake_used_blocks(struct inode *inode, int sd_size)
+{
+ loff_t bytes = inode_get_bytes(inode) ;
+ loff_t real_space = real_space_diff(inode, sd_size) ;
+
+ /* keeps fsck and non-quota versions of reiserfs happy */
+ if (S_ISLNK(inode->i_mode) || S_ISDIR(inode->i_mode)) {
+ bytes += (loff_t)511 ;
+ }
+
+ /* files from before the quota patch might i_blocks such that
+ ** bytes < real_space. Deal with that here to prevent it from
+ ** going negative.
+ */
+ if (bytes < real_space)
+ return 0 ;
+ return (bytes - real_space) >> 9;
+}
+
//
// BAD: new directories have stat data of new type and all other items
// of old type. Version stored in the inode says about body items, so
REISERFS_I(inode)->i_prealloc_count = 0;
REISERFS_I(inode)->i_trans_id = 0;
REISERFS_I(inode)->i_jl = NULL;
+ REISERFS_I(inode)->i_acl_access = NULL;
+ REISERFS_I(inode)->i_acl_default = NULL;
+ init_rwsem (&REISERFS_I(inode)->xattr_sem);
if (stat_data_v1 (ih)) {
struct stat_data_v1 * sd = (struct stat_data_v1 *)B_I_PITEM (bh, ih);
rdev = sd_v1_rdev(sd);
REISERFS_I(inode)->i_first_direct_byte = sd_v1_first_direct_byte(sd);
+ /* an early bug in the quota code can give us an odd number for the
+ ** block count. This is incorrect, fix it here.
+ */
+ if (inode->i_blocks & 1) {
+ inode->i_blocks++ ;
+ }
+ inode_set_bytes(inode, to_real_used_space(inode, inode->i_blocks,
+ SD_V1_SIZE));
/* nopack is initially zero for v1 objects. For v2 objects,
nopack is initialised from sd_attrs */
REISERFS_I(inode)->i_flags &= ~i_nopack_mask;
set_inode_item_key_version (inode, KEY_FORMAT_3_6);
REISERFS_I(inode)->i_first_direct_byte = 0;
set_inode_sd_version (inode, STAT_DATA_V2);
+ inode_set_bytes(inode, to_real_used_space(inode, inode->i_blocks,
+ SD_V2_SIZE));
/* read persistent inode attributes from sd and initalise
generic inode flags from them */
REISERFS_I(inode)->i_attrs = sd_v2_attrs( sd );
sd_attrs_to_i_attrs( sd_v2_attrs( sd ), inode );
}
- inode->i_uid = INOXID_UID(uid, gid);
- inode->i_gid = INOXID_GID(uid, gid);
- inode->i_xid = INOXID_XID(uid, gid, 0);
+ inode->i_uid = INOXID_UID(XID_TAG(inode), uid, gid);
+ inode->i_gid = INOXID_GID(XID_TAG(inode), uid, gid);
+ inode->i_xid = INOXID_XID(XID_TAG(inode), uid, gid, 0);
pathrelse (path);
if (S_ISREG (inode->i_mode)) {
inode->i_op = &reiserfs_dir_inode_operations;
inode->i_fop = &reiserfs_dir_operations;
} else if (S_ISLNK (inode->i_mode)) {
- inode->i_op = &page_symlink_inode_operations;
+ inode->i_op = &reiserfs_symlink_inode_operations;
inode->i_mapping->a_ops = &reiserfs_address_space_operations;
} else {
inode->i_blocks = 0;
+ inode->i_op = &reiserfs_special_inode_operations;
init_special_inode(inode, inode->i_mode, new_decode_dev(rdev));
}
}
// update new stat data with inode fields
-static void inode2sd (void * sd, struct inode * inode)
+static void inode2sd (void * sd, struct inode * inode, loff_t size)
{
struct stat_data * sd_v2 = (struct stat_data *)sd;
- uid_t uid = XIDINO_UID(inode->i_uid, inode->i_xid);
- gid_t gid = XIDINO_GID(inode->i_gid, inode->i_xid);
+ uid_t uid = XIDINO_UID(XID_TAG(inode), inode->i_uid, inode->i_xid);
+ gid_t gid = XIDINO_GID(XID_TAG(inode), inode->i_gid, inode->i_xid);
__u16 flags;
set_sd_v2_uid(sd_v2, uid );
set_sd_v2_gid(sd_v2, gid );
set_sd_v2_mode(sd_v2, inode->i_mode );
set_sd_v2_nlink(sd_v2, inode->i_nlink );
- set_sd_v2_size(sd_v2, inode->i_size );
+ set_sd_v2_size(sd_v2, size );
set_sd_v2_mtime(sd_v2, inode->i_mtime.tv_sec );
set_sd_v2_atime(sd_v2, inode->i_atime.tv_sec );
set_sd_v2_ctime(sd_v2, inode->i_ctime.tv_sec );
- set_sd_v2_blocks(sd_v2, inode->i_blocks );
+ set_sd_v2_blocks(sd_v2, to_fake_used_blocks(inode, SD_V2_SIZE));
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
set_sd_v2_rdev(sd_v2, new_encode_dev(inode->i_rdev));
else
// used to copy inode's fields to old stat data
-static void inode2sd_v1 (void * sd, struct inode * inode)
+static void inode2sd_v1 (void * sd, struct inode * inode, loff_t size)
{
struct stat_data_v1 * sd_v1 = (struct stat_data_v1 *)sd;
set_sd_v1_uid(sd_v1, inode->i_uid );
set_sd_v1_gid(sd_v1, inode->i_gid );
set_sd_v1_nlink(sd_v1, inode->i_nlink );
- set_sd_v1_size(sd_v1, inode->i_size );
+ set_sd_v1_size(sd_v1, size );
set_sd_v1_atime(sd_v1, inode->i_atime.tv_sec );
set_sd_v1_ctime(sd_v1, inode->i_ctime.tv_sec );
set_sd_v1_mtime(sd_v1, inode->i_mtime.tv_sec );
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
set_sd_v1_rdev(sd_v1, new_encode_dev(inode->i_rdev));
else
- set_sd_v1_blocks(sd_v1, inode->i_blocks );
+ set_sd_v1_blocks(sd_v1, to_fake_used_blocks(inode, SD_V1_SIZE));
// Sigh. i_first_direct_byte is back
set_sd_v1_first_direct_byte(sd_v1, REISERFS_I(inode)->i_first_direct_byte);
/* NOTE, you must prepare the buffer head before sending it here,
** and then log it after the call
*/
-static void update_stat_data (struct path * path, struct inode * inode)
+static void update_stat_data (struct path * path, struct inode * inode,
+ loff_t size)
{
struct buffer_head * bh;
struct item_head * ih;
if (stat_data_v1 (ih)) {
// path points to old stat data
- inode2sd_v1 (B_I_PITEM (bh, ih), inode);
+ inode2sd_v1 (B_I_PITEM (bh, ih), inode, size);
} else {
- inode2sd (B_I_PITEM (bh, ih), inode);
+ inode2sd (B_I_PITEM (bh, ih), inode, size);
}
return;
}
-void reiserfs_update_sd (struct reiserfs_transaction_handle *th,
- struct inode * inode)
+void reiserfs_update_sd_size (struct reiserfs_transaction_handle *th,
+ struct inode * inode, loff_t size)
{
struct cpu_key key;
INITIALIZE_PATH(path);
struct item_head *ih, tmp_ih ;
int retval;
+ BUG_ON (!th->t_trans_id);
+
make_cpu_key (&key, inode, SD_OFFSET, TYPE_STAT_DATA, 3);//key type is unimportant
for(;;) {
/* look for the object's stat data */
retval = search_item (inode->i_sb, &key, &path);
if (retval == IO_ERROR) {
- reiserfs_warning ("vs-13050: reiserfs_update_sd: "
+ reiserfs_warning (inode->i_sb, "vs-13050: reiserfs_update_sd: "
"i/o failure occurred trying to update %K stat data",
&key);
return;
pos = PATH_LAST_POSITION (&path);
pathrelse(&path) ;
if (inode->i_nlink == 0) {
- /*printk ("vs-13050: reiserfs_update_sd: i_nlink == 0, stat data not found\n");*/
+ /*reiserfs_warning (inode->i_sb, "vs-13050: reiserfs_update_sd: i_nlink == 0, stat data not found");*/
return;
}
- reiserfs_warning ("vs-13060: reiserfs_update_sd: "
- "stat data of object %k (nlink == %d) not found (pos %d)\n",
+ reiserfs_warning (inode->i_sb, "vs-13060: reiserfs_update_sd: "
+ "stat data of object %k (nlink == %d) not found (pos %d)",
INODE_PKEY (inode), inode->i_nlink, pos);
reiserfs_check_path(&path) ;
return;
}
break;
}
- update_stat_data (&path, inode);
+ update_stat_data (&path, inode, size);
journal_mark_dirty(th, th->t_super, bh) ;
pathrelse (&path);
return;
/* look for the object's stat data */
retval = search_item (inode->i_sb, &key, &path_to_sd);
if (retval == IO_ERROR) {
- reiserfs_warning ("vs-13070: reiserfs_read_locked_inode: "
- "i/o failure occurred trying to find stat data of %K\n",
- &key);
+ reiserfs_warning (inode->i_sb, "vs-13070: reiserfs_read_locked_inode: "
+ "i/o failure occurred trying to find stat data of %K",
+ &key);
reiserfs_make_bad_inode(inode) ;
return;
}
during mount (fs/reiserfs/super.c:finish_unfinished()). */
if( ( inode -> i_nlink == 0 ) &&
! REISERFS_SB(inode -> i_sb) -> s_is_unlinked_ok ) {
- reiserfs_warning( "vs-13075: reiserfs_read_locked_inode: "
+ reiserfs_warning (inode->i_sb,
+ "vs-13075: reiserfs_read_locked_inode: "
"dead inode read from disk %K. "
- "This is likely to be race with knfsd. Ignore\n",
+ "This is likely to be race with knfsd. Ignore",
&key );
reiserfs_make_bad_inode( inode );
}
if (comp_short_keys (INODE_PKEY (inode), key) || is_bad_inode (inode)) {
/* either due to i/o error or a stale NFS handle */
iput (inode);
- inode = 0;
+ inode = NULL;
}
return inode;
}
key.on_disk_key.k_objectid = data[0] ;
key.on_disk_key.k_dir_id = data[1] ;
+ reiserfs_write_lock(sb);
inode = reiserfs_iget(sb, &key) ;
if (inode && !IS_ERR(inode) && data[2] != 0 &&
data[2] != inode->i_generation) {
iput(inode) ;
inode = NULL ;
}
+ reiserfs_write_unlock(sb);
if (!inode)
inode = ERR_PTR(-ESTALE);
if (IS_ERR(inode))
*/
if (fhtype > len) {
if (fhtype != 6 || len != 5)
- printk(KERN_WARNING "nfsd/reiserfs, fhtype=%d, len=%d - odd\n",
+ reiserfs_warning (sb, "nfsd/reiserfs, fhtype=%d, len=%d - odd",
fhtype, len);
fhtype = 5;
}
** to properly mark inodes for datasync and such, but only actually
** does something when called for a synchronous update.
*/
-void reiserfs_write_inode (struct inode * inode, int do_sync) {
+int reiserfs_write_inode (struct inode * inode, int do_sync) {
struct reiserfs_transaction_handle th ;
int jbegin_count = 1 ;
- if (inode->i_sb->s_flags & MS_RDONLY) {
- reiserfs_warning("clm-6005: writing inode %lu on readonly FS\n",
- inode->i_ino) ;
- return ;
- }
+ if (inode->i_sb->s_flags & MS_RDONLY)
+ return -EROFS;
/* memory pressure can sometimes initiate write_inode calls with sync == 1,
** these cases are just when the system needs ram, not when the
** inode needs to reach disk for safety, and they can safely be
*/
if (do_sync && !(current->flags & PF_MEMALLOC)) {
reiserfs_write_lock(inode->i_sb);
- journal_begin(&th, inode->i_sb, jbegin_count) ;
- reiserfs_update_sd (&th, inode);
- journal_end_sync(&th, inode->i_sb, jbegin_count) ;
+ if (!journal_begin(&th, inode->i_sb, jbegin_count)) {
+ reiserfs_update_sd (&th, inode);
+ journal_end_sync(&th, inode->i_sb, jbegin_count) ;
+ }
reiserfs_write_unlock(inode->i_sb);
}
+ return 0;
}
-/* FIXME: no need any more. right? */
-int reiserfs_sync_inode (struct reiserfs_transaction_handle *th, struct inode * inode)
-{
- int err = 0;
-
- reiserfs_update_sd (th, inode);
- return err;
-}
-
-
/* stat data of new object is inserted already, this inserts the item
containing "." and ".." entries */
static int reiserfs_new_directory (struct reiserfs_transaction_handle *th,
+ struct inode *inode,
struct item_head * ih, struct path * path,
struct inode * dir)
{
char * body = empty_dir;
struct cpu_key key;
int retval;
+
+ BUG_ON (!th->t_trans_id);
_make_cpu_key (&key, KEY_FORMAT_3_5, le32_to_cpu (ih->ih_key.k_dir_id),
le32_to_cpu (ih->ih_key.k_objectid), DOT_OFFSET, TYPE_DIRENTRY, 3/*key length*/);
old type (ITEM_VERSION_1). Do not set key (second arg is 0), it
is done by reiserfs_new_inode */
if (old_format_only (sb)) {
- make_le_item_head (ih, 0, KEY_FORMAT_3_5, DOT_OFFSET, TYPE_DIRENTRY, EMPTY_DIR_SIZE_V1, 2);
+ make_le_item_head (ih, NULL, KEY_FORMAT_3_5, DOT_OFFSET, TYPE_DIRENTRY, EMPTY_DIR_SIZE_V1, 2);
make_empty_dir_item_v1 (body, ih->ih_key.k_dir_id, ih->ih_key.k_objectid,
INODE_PKEY (dir)->k_dir_id,
INODE_PKEY (dir)->k_objectid );
} else {
- make_le_item_head (ih, 0, KEY_FORMAT_3_5, DOT_OFFSET, TYPE_DIRENTRY, EMPTY_DIR_SIZE, 2);
+ make_le_item_head (ih, NULL, KEY_FORMAT_3_5, DOT_OFFSET, TYPE_DIRENTRY, EMPTY_DIR_SIZE, 2);
make_empty_dir_item (body, ih->ih_key.k_dir_id, ih->ih_key.k_objectid,
INODE_PKEY (dir)->k_dir_id,
/* look for place in the tree for new item */
retval = search_item (sb, &key, path);
if (retval == IO_ERROR) {
- reiserfs_warning ("vs-13080: reiserfs_new_directory: "
- "i/o failure occurred creating new directory\n");
+ reiserfs_warning (sb, "vs-13080: reiserfs_new_directory: "
+ "i/o failure occurred creating new directory");
return -EIO;
}
if (retval == ITEM_FOUND) {
pathrelse (path);
- reiserfs_warning ("vs-13070: reiserfs_new_directory: "
+ reiserfs_warning (sb, "vs-13070: reiserfs_new_directory: "
"object with this key exists (%k)", &(ih->ih_key));
return -EEXIST;
}
/* insert item, that is empty directory item */
- return reiserfs_insert_item (th, path, &key, ih, body);
+ return reiserfs_insert_item (th, path, &key, ih, inode, body);
}
/* stat data of object has been inserted, this inserts the item
containing the body of symlink */
static int reiserfs_new_symlink (struct reiserfs_transaction_handle *th,
+ struct inode *inode, /* Inode of symlink */
struct item_head * ih,
struct path * path, const char * symname, int item_len)
{
struct cpu_key key;
int retval;
+ BUG_ON (!th->t_trans_id);
+
_make_cpu_key (&key, KEY_FORMAT_3_5,
le32_to_cpu (ih->ih_key.k_dir_id),
le32_to_cpu (ih->ih_key.k_objectid),
1, TYPE_DIRECT, 3/*key length*/);
- make_le_item_head (ih, 0, KEY_FORMAT_3_5, 1, TYPE_DIRECT, item_len, 0/*free_space*/);
+ make_le_item_head (ih, NULL, KEY_FORMAT_3_5, 1, TYPE_DIRECT, item_len, 0/*free_space*/);
/* look for place in the tree for new item */
retval = search_item (sb, &key, path);
if (retval == IO_ERROR) {
- reiserfs_warning ("vs-13080: reiserfs_new_symlinik: "
- "i/o failure occurred creating new symlink\n");
+ reiserfs_warning (sb, "vs-13080: reiserfs_new_symlinik: "
+ "i/o failure occurred creating new symlink");
return -EIO;
}
if (retval == ITEM_FOUND) {
pathrelse (path);
- reiserfs_warning ("vs-13080: reiserfs_new_symlink: "
+ reiserfs_warning (sb, "vs-13080: reiserfs_new_symlink: "
"object with this key exists (%k)", &(ih->ih_key));
return -EEXIST;
}
/* insert item, that is body of symlink */
- return reiserfs_insert_item (th, path, &key, ih, symname);
+ return reiserfs_insert_item (th, path, &key, ih, inode, symname);
}
struct stat_data sd;
int retval;
int err;
+
+ BUG_ON (!th->t_trans_id);
+ if (DQUOT_ALLOC_INODE(inode)) {
+ err = -EDQUOT;
+ goto out_end_trans;
+ }
if (!dir || !dir->i_nlink) {
err = -EPERM;
goto out_bad_inode;
sb = dir->i_sb;
/* item head of new item */
- ih.ih_key.k_dir_id = INODE_PKEY (dir)->k_objectid;
+ ih.ih_key.k_dir_id = reiserfs_choose_packing(dir);
ih.ih_key.k_objectid = cpu_to_le32 (reiserfs_get_unused_objectid (th));
if (!ih.ih_key.k_objectid) {
err = -ENOMEM;
if( S_ISLNK( inode -> i_mode ) )
inode -> i_flags &= ~ ( S_IMMUTABLE | S_APPEND );
- inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ inode->i_mtime = inode->i_atime = inode->i_ctime =
+ CURRENT_TIME_SEC;
inode->i_size = i_size;
- inode->i_blocks = (inode->i_size + 511) >> 9;
+ inode->i_blocks = 0;
+ inode->i_bytes = 0;
REISERFS_I(inode)->i_first_direct_byte = S_ISLNK(mode) ? 1 :
U32_MAX/*NO_BYTES_IN_DIRECT_ITEM*/;
REISERFS_I(inode)->i_prealloc_block = 0;
REISERFS_I(inode)->i_prealloc_count = 0;
REISERFS_I(inode)->i_trans_id = 0;
- REISERFS_I(inode)->i_jl = 0;
+ REISERFS_I(inode)->i_jl = NULL;
REISERFS_I(inode)->i_attrs =
REISERFS_I(dir)->i_attrs & REISERFS_INHERIT_MASK;
sd_attrs_to_i_attrs( REISERFS_I(inode) -> i_attrs, inode );
+ REISERFS_I(inode)->i_acl_access = NULL;
+ REISERFS_I(inode)->i_acl_default = NULL;
+ init_rwsem (&REISERFS_I(inode)->xattr_sem);
if (old_format_only (sb))
- make_le_item_head (&ih, 0, KEY_FORMAT_3_5, SD_OFFSET, TYPE_STAT_DATA, SD_V1_SIZE, MAX_US_INT);
+ make_le_item_head (&ih, NULL, KEY_FORMAT_3_5, SD_OFFSET, TYPE_STAT_DATA, SD_V1_SIZE, MAX_US_INT);
else
- make_le_item_head (&ih, 0, KEY_FORMAT_3_6, SD_OFFSET, TYPE_STAT_DATA, SD_SIZE, MAX_US_INT);
+ make_le_item_head (&ih, NULL, KEY_FORMAT_3_6, SD_OFFSET, TYPE_STAT_DATA, SD_SIZE, MAX_US_INT);
/* key to search for correct place for new stat data */
_make_cpu_key (&key, KEY_FORMAT_3_6, le32_to_cpu (ih.ih_key.k_dir_id),
err = -EEXIST;
goto out_bad_inode;
}
-
if (old_format_only (sb)) {
if (inode->i_uid & ~0xffff || inode->i_gid & ~0xffff) {
pathrelse (&path_to_key);
err = -EINVAL;
goto out_bad_inode;
}
- inode2sd_v1 (&sd, inode);
+ inode2sd_v1 (&sd, inode, inode->i_size);
} else {
- inode2sd (&sd, inode);
+ inode2sd (&sd, inode, inode->i_size);
}
// these do not go to on-disk stat data
inode->i_ino = le32_to_cpu (ih.ih_key.k_objectid);
if (REISERFS_I(dir)->new_packing_locality)
th->displace_new_blocks = 1;
#endif
- retval = reiserfs_insert_item (th, &path_to_key, &key, &ih, (char *)(&sd));
+ retval = reiserfs_insert_item (th, &path_to_key, &key, &ih, inode, (char *)(&sd));
if (retval) {
err = retval;
reiserfs_check_path(&path_to_key) ;
#endif
if (S_ISDIR(mode)) {
/* insert item with "." and ".." */
- retval = reiserfs_new_directory (th, &ih, &path_to_key, dir);
+ retval = reiserfs_new_directory (th, inode, &ih, &path_to_key, dir);
}
if (S_ISLNK(mode)) {
/* insert body of symlink */
if (!old_format_only (sb))
i_size = ROUND_UP(i_size);
- retval = reiserfs_new_symlink (th, &ih, &path_to_key, symname, i_size);
+ retval = reiserfs_new_symlink (th, inode, &ih, &path_to_key, symname, i_size);
}
if (retval) {
err = retval;
goto out_inserted_sd;
}
+ /* XXX CHECK THIS */
+ if (reiserfs_posixacl (inode->i_sb)) {
+ retval = reiserfs_inherit_default_acl (dir, dentry, inode);
+ if (retval) {
+ err = retval;
+ reiserfs_check_path(&path_to_key) ;
+ journal_end(th, th->t_super, th->t_blocks_allocated);
+ goto out_inserted_sd;
+ }
+ } else if (inode->i_sb->s_flags & MS_POSIXACL) {
+ reiserfs_warning (inode->i_sb, "ACLs aren't enabled in the fs, "
+ "but vfs thinks they are!");
+ }
+
insert_inode_hash (inode);
reiserfs_update_sd(th, inode);
reiserfs_check_path(&path_to_key) ;
/* Invalidate the object, nothing was inserted yet */
INODE_PKEY(inode)->k_objectid = 0;
- /* dquot_drop must be done outside a transaction */
+ /* Quota change must be inside a transaction for journaling */
+ DQUOT_FREE_INODE(inode);
+
+out_end_trans:
journal_end(th, th->t_super, th->t_blocks_allocated) ;
+ /* Drop can be outside and it needs more credits so it's better to have it outside */
+ DQUOT_DROP(inode);
+ inode->i_flags |= S_NOQUOTA;
make_bad_inode(inode);
out_inserted_sd:
** I've screwed up the code to find the buffer, or the code to
** call prepare_write
*/
- reiserfs_warning("clm-6000: error reading block %lu on dev %s\n",
- bh->b_blocknr,
- reiserfs_bdevname (p_s_inode->i_sb)) ;
+ reiserfs_warning (p_s_inode->i_sb,
+ "clm-6000: error reading block %lu on dev %s",
+ bh->b_blocknr,
+ reiserfs_bdevname (p_s_inode->i_sb)) ;
error = -EIO ;
goto unlock ;
}
**
** some code taken from block_truncate_page
*/
-void reiserfs_truncate_file(struct inode *p_s_inode, int update_timestamps) {
+int reiserfs_truncate_file(struct inode *p_s_inode, int update_timestamps) {
struct reiserfs_transaction_handle th ;
/* we want the offset for the first byte after the end of the file */
unsigned long offset = p_s_inode->i_size & (PAGE_CACHE_SIZE - 1) ;
// and get_block_create_0 could not find a block to read in,
// which is ok.
if (error != -ENOENT)
- reiserfs_warning("clm-6001: grab_tail_page failed %d\n", error);
+ reiserfs_warning (p_s_inode->i_sb,
+ "clm-6001: grab_tail_page failed %d",
+ error);
page = NULL ;
bh = NULL ;
}
/* it is enough to reserve space in transaction for 2 balancings:
one for "save" link adding and another for the first
cut_from_item. 1 is for update_sd */
- journal_begin(&th, p_s_inode->i_sb, JOURNAL_PER_BALANCE_CNT * 2 + 1 ) ;
+ error = journal_begin (&th, p_s_inode->i_sb,
+ JOURNAL_PER_BALANCE_CNT * 2 + 1);
+ if (error)
+ goto out;
reiserfs_update_inode_transaction(p_s_inode) ;
if (update_timestamps)
/* we are doing real truncate: if the system crashes before the last
transaction of truncating gets committed - on reboot the file
either appears truncated properly or not truncated at all */
add_save_link (&th, p_s_inode, 1);
- reiserfs_do_truncate (&th, p_s_inode, page, update_timestamps) ;
- journal_end(&th, p_s_inode->i_sb, JOURNAL_PER_BALANCE_CNT * 2 + 1 ) ;
+ error = reiserfs_do_truncate (&th, p_s_inode, page, update_timestamps) ;
+ if (error)
+ goto out;
+ error = journal_end (&th, p_s_inode->i_sb, JOURNAL_PER_BALANCE_CNT * 2 + 1);
+ if (error)
+ goto out;
- if (update_timestamps)
- remove_save_link (p_s_inode, 1/* truncate */);
+ if (update_timestamps) {
+ error = remove_save_link (p_s_inode, 1/* truncate */);
+ if (error)
+ goto out;
+ }
if (page) {
length = offset & (blocksize - 1) ;
}
reiserfs_write_unlock(p_s_inode->i_sb);
+ return 0;
+out:
+ if (page) {
+ unlock_page (page);
+ page_cache_release (page);
+ }
+ reiserfs_write_unlock(p_s_inode->i_sb);
+ return error;
}
static int map_block_for_writepage(struct inode *inode,
/* we've found an unformatted node */
if (indirect_item_found(retval, ih)) {
if (bytes_copied > 0) {
- reiserfs_warning("clm-6002: bytes_copied %d\n", bytes_copied) ;
+ reiserfs_warning (inode->i_sb, "clm-6002: bytes_copied %d",
+ bytes_copied) ;
}
if (!get_block_num(item, pos_in_item)) {
/* crap, we are writing to a hole */
if (!trans_running) {
/* vs-3050 is gone, no need to drop the path */
- journal_begin(&th, inode->i_sb, jbegin_count) ;
+ retval = journal_begin(&th, inode->i_sb, jbegin_count) ;
+ if (retval)
+ goto out;
reiserfs_update_inode_transaction(inode) ;
trans_running = 1;
if (fs_changed(fs_gen, inode->i_sb) && item_moved(&tmp_ih, &path)) {
goto research ;
}
} else {
- reiserfs_warning("clm-6003: bad item inode %lu, device %s\n", inode->i_ino, reiserfs_bdevname (inode->i_sb)) ;
+ reiserfs_warning (inode->i_sb,
+ "clm-6003: bad item inode %lu, device %s",
+ inode->i_ino, reiserfs_bdevname (inode->i_sb)) ;
retval = -EIO ;
goto out ;
}
out:
pathrelse(&path) ;
if (trans_running) {
- journal_end(&th, inode->i_sb, jbegin_count) ;
+ int err = journal_end(&th, inode->i_sb, jbegin_count) ;
+ if (err)
+ retval = err;
trans_running = 0;
}
reiserfs_write_unlock(inode->i_sb);
struct buffer_head *head, *bh;
int partial = 0 ;
int nr = 0;
+ int checked = PageChecked(page);
+ struct reiserfs_transaction_handle th;
+ struct super_block *s = inode->i_sb;
+ int bh_per_page = PAGE_CACHE_SIZE / s->s_blocksize;
+ th.t_trans_id = 0;
/* The page dirty bit is cleared before writepage is called, which
* means we have to tell create_empty_buffers to make dirty buffers
* in the BH_Uptodate is just a sanity check.
*/
if (!page_has_buffers(page)) {
- create_empty_buffers(page, inode->i_sb->s_blocksize,
+ create_empty_buffers(page, s->s_blocksize,
(1 << BH_Dirty) | (1 << BH_Uptodate));
}
head = page_buffers(page) ;
kunmap_atomic(kaddr, KM_USER0) ;
}
bh = head ;
- block = page->index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits) ;
+ block = page->index << (PAGE_CACHE_SHIFT - s->s_blocksize_bits) ;
/* first map all the buffers, logging any direct items we find */
do {
- if (buffer_dirty(bh) && (!buffer_mapped(bh) ||
+ if ((checked || buffer_dirty(bh)) && (!buffer_mapped(bh) ||
(buffer_mapped(bh) && bh->b_blocknr == 0))) {
/* not mapped yet, or it points to a direct item, search
* the btree for the mapping info, and log any direct
block++;
} while(bh != head) ;
+ /*
+ * we start the transaction after map_block_for_writepage,
+ * because it can create holes in the file (an unbounded operation).
+ * starting it here, we can make a reliable estimate for how many
+ * blocks we're going to log
+ */
+ if (checked) {
+ ClearPageChecked(page);
+ reiserfs_write_lock(s);
+ error = journal_begin(&th, s, bh_per_page + 1);
+ if (error) {
+ reiserfs_write_unlock(s);
+ goto fail;
+ }
+ reiserfs_update_inode_transaction(inode);
+ }
/* now go through and lock any dirty buffers on the page */
do {
get_bh(bh);
if (buffer_mapped(bh) && bh->b_blocknr == 0)
continue;
+ if (checked) {
+ reiserfs_prepare_for_journal(s, bh, 1);
+ journal_mark_dirty(&th, s, bh);
+ continue;
+ }
/* from this point on, we know the buffer is mapped to a
* real block and not a direct item
*/
}
} while((bh = bh->b_this_page) != head);
+ if (checked) {
+ error = journal_end(&th, s, bh_per_page + 1);
+ reiserfs_write_unlock(s);
+ if (error)
+ goto fail;
+ }
BUG_ON(PageWriteback(page));
set_page_writeback(page);
unlock_page(page);
return reiserfs_write_full_page(page, wbc) ;
}
-int reiserfs_prepare_write(struct file *f, struct page *page,
+static int reiserfs_prepare_write(struct file *f, struct page *page,
unsigned from, unsigned to) {
struct inode *inode = page->mapping->host ;
int ret;
fix_tail_page_for_writing(page) ;
if (reiserfs_transaction_running(inode->i_sb)) {
struct reiserfs_transaction_handle *th;
- th = (struct reiserfs_transaction_handle *)current->journal_info;
+ th = (struct reiserfs_transaction_handle *)current->journal_info;
+ BUG_ON (!th->t_refcount);
+ BUG_ON (!th->t_trans_id);
old_ref = th->t_refcount;
th->t_refcount++;
}
if (old_ref)
th->t_refcount--;
else {
+ int err;
reiserfs_write_lock(inode->i_sb);
- reiserfs_end_persistent_transaction(th);
+ err = reiserfs_end_persistent_transaction(th);
reiserfs_write_unlock(inode->i_sb);
+ if (err)
+ ret = err;
}
}
}
struct inode *inode = page->mapping->host ;
loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
int ret = 0;
+ int update_sd = 0;
struct reiserfs_transaction_handle *th = NULL;
reiserfs_wait_on_write_block(inode->i_sb) ;
(have_small_tails (inode->i_sb) && inode->i_size > i_block_size(inode)) )
REISERFS_I(inode)->i_flags &= ~i_pack_on_close_mask ;
- journal_begin(&myth, inode->i_sb, 1) ;
+ ret = journal_begin(&myth, inode->i_sb, 1) ;
+ if (ret) {
+ reiserfs_write_unlock(inode->i_sb);
+ goto journal_error;
+ }
reiserfs_update_inode_transaction(inode) ;
inode->i_size = pos ;
reiserfs_update_sd(&myth, inode) ;
- journal_end(&myth, inode->i_sb, 1) ;
+ update_sd = 1;
+ ret = journal_end(&myth, inode->i_sb, 1) ;
reiserfs_write_unlock(inode->i_sb);
+ if (ret)
+ goto journal_error;
}
if (th) {
reiserfs_write_lock(inode->i_sb);
- reiserfs_end_persistent_transaction(th);
+ if (!update_sd)
+ reiserfs_update_sd(th, inode) ;
+ ret = reiserfs_end_persistent_transaction(th);
reiserfs_write_unlock(inode->i_sb);
+ if (ret)
+ goto out;
}
/* we test for O_SYNC here so we can commit the transaction
*/
if (f && (f->f_flags & O_SYNC)) {
reiserfs_write_lock(inode->i_sb);
- reiserfs_commit_for_inode(inode) ;
+ ret = reiserfs_commit_for_inode(inode) ;
reiserfs_write_unlock(inode->i_sb);
}
+out:
return ret ;
+
+journal_error:
+ if (th) {
+ reiserfs_write_lock(inode->i_sb);
+ if (!update_sd)
+ reiserfs_update_sd(th, inode) ;
+ ret = reiserfs_end_persistent_transaction(th);
+ reiserfs_write_unlock(inode->i_sb);
+ }
+
+ return ret;
}
void sd_attrs_to_i_attrs( __u16 sd_attrs, struct inode *inode )
/* the page is locked, and the only places that log a data buffer
* also lock the page.
*/
-#if 0
if (reiserfs_file_data_log(inode)) {
- /* very conservative, leave the buffer pinned if anyone might need it.
- ** this should be changed to drop the buffer if it is only in the
- ** current transaction
- */
+ /*
+ * very conservative, leave the buffer pinned if
+ * anyone might need it.
+ */
if (buffer_journaled(bh) || buffer_journal_dirty(bh)) {
ret = 0 ;
}
} else
-#endif
if (buffer_dirty(bh) || buffer_locked(bh)) {
struct reiserfs_journal_list *jl;
struct reiserfs_jh *jh = bh->b_private;
int ret = 1;
BUG_ON(!PageLocked(page));
+
+ if (offset == 0)
+ ClearPageChecked(page);
+
if (!page_has_buffers(page))
goto out;
return ret;
}
+static int reiserfs_set_page_dirty(struct page *page) {
+ struct inode *inode = page->mapping->host;
+ if (reiserfs_file_data_log(inode)) {
+ SetPageChecked(page);
+ return __set_page_dirty_nobuffers(page);
+ }
+ return __set_page_dirty_buffers(page);
+}
+
/*
* Returns 1 if the page's buffers were dropped. The page is locked.
*
struct buffer_head *bh ;
int ret = 1 ;
+ WARN_ON(PageChecked(page));
spin_lock(&j->j_dirty_buffers_lock) ;
head = page_buffers(page) ;
bh = head ;
offset, nr_segs, reiserfs_get_blocks_direct_io, NULL);
}
+int reiserfs_setattr_flags(struct inode *inode, unsigned int flags)
+{
+ unsigned int oldflags, newflags;
+
+ oldflags = REISERFS_I(inode)->i_flags;
+ newflags = oldflags & ~(REISERFS_IMMUTABLE_FL |
+ REISERFS_IUNLINK_FL | REISERFS_BARRIER_FL);
+ if (flags & ATTR_FLAG_IMMUTABLE)
+ newflags |= REISERFS_IMMUTABLE_FL;
+ if (flags & ATTR_FLAG_IUNLINK)
+ newflags |= REISERFS_IUNLINK_FL;
+ if (flags & ATTR_FLAG_BARRIER)
+ newflags |= REISERFS_BARRIER_FL;
+
+ if (oldflags ^ newflags) {
+ REISERFS_I(inode)->i_flags = newflags;
+ inode->i_ctime = CURRENT_TIME;
+ }
+ return 0;
+}
+
+int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) {
+ struct inode *inode = dentry->d_inode ;
+ int error ;
+ unsigned int ia_valid = attr->ia_valid;
+ reiserfs_write_lock(inode->i_sb);
+ if (attr->ia_valid & ATTR_SIZE) {
+ /* version 2 items will be caught by the s_maxbytes check
+ ** done for us in vmtruncate
+ */
+ if (get_inode_item_key_version(inode) == KEY_FORMAT_3_5 &&
+ attr->ia_size > MAX_NON_LFS) {
+ error = -EFBIG ;
+ goto out;
+ }
+ /* fill in hole pointers in the expanding truncate case. */
+ if (attr->ia_size > inode->i_size) {
+ error = generic_cont_expand(inode, attr->ia_size) ;
+ if (REISERFS_I(inode)->i_prealloc_count > 0) {
+ int err;
+ struct reiserfs_transaction_handle th ;
+ /* we're changing at most 2 bitmaps, inode + super */
+ err = journal_begin(&th, inode->i_sb, 4) ;
+ if (!err) {
+ reiserfs_discard_prealloc (&th, inode);
+ err = journal_end(&th, inode->i_sb, 4) ;
+ }
+ if (err)
+ error = err;
+ }
+ if (error)
+ goto out;
+ }
+ }
+
+ if ((((attr->ia_valid & ATTR_UID) && (attr->ia_uid & ~0xffff)) ||
+ ((attr->ia_valid & ATTR_GID) && (attr->ia_gid & ~0xffff))) &&
+ (get_inode_sd_version (inode) == STAT_DATA_V1)) {
+ /* stat data of format v3.5 has 16 bit uid and gid */
+ error = -EINVAL;
+ goto out;
+ }
+
+ error = inode_change_ok(inode, attr) ;
+
+ if (!error && attr->ia_valid & ATTR_ATTR_FLAG)
+ reiserfs_setattr_flags(inode, attr->ia_attr_flags);
+
+ if (!error) {
+ if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) ||
+ (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) {
+ error = reiserfs_chown_xattrs (inode, attr);
+
+ if (!error) {
+ struct reiserfs_transaction_handle th;
+
+ /* (user+group)*(old+new) structure - we count quota info and , inode write (sb, inode) */
+ journal_begin(&th, inode->i_sb, 4*REISERFS_QUOTA_INIT_BLOCKS+2);
+ error = DQUOT_TRANSFER(inode, attr) ? -EDQUOT : 0;
+ if (error) {
+ journal_end(&th, inode->i_sb, 4*REISERFS_QUOTA_INIT_BLOCKS+2);
+ goto out;
+ }
+ /* Update corresponding info in inode so that everything is in
+ * one transaction */
+ if (attr->ia_valid & ATTR_UID)
+ inode->i_uid = attr->ia_uid;
+ if (attr->ia_valid & ATTR_GID)
+ inode->i_gid = attr->ia_gid;
+ mark_inode_dirty(inode);
+ journal_end(&th, inode->i_sb, 4*REISERFS_QUOTA_INIT_BLOCKS+2);
+ }
+ }
+ if (!error)
+ error = inode_setattr(inode, attr) ;
+ }
+
+
+ if (!error && reiserfs_posixacl (inode->i_sb)) {
+ if (attr->ia_valid & ATTR_MODE)
+ error = reiserfs_acl_chmod (inode);
+ }
+
+out:
+ reiserfs_write_unlock(inode->i_sb);
+ return error ;
+}
+
+
struct address_space_operations reiserfs_address_space_operations = {
.writepage = reiserfs_writepage,
.prepare_write = reiserfs_prepare_write,
.commit_write = reiserfs_commit_write,
.bmap = reiserfs_aop_bmap,
- .direct_IO = reiserfs_direct_IO
+ .direct_IO = reiserfs_direct_IO,
+ .set_page_dirty = reiserfs_set_page_dirty,
} ;