[Ocfs2-commits] mfasheh commits r1922 - trunk/fs/ocfs2
svn-commits at oss.oracle.com
svn-commits at oss.oracle.com
Mon Feb 28 18:20:51 CST 2005
Author: mfasheh
Signed-off-by: zab
Date: 2005-02-28 18:20:50 -0600 (Mon, 28 Feb 2005)
New Revision: 1922
Modified:
trunk/fs/ocfs2/file.c
trunk/fs/ocfs2/file.h
Log:
* deal with out of space errors more gracefully.
Signed-off-by: zab
Modified: trunk/fs/ocfs2/file.c
===================================================================
--- trunk/fs/ocfs2/file.c 2005-03-01 00:06:48 UTC (rev 1921)
+++ trunk/fs/ocfs2/file.c 2005-03-01 00:20:50 UTC (rev 1922)
@@ -66,6 +66,11 @@
ocfs2_dinode *fe,
u64 new_size);
+static int ocfs_extend_file(ocfs_super *osb,
+ struct inode *inode,
+ u64 new_i_size,
+ u64 *bytes_extended);
+
int ocfs_sync_inode(struct inode *inode)
{
filemap_fdatawrite(inode->i_mapping);
@@ -174,6 +179,16 @@
return (err < 0) ? -EIO : 0;
} /* ocfs_sync_file */
+static void ocfs2_update_inode_size(struct inode *inode,
+ u64 new_size)
+{
+ struct super_block *sb = inode->i_sb;
+
+ i_size_write(inode, new_size);
+ inode->i_blocks = (new_size + sb->s_blocksize - 1) >>
+ sb->s_blocksize_bits;
+}
+
/*
* ocfs_file_write()
* Linux 2.6 TODO: Remove all O_DIRECT conditionals here, they are no longer
@@ -188,8 +203,7 @@
struct dentry *dentry = filp->f_dentry;
struct inode *inode = dentry->d_inode;
int status;
- u64 newsize;
- struct super_block *sb = inode->i_sb;
+ u64 newsize, bytes_added = 0;
int do_direct_io = 0;
int sector_size;
int have_i_sem = 0;
@@ -305,20 +319,34 @@
"i_size=%llu, need=%llu\n",
i_size_read(inode), newsize);
- status = ocfs_extend_file(osb, inode, newsize);
- if (status < 0) {
+ /* If we extend AT ALL here then we update our state
+ * and continue the write call, regardless of error --
+ * this is basically a short write. */
+ status = ocfs_extend_file(osb, inode, newsize, &bytes_added);
+ if (status < 0 && (!bytes_added)) {
if (status != -EINTR && status != -ENOSPC) {
LOG_ERROR_STATUS (status);
- LOG_ERROR_ARGS ("Failed to extend file from "
- "%llu to %llu",
- *ppos, newsize);
- ret = -ENOSPC;
- } else
- ret = status;
-
- ocfs2_meta_unlock(inode, level);
+ LOG_ERROR_ARGS("Failed to extend inode %llu "
+ "from %llu to %llu",
+ OCFS_I(inode)->ip_blkno,
+ *ppos, newsize);
+ }
+ ret = status;
goto bail_unlock;
}
+
+ /* We need to recalulate newsize and count according
+ * to what extend could give us. If we got the whole
+ * extend then this doesn't wind up changing the
+ * values. */
+ newsize = i_size_read(inode) + bytes_added;
+ count = newsize - saved_ppos;
+
+ if (status < 0 && status != -ENOSPC && status != -EINTR)
+ LOG_ERROR_ARGS("status return of %d extending inode "
+ "%llu\n", status,
+ OCFS_I(inode)->ip_blkno);
+ status = 0;
}
/* we've got whatever cluster lock is appropriate now, so we
@@ -332,6 +360,14 @@
LOG_ERROR_STATUS(status);
ret = status;
+ /* The write context stuff needs to be updated
+ * to understand that we haven't locked for
+ * data so that we can just jump down to the
+ * generic zeroing code here instead. */
+ if (extended) {
+ ocfs2_update_inode_size(inode, newsize);
+ OCFS_I(inode)->ip_mmu_private = newsize;
+ }
ocfs2_meta_unlock(inode, level);
goto bail_unlock;
}
@@ -347,7 +383,7 @@
if (ret < 0) {
if (ret != -EINTR)
LOG_ERROR_STATUS(ret);
- goto bail_unlock;
+ goto bail_zero;
}
down_read(&OCFS_I(inode)->ip_alloc_sem);
@@ -378,11 +414,12 @@
#endif
up_read(&OCFS_I(inode)->ip_alloc_sem);
+bail_zero:
if (extended) {
LOG_TRACE_STR
("Generic_file_write ok, asking for OIN update now");
- i_size_write(inode, newsize);
- inode->i_blocks = (newsize + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
+ ocfs2_update_inode_size(inode, newsize);
+
if (do_direct_io) {
/*
* This leaves dirty data in holes.
@@ -867,10 +904,15 @@
*
* Ok, this function is heavy on the goto's - we need to clean it up a
* bit.
+ *
+ * *bytes_extended is a measure of how much was added to
+ * dinode->i_size, NOT how much allocated was actually added to the
+ * file. It will always be correct, even when we return an error.
*/
-int ocfs_extend_file(ocfs_super *osb,
- struct inode *inode,
- u64 new_i_size)
+static int ocfs_extend_file(ocfs_super *osb,
+ struct inode *inode,
+ u64 new_i_size,
+ u64 *bytes_extended)
{
int status = 0;
int restart_func = 0;
@@ -879,6 +921,7 @@
int credits, num_free_extents;
unsigned int overalloc_bits = 0;
u32 clusters_to_add;
+ u64 new_fe_size;
struct buffer_head *bh = NULL;
ocfs2_dinode *fe;
ocfs_journal_handle *handle = NULL;
@@ -888,6 +931,8 @@
LOG_ENTRY_ARGS("(new_i_size=%llu)\n", new_i_size);
+ *bytes_extended = 0;
+
/* setattr sometimes calls us like this. */
if (new_i_size == 0)
goto leave;
@@ -908,7 +953,7 @@
fe = (ocfs2_dinode *) bh->b_data;
OCFS_ASSERT(IS_VALID_FILE_ENTRY(fe));
- OCFS_ASSERT(i_size_read(inode) == fe->i_size);
+ OCFS_ASSERT(i_size_read(inode) == (fe->i_size - *bytes_extended));
OCFS_ASSERT(new_i_size >= i_size_read(inode));
if (i_size_read(inode) == new_i_size)
@@ -1019,11 +1064,13 @@
} else {
OCFS_ASSERT(why == RESTART_TRANS);
+ new_fe_size = ocfs2_clusters_to_bytes(osb->sb,
+ fe->i_clusters);
+ *bytes_extended += new_fe_size - fe->i_size;
/* update i_size in case we crash after the
* extend_trans */
- fe->i_size =
- ocfs2_clusters_to_bytes(osb->sb,
- fe->i_clusters);
+ fe->i_size = new_fe_size;
+
fe->i_mtime = OCFS_CURRENT_TIME;
status = ocfs_journal_dirty(handle, bh);
@@ -1056,11 +1103,13 @@
no_alloc:
/* this may not be the end of our allocation so only update
* i_size to what's appropriate. */
- if (new_i_size > ocfs2_clusters_to_bytes(osb->sb, fe->i_clusters))
- fe->i_size = ocfs2_clusters_to_bytes(osb->sb, fe->i_clusters);
- else
- fe->i_size = new_i_size;
+ new_fe_size = ocfs2_clusters_to_bytes(osb->sb, fe->i_clusters);
+ if (new_i_size < new_fe_size)
+ new_fe_size = new_i_size;
+ *bytes_extended += new_fe_size - fe->i_size;
+ fe->i_size = new_fe_size;
+
LOG_TRACE_ARGS("fe: i_clusters = %u, i_size=%llu\n",
fe->i_clusters, fe->i_size);
@@ -1100,6 +1149,7 @@
restart_func = 0;
goto restart_all;
}
+
LOG_EXIT_STATUS (status);
return status;
} /* ocfs_extend_file */
@@ -1112,7 +1162,7 @@
{
int status = 0;
int unlock = 0;
- u64 newsize;
+ u64 newsize, bytes_added;
struct inode *inode = dentry->d_inode;
struct super_block *sb = inode->i_sb;
ocfs_super *osb = OCFS2_SB(sb);
@@ -1156,19 +1206,32 @@
if (attr->ia_valid & ATTR_SIZE &&
newsize != i_size_read(inode)) {
+ bytes_added = 0;
+
if (i_size_read(inode) > newsize)
status = ocfs_truncate_file(osb, newsize, inode);
else
- status = ocfs_extend_file(osb, inode, newsize);
- if (status < 0) {
+ status = ocfs_extend_file(osb, inode, newsize,
+ &bytes_added);
+ if (status < 0 && (!bytes_added)) {
if (status != -EINTR && status != -ENOSPC)
LOG_ERROR_STATUS(status);
status = -ENOSPC;
goto bail;
}
+
+ /* partial extend, we continue with what we've got. */
+ if (status < 0 && status != -ENOSPC && status != -EINTR)
+ LOG_ERROR_ARGS("status return of %d extending inode "
+ "%llu\n", status,
+ OCFS_I(inode)->ip_blkno);
+ status = 0;
+
+ newsize = bytes_added + i_size_read(inode);
+ if (bytes_added)
+ ocfs2_update_inode_size(inode, newsize);
+
spin_lock(&OCFS_I(inode)->ip_lock);
- i_size_write(inode, newsize);
- inode->i_blocks = (newsize + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
if (OCFS_I(inode)->ip_flags & OCFS_INODE_OPEN_DIRECT) {
/* This is a total broken hack for O_DIRECT crack */
OCFS_I(inode)->ip_mmu_private = i_size_read(inode);
Modified: trunk/fs/ocfs2/file.h
===================================================================
--- trunk/fs/ocfs2/file.h 2005-03-01 00:06:48 UTC (rev 1921)
+++ trunk/fs/ocfs2/file.h 2005-03-01 00:20:50 UTC (rev 1922)
@@ -43,9 +43,6 @@
struct _ocfs2_alloc_context *data_ac,
struct _ocfs2_alloc_context *meta_ac,
enum ocfs2_alloc_restarted *reason);
-int ocfs_extend_file(ocfs_super *osb,
- struct inode *inode,
- u64 new_i_size);
int ocfs_setattr(struct dentry *dentry, struct iattr *attr);
int ocfs_sync_inode(struct inode *inode);
More information about the Ocfs2-commits
mailing list