Release 4.10 fs/ocfs2/file.c
/* -*- mode: c; c-basic-offset: 8; -*-
* vim: noexpandtab sw=8 ts=8 sts=0:
*
* file.c
*
* File open, close, extend, truncate
*
* Copyright (C) 2002, 2004 Oracle. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 021110-1307, USA.
*/
#include <linux/capability.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/highmem.h>
#include <linux/pagemap.h>
#include <linux/uio.h>
#include <linux/sched.h>
#include <linux/splice.h>
#include <linux/mount.h>
#include <linux/writeback.h>
#include <linux/falloc.h>
#include <linux/quotaops.h>
#include <linux/blkdev.h>
#include <linux/backing-dev.h>
#include <cluster/masklog.h>
#include "ocfs2.h"
#include "alloc.h"
#include "aops.h"
#include "dir.h"
#include "dlmglue.h"
#include "extent_map.h"
#include "file.h"
#include "sysfile.h"
#include "inode.h"
#include "ioctl.h"
#include "journal.h"
#include "locks.h"
#include "mmap.h"
#include "suballoc.h"
#include "super.h"
#include "xattr.h"
#include "acl.h"
#include "quota.h"
#include "refcounttree.h"
#include "ocfs2_trace.h"
#include "buffer_head_io.h"
static int ocfs2_init_file_private(struct inode *inode, struct file *file)
{
struct ocfs2_file_private *fp;
fp = kzalloc(sizeof(struct ocfs2_file_private), GFP_KERNEL);
if (!fp)
return -ENOMEM;
fp->fp_file = file;
mutex_init(&fp->fp_mutex);
ocfs2_file_lock_res_init(&fp->fp_flock, fp);
file->private_data = fp;
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
mark fasheh | mark fasheh | 76 | 100.00% | 1 | 100.00% |
| Total | 76 | 100.00% | 1 | 100.00% |
static void ocfs2_free_file_private(struct inode *inode, struct file *file)
{
struct ocfs2_file_private *fp = file->private_data;
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
if (fp) {
ocfs2_simple_drop_lockres(osb, &fp->fp_flock);
ocfs2_lock_res_free(&fp->fp_flock);
kfree(fp);
file->private_data = NULL;
}
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
mark fasheh | mark fasheh | 72 | 100.00% | 1 | 100.00% |
| Total | 72 | 100.00% | 1 | 100.00% |
static int ocfs2_file_open(struct inode *inode, struct file *file)
{
int status;
int mode = file->f_flags;
struct ocfs2_inode_info *oi = OCFS2_I(inode);
trace_ocfs2_file_open(inode, file, file->f_path.dentry,
(unsigned long long)OCFS2_I(inode)->ip_blkno,
file->f_path.dentry->d_name.len,
file->f_path.dentry->d_name.name, mode);
if (file->f_mode & FMODE_WRITE) {
status = dquot_initialize(inode);
if (status)
goto leave;
}
spin_lock(&oi->ip_lock);
/* Check that the inode hasn't been wiped from disk by another
* node. If it hasn't then we're safe as long as we hold the
* spin lock until our increment of open count. */
if (OCFS2_I(inode)->ip_flags & OCFS2_INODE_DELETED) {
spin_unlock(&oi->ip_lock);
status = -ENOENT;
goto leave;
}
if (mode & O_DIRECT)
oi->ip_flags |= OCFS2_INODE_OPEN_DIRECT;
oi->ip_open_count++;
spin_unlock(&oi->ip_lock);
status = ocfs2_init_file_private(inode, file);
if (status) {
/*
* We want to set open count back if we're failing the
* open.
*/
spin_lock(&oi->ip_lock);
oi->ip_open_count--;
spin_unlock(&oi->ip_lock);
}
leave:
return status;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
mark fasheh | mark fasheh | 161 | 75.94% | 2 | 28.57% |
tao ma | tao ma | 21 | 9.91% | 1 | 14.29% |
christoph hellwig | christoph hellwig | 13 | 6.13% | 2 | 28.57% |
jan kara | jan kara | 11 | 5.19% | 1 | 14.29% |
josef sipek | josef sipek | 6 | 2.83% | 1 | 14.29% |
| Total | 212 | 100.00% | 7 | 100.00% |
static int ocfs2_file_release(struct inode *inode, struct file *file)
{
struct ocfs2_inode_info *oi = OCFS2_I(inode);
spin_lock(&oi->ip_lock);
if (!--oi->ip_open_count)
oi->ip_flags &= ~OCFS2_INODE_OPEN_DIRECT;
trace_ocfs2_file_release(inode, file, file->f_path.dentry,
oi->ip_blkno,
file->f_path.dentry->d_name.len,
file->f_path.dentry->d_name.name,
oi->ip_open_count);
spin_unlock(&oi->ip_lock);
ocfs2_free_file_private(inode, file);
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
mark fasheh | mark fasheh | 66 | 61.11% | 2 | 50.00% |
tao ma | tao ma | 36 | 33.33% | 1 | 25.00% |
josef sipek | josef sipek | 6 | 5.56% | 1 | 25.00% |
| Total | 108 | 100.00% | 4 | 100.00% |
static int ocfs2_dir_open(struct inode *inode, struct file *file)
{
return ocfs2_init_file_private(inode, file);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
mark fasheh | mark fasheh | 24 | 100.00% | 1 | 100.00% |
| Total | 24 | 100.00% | 1 | 100.00% |
static int ocfs2_dir_release(struct inode *inode, struct file *file)
{
ocfs2_free_file_private(inode, file);
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
mark fasheh | mark fasheh | 26 | 100.00% | 1 | 100.00% |
| Total | 26 | 100.00% | 1 | 100.00% |
static int ocfs2_sync_file(struct file *file, loff_t start, loff_t end,
int datasync)
{
int err = 0;
struct inode *inode = file->f_mapping->host;
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
struct ocfs2_inode_info *oi = OCFS2_I(inode);
journal_t *journal = osb->journal->j_journal;
int ret;
tid_t commit_tid;
bool needs_barrier = false;
trace_ocfs2_sync_file(inode, file, file->f_path.dentry,
OCFS2_I(inode)->ip_blkno,
file->f_path.dentry->d_name.len,
file->f_path.dentry->d_name.name,
(unsigned long long)datasync);
if (ocfs2_is_hard_readonly(osb) || ocfs2_is_soft_readonly(osb))
return -EROFS;
err = filemap_write_and_wait_range(inode->i_mapping, start, end);
if (err)
return err;
commit_tid = datasync ? oi->i_datasync_tid : oi->i_sync_tid;
if (journal->j_flags & JBD2_BARRIER &&
!jbd2_trans_will_send_data_barrier(journal, commit_tid))
needs_barrier = true;
err = jbd2_complete_transaction(journal, commit_tid);
if (needs_barrier) {
ret = blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL);
if (!err)
err = ret;
}
if (err)
mlog_errno(err);
return (err < 0) ? -EIO : 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
darrick j. wong | darrick j. wong | 76 | 29.92% | 1 | 10.00% |
mark fasheh | mark fasheh | 74 | 29.13% | 1 | 10.00% |
josef bacik | josef bacik | 28 | 11.02% | 1 | 10.00% |
tao ma | tao ma | 21 | 8.27% | 2 | 20.00% |
younger liu | younger liu | 16 | 6.30% | 1 | 10.00% |
jan kara | jan kara | 16 | 6.30% | 1 | 10.00% |
joel becker | joel becker | 14 | 5.51% | 1 | 10.00% |
hisashi hifumi | hisashi hifumi | 5 | 1.97% | 1 | 10.00% |
christoph hellwig | christoph hellwig | 4 | 1.57% | 1 | 10.00% |
| Total | 254 | 100.00% | 10 | 100.00% |
int ocfs2_should_update_atime(struct inode *inode,
struct vfsmount *vfsmnt)
{
struct timespec now;
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
if (ocfs2_is_hard_readonly(osb) || ocfs2_is_soft_readonly(osb))
return 0;
if ((inode->i_flags & S_NOATIME) ||
((inode->i_sb->s_flags & MS_NODIRATIME) && S_ISDIR(inode->i_mode)))
return 0;
/*
* We can be called with no vfsmnt structure - NFSD will
* sometimes do this.
*
* Note that our action here is different than touch_atime() -
* if we can't tell whether this is a noatime mount, then we
* don't know whether to trust the value of s_atime_quantum.
*/
if (vfsmnt == NULL)
return 0;
if ((vfsmnt->mnt_flags & MNT_NOATIME) ||
((vfsmnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode)))
return 0;
if (vfsmnt->mnt_flags & MNT_RELATIME) {
if ((timespec_compare(&inode->i_atime, &inode->i_mtime) <= 0) ||
(timespec_compare(&inode->i_atime, &inode->i_ctime) <= 0))
return 1;
return 0;
}
now = current_time(inode);
if ((now.tv_sec - inode->i_atime.tv_sec <= osb->s_atime_quantum))
return 0;
else
return 1;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
tiger yang | tiger yang | 136 | 67.33% | 1 | 25.00% |
mark fasheh | mark fasheh | 62 | 30.69% | 2 | 50.00% |
deepa dinamani | deepa dinamani | 4 | 1.98% | 1 | 25.00% |
| Total | 202 | 100.00% | 4 | 100.00% |
int ocfs2_update_inode_atime(struct inode *inode,
struct buffer_head *bh)
{
int ret;
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
handle_t *handle;
struct ocfs2_dinode *di = (struct ocfs2_dinode *) bh->b_data;
handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS);
if (IS_ERR(handle)) {
ret = PTR_ERR(handle);
mlog_errno(ret);
goto out;
}
ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), bh,
OCFS2_JOURNAL_ACCESS_WRITE);
if (ret) {
mlog_errno(ret);
goto out_commit;
}
/*
* Don't use ocfs2_mark_inode_dirty() here as we don't always
* have i_mutex to guard against concurrent changes to other
* inode fields.
*/
inode->i_atime = current_time(inode);
di->i_atime = cpu_to_le64(inode->i_atime.tv_sec);
di->i_atime_nsec = cpu_to_le32(inode->i_atime.tv_nsec);
ocfs2_update_inode_fsync_trans(handle, inode, 0);
ocfs2_journal_dirty(handle, bh);
out_commit:
ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle);
out:
return ret;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
tiger yang | tiger yang | 88 | 48.35% | 1 | 14.29% |
mark fasheh | mark fasheh | 70 | 38.46% | 1 | 14.29% |
darrick j. wong | darrick j. wong | 9 | 4.95% | 1 | 14.29% |
jan kara | jan kara | 7 | 3.85% | 1 | 14.29% |
joel becker | joel becker | 4 | 2.20% | 2 | 28.57% |
deepa dinamani | deepa dinamani | 4 | 2.20% | 1 | 14.29% |
| Total | 182 | 100.00% | 7 | 100.00% |
int ocfs2_set_inode_size(handle_t *handle,
struct inode *inode,
struct buffer_head *fe_bh,
u64 new_i_size)
{
int status;
i_size_write(inode, new_i_size);
inode->i_blocks = ocfs2_inode_sector_count(inode);
inode->i_ctime = inode->i_mtime = current_time(inode);
status = ocfs2_mark_inode_dirty(handle, inode, fe_bh);
if (status < 0) {
mlog_errno(status);
goto bail;
}
bail:
return status;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
mark fasheh | mark fasheh | 82 | 95.35% | 3 | 75.00% |
deepa dinamani | deepa dinamani | 4 | 4.65% | 1 | 25.00% |
| Total | 86 | 100.00% | 4 | 100.00% |
int ocfs2_simple_size_update(struct inode *inode,
struct buffer_head *di_bh,
u64 new_i_size)
{
int ret;
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
handle_t *handle = NULL;
handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS);
if (IS_ERR(handle)) {
ret = PTR_ERR(handle);
mlog_errno(ret);
goto out;
}
ret = ocfs2_set_inode_size(handle, inode, di_bh,
new_i_size);
if (ret < 0)
mlog_errno(ret);
ocfs2_update_inode_fsync_trans(handle, inode, 0);
ocfs2_commit_trans(osb, handle);
out:
return ret;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
mark fasheh | mark fasheh | 101 | 86.32% | 3 | 60.00% |
darrick j. wong | darrick j. wong | 9 | 7.69% | 1 | 20.00% |
jan kara | jan kara | 7 | 5.98% | 1 | 20.00% |
| Total | 117 | 100.00% | 5 | 100.00% |
static int ocfs2_cow_file_pos(struct inode *inode,
struct buffer_head *fe_bh,
u64 offset)
{
int status;
u32 phys, cpos = offset >> OCFS2_SB(inode->i_sb)->s_clustersize_bits;
unsigned int num_clusters = 0;
unsigned int ext_flags = 0;
/*
* If the new offset is aligned to the range of the cluster, there is
* no space for ocfs2_zero_range_for_truncate to fill, so no need to
* CoW either.
*/
if ((offset & (OCFS2_SB(inode->i_sb)->s_clustersize - 1)) == 0)
return 0;
status = ocfs2_get_clusters(inode, cpos, &phys,
&num_clusters, &ext_flags);
if (status) {
mlog_errno(status);
goto out;
}
if (!(ext_flags & OCFS2_EXT_REFCOUNTED))
goto out;
return ocfs2_refcount_cow(inode, fe_bh, cpos, 1, cpos+1);
out:
return status;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
tao ma | tao ma | 140 | 100.00% | 1 | 100.00% |
| Total | 140 | 100.00% | 1 | 100.00% |
static int ocfs2_orphan_for_truncate(struct ocfs2_super *osb,
struct inode *inode,
struct buffer_head *fe_bh,
u64 new_i_size)
{
int status;
handle_t *handle;
struct ocfs2_dinode *di;
u64 cluster_bytes;
/*
* We need to CoW the cluster contains the offset if it is reflinked
* since we will call ocfs2_zero_range_for_truncate later which will
* write "0" from offset to the end of the cluster.
*/
status = ocfs2_cow_file_pos(inode, fe_bh, new_i_size);
if (status) {
mlog_errno(status);
return status;
}
/* TODO: This needs to actually orphan the inode in this
* transaction. */
handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS);
if (IS_ERR(handle)) {
status = PTR_ERR(handle);
mlog_errno(status);
goto out;
}
status = ocfs2_journal_access_di(handle, INODE_CACHE(inode), fe_bh,
OCFS2_JOURNAL_ACCESS_WRITE);
if (status < 0) {
mlog_errno(status);
goto out_commit;
}
/*
* Do this before setting i_size.
*/
cluster_bytes = ocfs2_align_bytes_to_clusters(inode->i_sb, new_i_size);
status = ocfs2_zero_range_for_truncate(inode, handle, new_i_size,
cluster_bytes);
if (status) {
mlog_errno(status);
goto out_commit;
}
i_size_write(inode, new_i_size);
inode->i_ctime = inode->i_mtime = current_time(inode);
di = (struct ocfs2_dinode *) fe_bh->b_data;
di->i_size = cpu_to_le64(new_i_size);
di->i_ctime = di->i_mtime = cpu_to_le64(inode->i_ctime.tv_sec);
di->i_ctime_nsec = di->i_mtime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec);
ocfs2_update_inode_fsync_trans(handle, inode, 0);
ocfs2_journal_dirty(handle, fe_bh);
out_commit:
ocfs2_commit_trans(osb, handle);
out:
return status;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
mark fasheh | mark fasheh | 231 | 84.31% | 5 | 50.00% |
tao ma | tao ma | 26 | 9.49% | 1 | 10.00% |
darrick j. wong | darrick j. wong | 9 | 3.28% | 1 | 10.00% |
joel becker | joel becker | 4 | 1.46% | 2 | 20.00% |
deepa dinamani | deepa dinamani | 4 | 1.46% | 1 | 10.00% |
| Total | 274 | 100.00% | 10 | 100.00% |
int ocfs2_truncate_file(struct inode *inode,
struct buffer_head *di_bh,
u64 new_i_size)
{
int status = 0;
struct ocfs2_dinode *fe = NULL;
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
/* We trust di_bh because it comes from ocfs2_inode_lock(), which
* already validated it */
fe = (struct ocfs2_dinode *) di_bh->b_data;
trace_ocfs2_truncate_file((unsigned long long)OCFS2_I(inode)->ip_blkno,
(unsigned long long)le64_to_cpu(fe->i_size),
(unsigned long long)new_i_size);
mlog_bug_on_msg(le64_to_cpu(fe->i_size) != i_size_read(inode),
"Inode %llu, inode i_size = %lld != di "
"i_size = %llu, i_flags = 0x%x\n",
(unsigned long long)OCFS2_I(inode)->ip_blkno,
i_size_read(inode),
(unsigned long long)le64_to_cpu(fe->i_size),
le32_to_cpu(fe->i_flags));
if (new_i_size > le64_to_cpu(fe->i_size)) {
trace_ocfs2_truncate_file_error(
(unsigned long long)le64_to_cpu(fe->i_size),
(unsigned long long)new_i_size);
status = -EINVAL;
mlog_errno(status);
goto bail;
}
down_write(&OCFS2_I(inode)->ip_alloc_sem);
ocfs2_resv_discard(&osb->osb_la_resmap,
&OCFS2_I(inode)->ip_la_data_resv);
/*
* The inode lock forced other nodes to sync and drop their
* pages, which (correctly) happens even if we have a truncate
* without allocation change - ocfs2 cluster sizes can be much
* greater than page size, so we have to truncate them
* anyway.
*/
unmap_mapping_range(inode->i_mapping, new_i_size + PAGE_SIZE - 1, 0, 1);
truncate_inode_pages(inode->i_mapping, new_i_size);
if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
status = ocfs2_truncate_inline(inode, di_bh, new_i_size,
i_size_read(inode), 1);
if (status)
mlog_errno(status);
goto bail_unlock_sem;
}
/* alright, we're going to need to do a full blown alloc size
* change. Orphan the inode so that recovery can complete the
* truncate if necessary. This does the task of marking
* i_size. */
status = ocfs2_orphan_for_truncate(osb, inode, di_bh, new_i_size);
if (status < 0) {
mlog_errno(status);
goto bail_unlock_sem;
}
status = ocfs2_commit_truncate(osb, inode, di_bh);
if (status < 0) {
mlog_errno(status);
goto bail_unlock_sem;
}
/* TODO: orphan dir cleanup here. */
bail_unlock_sem:
up_write(&OCFS2_I(inode)->ip_alloc_sem);
bail:
if (!status && OCFS2_I(inode)->ip_clusters == 0)
status = ocfs2_try_remove_refcount_tree(inode, di_bh);
return status;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
mark fasheh | mark fasheh | 338 | 87.56% | 8 | 80.00% |
tao ma | tao ma | 48 | 12.44% | 2 | 20.00% |
| Total | 386 | 100.00% | 10 | 100.00% |
/*
* extend file allocation only here.
* we'll update all the disk stuff, and oip->alloc_size
*
* expect stuff to be locked, a transaction started and enough data /
* metadata reservations in the contexts.
*
* Will return -EAGAIN, and a reason if a restart is needed.
* If passed in, *reason will always be set, even in error.
*/
int ocfs2_add_inode_data(struct ocfs2_super *osb,
struct inode *inode,
u32 *logical_offset,
u32 clusters_to_add,
int mark_unwritten,
struct buffer_head *fe_bh,
handle_t *handle,
struct ocfs2_alloc_context *data_ac,
struct ocfs2_alloc_context *meta_ac,
enum ocfs2_alloc_restarted *reason_ret)
{
int ret;
struct ocfs2_extent_tree et;
ocfs2_init_dinode_extent_tree(&et, INODE_CACHE(inode), fe_bh);
ret = ocfs2_add_clusters_in_btree(handle, &et, logical_offset,
clusters_to_add, mark_unwritten,
data_ac, meta_ac, reason_ret);
return ret;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
mark fasheh | mark fasheh | 60 | 63.83% | 5 | 45.45% |
joel becker | joel becker | 25 | 26.60% | 4 | 36.36% |
tao ma | tao ma | 9 | 9.57% | 2 | 18.18% |
| Total | 94 | 100.00% | 11 | 100.00% |
static int __ocfs2_extend_allocation(struct inode *inode, u32 logical_start,
u32 clusters_to_add, int mark_unwritten)
{
int status = 0;
int restart_func = 0;
int credits;
u32 prev_clusters;
struct buffer_head *bh = NULL;
struct ocfs2_dinode *fe = NULL;
handle_t *handle = NULL;
struct ocfs2_alloc_context *data_ac = NULL;
struct ocfs2_alloc_context *meta_ac = NULL;
enum ocfs2_alloc_restarted why = RESTART_NONE;
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
struct ocfs2_extent_tree et;
int did_quota = 0;
/*
* Unwritten extent only exists for file systems which
* support holes.
*/
BUG_ON(mark_unwritten && !ocfs2_sparse_alloc(osb));
status = ocfs2_read_inode_block(inode, &bh);
if (status < 0) {
mlog_errno(status);
goto leave;
}
fe = (struct ocfs2_dinode *) bh->b_data;
restart_all:
BUG_ON(le32_to_cpu(fe->i_clusters) != OCFS2_I(inode)->ip_clusters);
ocfs2_init_dinode_extent_tree(&et, INODE_CACHE(inode), bh);
status = ocfs2_lock_allocators(inode, &et, clusters_to_add, 0,
&data_ac, &meta_ac);
if (status) {
mlog_errno(status);
goto leave;
}
credits = ocfs2_calc_extend_credits(osb->sb, &fe->id2.i_list);
handle = ocfs2_start_trans(osb, credits);
if (IS_ERR(handle)) {
status = PTR_ERR(handle);
handle = NULL;
mlog_errno(status);
goto leave;
}
restarted_transaction:
trace_ocfs2_extend_allocation(
(unsigned long long)OCFS2_I(inode)->ip_blkno,
(unsigned long long)i_size_read(inode),
le32_to_cpu(fe->i_clusters), clusters_to_add,
why, restart_func);
status = dquot_alloc_space_nodirty(inode,
ocfs2_clusters_to_bytes(osb->sb, clusters_to_add));
if (status)
goto leave;
did_quota = 1;
/* reserve a write to the file entry early on - that we if we
* run out of credits in the allocation path, we can still
* update i_size. */
status = ocfs2_journal_access_di(handle, INODE_CACHE(inode), bh,
OCFS2_JOURNAL_ACCESS_WRITE);
if (status < 0) {
mlog_errno(status);
goto leave;
}
prev_clusters = OCFS2_I(inode)->ip_clusters;
status = ocfs2_add_inode_data(osb,
inode,
&logical_start,
clusters_to_add,
mark_unwritten,
bh,
handle,
data_ac,
meta_ac,
&why);
if ((status < 0) && (status != -EAGAIN)) {
if (status != -ENOSPC)
mlog_errno(status);
goto leave;
}
ocfs2_update_inode_fsync_trans(handle, inode, 1);
ocfs2_journal_dirty(handle, bh);
spin_lock(&OCFS2_I(inode)->ip_lock);
clusters_to_add -= (OCFS2_I(inode)->ip_clusters - prev_clusters);
spin_unlock(&OCFS2_I(inode)->ip_lock);
/* Release unused quota reservation */
dquot_free_space(inode,
ocfs2_clusters_to_bytes(osb->sb, clusters_to_add));
did_quota = 0;
if (why != RESTART_NONE && clusters_to_add) {
if (why == RESTART_META) {
restart_func = 1;
status = 0;
} else {
BUG_ON(why != RESTART_TRANS);
status = ocfs2_allocate_extend_trans(handle, 1);
if (status < 0) {
/* handle still has to be committed at
* this point. */
status = -ENOMEM;
mlog_errno(status);
goto