patch-2.4.17 linux/fs/ext3/inode.c

Next file: linux/fs/ext3/super.c
Previous file: linux/fs/ext3/acl.c
Back to the patch index
Back to the overall index

diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/ext3/inode.c linux/fs/ext3/inode.c
@@ -32,7 +32,6 @@
 #include <linux/quotaops.h>
 #include <linux/module.h>
 
-
 /*
  * SEARCH_FROM_ZERO forces each block allocation to search from the start
  * of the filesystem.  This is to force rapid reallocation of recently-freed
@@ -716,6 +715,8 @@
  * reachable from inode.
  *
  * akpm: `handle' can be NULL if create == 0.
+ *
+ * The BKL may not be held on entry here.  Be sure to take it early.
  */
 
 static int ext3_get_block_handle(handle_t *handle, struct inode *inode, 
@@ -823,6 +824,9 @@
 	goto reread;
 }
 
+/*
+ * The BKL is not held on entry here.
+ */
 static int ext3_get_block(struct inode *inode, long iblock,
 			struct buffer_head *bh_result, int create)
 {
@@ -1022,13 +1026,26 @@
 		ret = PTR_ERR(handle);
 		goto out;
 	}
+	unlock_kernel();
 	ret = block_prepare_write(page, from, to, ext3_get_block);
+	lock_kernel();
 	if (ret != 0)
 		goto prepare_write_failed;
 
-	if (ext3_should_journal_data(inode))
+	if (ext3_should_journal_data(inode)) {
 		ret = walk_page_buffers(handle, page->buffers,
 				from, to, NULL, do_journal_get_write_access);
+		if (ret) {
+			/*
+			 * We're going to fail this prepare_write(),
+			 * so commit_write() will not be called.
+			 * We need to undo block_prepare_write()'s kmap().
+			 * AKPM: Do we need to clear PageUptodate?  I don't
+			 * think so.
+			 */
+			kunmap(page);
+		}
+	}
 prepare_write_failed:
 	if (ret)
 		ext3_journal_stop(handle, inode);
@@ -1096,7 +1113,7 @@
 		kunmap(page);
 		if (pos > inode->i_size)
 			inode->i_size = pos;
-		set_bit(EXT3_STATE_JDATA, &inode->u.ext3_i.i_state);
+		EXT3_I(inode)->i_state |= EXT3_STATE_JDATA;
 	} else {
 		if (ext3_should_order_data(inode)) {
 			ret = walk_page_buffers(handle, page->buffers,
@@ -1104,8 +1121,17 @@
 		}
 		/* Be careful here if generic_commit_write becomes a
 		 * required invocation after block_prepare_write. */
-		if (ret == 0)
+		if (ret == 0) {
 			ret = generic_commit_write(file, page, from, to);
+		} else {
+			/*
+			 * block_prepare_write() was called, but we're not
+			 * going to call generic_commit_write().  So we
+			 * need to perform generic_commit_write()'s kunmap
+			 * by hand.
+			 */
+			kunmap(page);
+		}
 	}
 	if (inode->i_size > inode->u.ext3_i.i_disksize) {
 		inode->u.ext3_i.i_disksize = inode->i_size;
@@ -1140,7 +1166,7 @@
 	journal_t *journal;
 	int err;
 	
-	if (test_and_clear_bit(EXT3_STATE_JDATA, &inode->u.ext3_i.i_state)) {
+	if (EXT3_I(inode)->i_state & EXT3_STATE_JDATA) {
 		/* 
 		 * This is a REALLY heavyweight approach, but the use of
 		 * bmap on dirty files is expected to be extremely rare:
@@ -1159,6 +1185,7 @@
 		 * everything they get.
 		 */
 		
+		EXT3_I(inode)->i_state &= ~EXT3_STATE_JDATA;
 		journal = EXT3_JOURNAL(inode);
 		journal_lock_updates(journal);
 		err = journal_flush(journal);
@@ -2203,7 +2230,7 @@
 	/* If we are not tracking these fields in the in-memory inode,
 	 * then preserve them on disk, but still initialise them to zero
 	 * for new inodes. */
-	if (inode->u.ext3_i.i_state & EXT3_STATE_NEW) {
+	if (EXT3_I(inode)->i_state & EXT3_STATE_NEW) {
 		raw_inode->i_faddr = 0;
 		raw_inode->i_frag = 0;
 		raw_inode->i_fsize = 0;
@@ -2249,7 +2276,7 @@
 	rc = ext3_journal_dirty_metadata(handle, bh);
 	if (!err)
 		err = rc;
-	inode->u.ext3_i.i_state &= ~EXT3_STATE_NEW;
+	EXT3_I(inode)->i_state &= ~EXT3_STATE_NEW;
 
 out_brelse:
 	brelse (bh);
@@ -2333,12 +2360,20 @@
 int ext3_setattr(struct dentry *dentry, struct iattr *attr)
 {
 	struct inode *inode = dentry->d_inode;
-	int error, rc;
+	int error, rc = 0;
+	const unsigned int ia_valid = attr->ia_valid;
 
 	error = inode_change_ok(inode, attr);
 	if (error)
 		return error;
-	
+
+	if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) ||
+		(ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) {
+		error = DQUOT_TRANSFER(inode, attr) ? -EDQUOT : 0;
+		if (error)
+			return error;
+	}
+
 	if (attr->ia_valid & ATTR_SIZE && attr->ia_size < inode->i_size) {
 		handle_t *handle;
 
@@ -2356,7 +2391,7 @@
 		ext3_journal_stop(handle, inode);
 	}
 	
-	inode_setattr(inode, attr);
+	rc = inode_setattr(inode, attr);
 
 	/* If inode_setattr's call to ext3_truncate failed to get a
 	 * transaction handle at all, we need to clean up the in-core
@@ -2366,7 +2401,9 @@
 
 err_out:
 	ext3_std_error(inode->i_sb, error);
-	return 0;
+	if (!error)
+		error = rc;
+	return error;
 }
 
 
@@ -2667,6 +2704,3 @@
  * here, in ext3_aops_journal_start() to ensure that the forthcoming "see if we
  * need to extend" test in ext3_prepare_write() succeeds.  
  */
-
-
-MODULE_LICENSE("GPL");

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)