📄 file.c
字号:
size >> PAGE_CACHE_SHIFT); if (!page) { res = -ENOMEM; mlog_errno(res); return res; } offset = (unsigned int)(size & (PAGE_CACHE_SIZE - 1)) + 1; res = mapping->a_ops->prepare_write(NULL, page, offset, offset); if (res < 0) { mlog_errno(res); goto bail_unlock; } res = mapping->a_ops->commit_write(NULL, page, offset, offset); if (res < 0) mlog_errno(res);bail_unlock: unlock_page(page); page_cache_release(page); mark_inode_dirty(inode); } return res;}/* * extend 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. I'll return -EAGAIN, if we * run out of transaction credits, so the caller can restart us. */int ocfs2_extend_allocation(struct ocfs2_super *osb, struct inode *inode, u32 clusters_to_add, struct buffer_head *fe_bh, struct ocfs2_journal_handle *handle, struct ocfs2_alloc_context *data_ac, struct ocfs2_alloc_context *meta_ac, enum ocfs2_alloc_restarted *reason){ int status = 0; int free_extents; struct ocfs2_dinode *fe = (struct ocfs2_dinode *) fe_bh->b_data; u32 bit_off, num_bits; u64 block; BUG_ON(!clusters_to_add); free_extents = ocfs2_num_free_extents(osb, inode, fe); if (free_extents < 0) { status = free_extents; mlog_errno(status); goto leave; } /* there are two cases which could cause us to EAGAIN in the * we-need-more-metadata case: * 1) we haven't reserved *any* * 2) we are so fragmented, we've needed to add metadata too * many times. */ if (!free_extents && !meta_ac) { mlog(0, "we haven't reserved any metadata!\n"); status = -EAGAIN; if (reason) *reason = RESTART_META; goto leave; } else if ((!free_extents) && (ocfs2_alloc_context_bits_left(meta_ac) < ocfs2_extend_meta_needed(fe))) { mlog(0, "filesystem is really fragmented...\n"); status = -EAGAIN; if (reason) *reason = RESTART_META; goto leave; } status = ocfs2_claim_clusters(osb, handle, data_ac, 1, &bit_off, &num_bits); if (status < 0) { if (status != -ENOSPC) mlog_errno(status); goto leave; } BUG_ON(num_bits > clusters_to_add); /* reserve our write early -- insert_extent may update the inode */ status = ocfs2_journal_access(handle, inode, fe_bh, OCFS2_JOURNAL_ACCESS_WRITE); if (status < 0) { mlog_errno(status); goto leave; } block = ocfs2_clusters_to_blocks(osb->sb, bit_off); mlog(0, "Allocating %u clusters at block %u for inode %"MLFu64"\n", num_bits, bit_off, OCFS2_I(inode)->ip_blkno); status = ocfs2_insert_extent(osb, handle, inode, fe_bh, block, num_bits, meta_ac); if (status < 0) { mlog_errno(status); goto leave; } le32_add_cpu(&fe->i_clusters, num_bits); spin_lock(&OCFS2_I(inode)->ip_lock); OCFS2_I(inode)->ip_clusters = le32_to_cpu(fe->i_clusters); spin_unlock(&OCFS2_I(inode)->ip_lock); status = ocfs2_journal_dirty(handle, fe_bh); if (status < 0) { mlog_errno(status); goto leave; } clusters_to_add -= num_bits; if (clusters_to_add) { mlog(0, "need to alloc once more, clusters = %u, wanted = " "%u\n", fe->i_clusters, clusters_to_add); status = -EAGAIN; if (reason) *reason = RESTART_TRANS; }leave: mlog_exit(status); return status;}/* * 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 ocfs2_extend_file(struct ocfs2_super *osb, struct inode *inode, u64 new_i_size, u64 *bytes_extended){ int status = 0; int restart_func = 0; int drop_alloc_sem = 0; int credits, num_free_extents; u32 clusters_to_add; u64 new_fe_size; struct buffer_head *bh = NULL; struct ocfs2_dinode *fe; struct ocfs2_journal_handle *handle = NULL; struct ocfs2_alloc_context *data_ac = NULL; struct ocfs2_alloc_context *meta_ac = NULL; enum ocfs2_alloc_restarted why; mlog_entry("(Inode %"MLFu64" new_i_size=%"MLFu64")\n", OCFS2_I(inode)->ip_blkno, new_i_size); *bytes_extended = 0; /* setattr sometimes calls us like this. */ if (new_i_size == 0) goto leave;restart_all: handle = ocfs2_alloc_handle(osb); if (handle == NULL) { status = -ENOMEM; mlog_errno(status); goto leave; } status = ocfs2_read_block(osb, OCFS2_I(inode)->ip_blkno, &bh, OCFS2_BH_CACHED, inode); if (status < 0) { mlog_errno(status); goto leave; } fe = (struct ocfs2_dinode *) bh->b_data; if (!OCFS2_IS_VALID_DINODE(fe)) { OCFS2_RO_ON_INVALID_DINODE(inode->i_sb, fe); status = -EIO; goto leave; } mlog_bug_on_msg(i_size_read(inode) != (le64_to_cpu(fe->i_size) - *bytes_extended), "Inode %"MLFu64" i_size = %lld, dinode i_size " "= %"MLFu64", bytes_extended = %"MLFu64", new_i_size " "= %"MLFu64"\n", OCFS2_I(inode)->ip_blkno, i_size_read(inode), le64_to_cpu(fe->i_size), *bytes_extended, new_i_size); mlog_bug_on_msg(new_i_size < i_size_read(inode), "Inode %"MLFu64", i_size = %lld, new sz = %"MLFu64"\n", OCFS2_I(inode)->ip_blkno, i_size_read(inode), new_i_size); if (i_size_read(inode) == new_i_size) goto leave; clusters_to_add = ocfs2_clusters_for_bytes(osb->sb, new_i_size) - le32_to_cpu(fe->i_clusters); mlog(0, "extend inode %"MLFu64", new_i_size = %"MLFu64", " "i_size = %lld, fe->i_clusters = %u, clusters_to_add = %u\n", OCFS2_I(inode)->ip_blkno, new_i_size, i_size_read(inode), fe->i_clusters, clusters_to_add); if (!clusters_to_add) goto do_start_trans; num_free_extents = ocfs2_num_free_extents(osb, inode, fe); if (num_free_extents < 0) { status = num_free_extents; mlog_errno(status); goto leave; } if (!num_free_extents) { status = ocfs2_reserve_new_metadata(osb, handle, fe, &meta_ac); if (status < 0) { if (status != -ENOSPC) mlog_errno(status); goto leave; } } status = ocfs2_reserve_clusters(osb, handle, clusters_to_add, &data_ac); if (status < 0) { if (status != -ENOSPC) mlog_errno(status); goto leave; } /* blocks peope in read/write from reading our allocation * until we're done changing it. We depend on i_mutex to block * other extend/truncate calls while we're here. Ordering wrt * start_trans is important here -- always do it before! */ down_write(&OCFS2_I(inode)->ip_alloc_sem); drop_alloc_sem = 1;do_start_trans: credits = ocfs2_calc_extend_credits(osb->sb, fe, clusters_to_add); handle = ocfs2_start_trans(osb, handle, credits); if (IS_ERR(handle)) { status = PTR_ERR(handle); handle = NULL; mlog_errno(status); goto leave; }restarted_transaction: /* 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(handle, inode, bh, OCFS2_JOURNAL_ACCESS_WRITE); if (status < 0) { mlog_errno(status); goto leave; } if (!clusters_to_add) goto no_alloc; status = ocfs2_extend_allocation(osb, inode, clusters_to_add, bh, handle, data_ac, meta_ac, &why); if ((status < 0) && (status != -EAGAIN)) { if (status != -ENOSPC) mlog_errno(status); goto leave; } if (status == -EAGAIN && (new_i_size > ocfs2_clusters_to_bytes(osb->sb, le32_to_cpu(fe->i_clusters)))) { if (why == RESTART_META) { mlog(0, "Inode %"MLFu64" restarting function.\n", OCFS2_I(inode)->ip_blkno); restart_func = 1; } else { BUG_ON(why != RESTART_TRANS); new_fe_size = ocfs2_clusters_to_bytes(osb->sb, le32_to_cpu(fe->i_clusters)); *bytes_extended += new_fe_size - le64_to_cpu(fe->i_size); /* update i_size in case we crash after the * extend_trans */ fe->i_size = cpu_to_le64(new_fe_size); fe->i_mtime = cpu_to_le64(CURRENT_TIME.tv_sec); fe->i_mtime_nsec = cpu_to_le32(CURRENT_TIME.tv_nsec); status = ocfs2_journal_dirty(handle, bh); if (status < 0) { mlog_errno(status); goto leave; } clusters_to_add = ocfs2_clusters_for_bytes(osb->sb, new_i_size) - le32_to_cpu(fe->i_clusters); mlog(0, "Inode %"MLFu64" restarting transaction.\n", OCFS2_I(inode)->ip_blkno); /* TODO: This can be more intelligent. */ credits = ocfs2_calc_extend_credits(osb->sb, fe, clusters_to_add); status = ocfs2_extend_trans(handle, credits); if (status < 0) { /* handle still has to be committed at * this point. */ status = -ENOMEM; mlog_errno(status); goto leave; } goto restarted_transaction; } } status = 0;no_alloc: /* this may not be the end of our allocation so only update * i_size to what's appropriate. */ new_fe_size = ocfs2_clusters_to_bytes(osb->sb, le32_to_cpu(fe->i_clusters)); if (new_i_size < new_fe_size) new_fe_size = new_i_size; *bytes_extended += new_fe_size - le64_to_cpu(fe->i_size); fe->i_size = cpu_to_le64(new_fe_size); mlog(0, "fe: i_clusters = %u, i_size=%"MLFu64"\n", le32_to_cpu(fe->i_clusters), le64_to_cpu(fe->i_size)); mlog(0, "inode: ip_clusters=%u, i_size=%lld\n", OCFS2_I(inode)->ip_clusters, i_size_read(inode)); fe->i_ctime = fe->i_mtime = cpu_to_le64(CURRENT_TIME.tv_sec); fe->i_ctime_nsec = fe->i_mtime_nsec = cpu_to_le32(CURRENT_TIME.tv_nsec); status = ocfs2_journal_dirty(handle, bh); if (status < 0) { mlog_errno(status); goto leave; }leave: if (drop_alloc_sem) { up_write(&OCFS2_I(inode)->ip_alloc_sem); drop_alloc_sem = 0; } if (handle) { ocfs2_commit_trans(handle); handle = NULL; } if (data_ac) { ocfs2_free_alloc_context(data_ac); data_ac = NULL; } if (meta_ac) { ocfs2_free_alloc_context(meta_ac); meta_ac = NULL; } if (bh) { brelse(bh); bh = NULL; } if ((!status) && restart_func) { restart_func = 0; goto restart_all; } mlog_exit(status); return status;}static int ocfs2_setattr_newsize(struct ocfs2_super *osb, struct inode *inode, u64 newsize){ u64 bytes_added = 0; u64 actual_size; int tmp_status; int status; if (i_size_read(inode) > newsize) { status = ocfs2_truncate_file(osb, newsize, inode); /* should this be translating errnos to enospc? it * used to.. */ if (status < 0 && status != -ENOSPC) mlog_errno(status); /* _truncate_file calls _set_file_size which updates * mmu_private and i_size, we're done.. */ goto out; } /* * protect the pages that ocfs2_zero_extend is going to * be pulling into the page cache.. we do this before the * metadata extend so that we don't get into the situation * where we've extended the metadata but can't get the data * lock to zero. */ status = ocfs2_data_lock(inode, 1); if (status < 0) { mlog_errno(status); goto out; } status = ocfs2_extend_file(osb, inode, newsize, &bytes_added); if (status < 0 && (!bytes_added)) { if (status != -ENOSPC) mlog_errno(status); status = -ENOSPC; goto out_unlock; } /* partial extend, we continue with what we've got. */ if (status < 0 && status != -ENOSPC && status != -EINTR && status != -ERESTARTSYS) mlog(ML_ERROR, "status return of %d extending inode " "%"MLFu64"\n", status, OCFS2_I(inode)->ip_blkno); actual_size = bytes_added + i_size_read(inode); if ((newsize > actual_size) && (status == 0)) status = -ENOSPC; if (bytes_added) ocfs2_update_inode_size(inode, actual_size);#ifdef OCFS2_ORACORE_WORKAROUNDS spin_lock(&OCFS2_I(inode)->ip_lock); if (OCFS2_I(inode)->ip_flags & OCFS2_INODE_OPEN_DIRECT) { /* This is a total broken hack for O_DIRECT crack */ OCFS2_I(inode)->ip_mmu_private = i_size_read(inode); } spin_unlock(&OCFS2_I(inode)->ip_lock);#endif tmp_status = status; status = ocfs2_zero_extend(inode); if (status < 0) mlog_errno(status); if (tmp_status < 0) status = tmp_status;out_unlock: ocfs2_data_unlock(inode, 1);out: return status;}int ocfs2_setattr(struct dentry *dentry, struct iattr *attr){ int status = 0; u64 newsize; struct inode *inode = dentry->d_inode; struct super_block *sb = inode->i_sb; struct ocfs2_super *osb = OCFS2_SB(sb); struct buffer_head *bh = NULL; struct ocfs2_journal_handle *handle = NULL; mlog_entry("(0x%p, '%.*s', inode %"MLFu64")\n", dentry, dentry->d_name.len, dentry->d_name.name, OCFS2_I(inode)->ip_blkno); if (attr->ia_valid & ATTR_MODE) mlog(0, "mode change: %d\n", attr->ia_mode); if (attr->ia_valid & ATTR_UID) mlog(0, "uid change: %d\n", attr->ia_uid); if (attr->ia_valid & ATTR_GID) mlog(0, "gid change: %d\n", attr->ia_gid); if (attr->ia_valid & ATTR_SIZE) mlog(0, "size change...\n"); if (attr->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_CTIME)) mlog(0, "time change...\n");#define OCFS2_VALID_ATTRS (ATTR_ATIME | ATTR_MTIME | ATTR_CTIME | ATTR_SIZE \ | ATTR_GID | ATTR_UID | ATTR_MODE) if (!(attr->ia_valid & OCFS2_VALID_ATTRS)) { mlog(0, "can't handle attrs: 0x%x\n", attr->ia_valid); return 0; } status = inode_change_ok(inode, attr); if (status) return status; newsize = attr->ia_size; status = ocfs2_meta_lock(inode, NULL, &bh, 1); if (status < 0) { if (status != -ENOENT) mlog_errno(status); goto bail; } if (S_ISREG(inode->i_mode) && attr->ia_valid & ATTR_SIZE && newsize != i_size_read(inode)) { status = ocfs2_setattr_newsize(osb, inode, newsize); if (status < 0) goto bail_unlock; } handle = ocfs2_start_trans(osb, NULL, OCFS2_INODE_UPDATE_CREDITS); if (IS_ERR(handle)) { status = PTR_ERR(handle); mlog_errno(status); goto bail_unlock; } status = inode_setattr(inode, attr); if (status < 0) { mlog_errno(status); goto bail_commit; } status = ocfs2_mark_inode_dirty(handle, inode, bh); if (status < 0) mlog_errno(status);bail_commit: ocfs2_commit_trans(handle);bail_unlock: ocfs2_meta_unlock(inode, 1);bail: if (bh) brelse(bh); mlog_exit(status); return status;}int ocfs2_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat){ struct inode *inode = dentry->d_inode; struct super_block *sb = dentry->d_inode->i_sb; struct ocfs2_super *osb = sb->s_fs_info; int err; mlog_entry_void(); err = ocfs2_inode_revalidate(dentry); if (err) { if (err != -ENOENT) mlog_errno(err); goto bail; } generic_fillattr(inode, stat); /* We set the blksize from the cluster size for performance */ stat->blksize = osb->s_clustersize;bail: mlog_exit(err); return err;}struct inode_operations ocfs2_file_iops = { .setattr = ocfs2_setattr, .getattr = ocfs2_getattr,};struct inode_operations ocfs2_special_file_iops = { .setattr = ocfs2_setattr, .getattr = ocfs2_getattr,};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -