📄 file.c
字号:
out_update_size: ret = ocfs2_simple_size_update(inode, di_bh, new_i_size); if (ret < 0) mlog_errno(ret);out: return ret;}int ocfs2_setattr(struct dentry *dentry, struct iattr *attr){ int status = 0, size_change; 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; handle_t *handle = NULL; mlog_entry("(0x%p, '%.*s')\n", dentry, dentry->d_name.len, dentry->d_name.name); /* ensuring we don't even attempt to truncate a symlink */ if (S_ISLNK(inode->i_mode)) attr->ia_valid &= ~ATTR_SIZE; 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; size_change = S_ISREG(inode->i_mode) && attr->ia_valid & ATTR_SIZE; if (size_change) { status = ocfs2_rw_lock(inode, 1); if (status < 0) { mlog_errno(status); goto bail; } } status = ocfs2_inode_lock(inode, &bh, 1); if (status < 0) { if (status != -ENOENT) mlog_errno(status); goto bail_unlock_rw; } if (size_change && attr->ia_size != i_size_read(inode)) { if (attr->ia_size > sb->s_maxbytes) { status = -EFBIG; goto bail_unlock; } if (i_size_read(inode) > attr->ia_size) status = ocfs2_truncate_file(inode, bh, attr->ia_size); else status = ocfs2_extend_file(inode, bh, attr->ia_size); if (status < 0) { if (status != -ENOSPC) mlog_errno(status); status = -ENOSPC; goto bail_unlock; } } handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); if (IS_ERR(handle)) { status = PTR_ERR(handle); mlog_errno(status); goto bail_unlock; } /* * This will intentionally not wind up calling vmtruncate(), * since all the work for a size change has been done above. * Otherwise, we could get into problems with truncate as * ip_alloc_sem is used there to protect against i_size * changes. */ 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(osb, handle);bail_unlock: ocfs2_inode_unlock(inode, 1);bail_unlock_rw: if (size_change) ocfs2_rw_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;}int ocfs2_permission(struct inode *inode, int mask, struct nameidata *nd){ int ret; mlog_entry_void(); ret = ocfs2_inode_lock(inode, NULL, 0); if (ret) { if (ret != -ENOENT) mlog_errno(ret); goto out; } ret = generic_permission(inode, mask, NULL); ocfs2_inode_unlock(inode, 0);out: mlog_exit(ret); return ret;}static int __ocfs2_write_remove_suid(struct inode *inode, struct buffer_head *bh){ int ret; handle_t *handle; struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); struct ocfs2_dinode *di; mlog_entry("(Inode %llu, mode 0%o)\n", (unsigned long long)OCFS2_I(inode)->ip_blkno, inode->i_mode); handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); if (handle == NULL) { ret = -ENOMEM; mlog_errno(ret); goto out; } ret = ocfs2_journal_access(handle, inode, bh, OCFS2_JOURNAL_ACCESS_WRITE); if (ret < 0) { mlog_errno(ret); goto out_trans; } inode->i_mode &= ~S_ISUID; if ((inode->i_mode & S_ISGID) && (inode->i_mode & S_IXGRP)) inode->i_mode &= ~S_ISGID; di = (struct ocfs2_dinode *) bh->b_data; di->i_mode = cpu_to_le16(inode->i_mode); ret = ocfs2_journal_dirty(handle, bh); if (ret < 0) mlog_errno(ret);out_trans: ocfs2_commit_trans(osb, handle);out: mlog_exit(ret); return ret;}/* * Will look for holes and unwritten extents in the range starting at * pos for count bytes (inclusive). */static int ocfs2_check_range_for_holes(struct inode *inode, loff_t pos, size_t count){ int ret = 0; unsigned int extent_flags; u32 cpos, clusters, extent_len, phys_cpos; struct super_block *sb = inode->i_sb; cpos = pos >> OCFS2_SB(sb)->s_clustersize_bits; clusters = ocfs2_clusters_for_bytes(sb, pos + count) - cpos; while (clusters) { ret = ocfs2_get_clusters(inode, cpos, &phys_cpos, &extent_len, &extent_flags); if (ret < 0) { mlog_errno(ret); goto out; } if (phys_cpos == 0 || (extent_flags & OCFS2_EXT_UNWRITTEN)) { ret = 1; break; } if (extent_len > clusters) extent_len = clusters; clusters -= extent_len; cpos += extent_len; }out: return ret;}static int ocfs2_write_remove_suid(struct inode *inode){ int ret; struct buffer_head *bh = NULL; struct ocfs2_inode_info *oi = OCFS2_I(inode); ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), oi->ip_blkno, &bh, OCFS2_BH_CACHED, inode); if (ret < 0) { mlog_errno(ret); goto out; } ret = __ocfs2_write_remove_suid(inode, bh);out: brelse(bh); return ret;}/* * Allocate enough extents to cover the region starting at byte offset * start for len bytes. Existing extents are skipped, any extents * added are marked as "unwritten". */static int ocfs2_allocate_unwritten_extents(struct inode *inode, u64 start, u64 len){ int ret; u32 cpos, phys_cpos, clusters, alloc_size; u64 end = start + len; struct buffer_head *di_bh = NULL; if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) { ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), OCFS2_I(inode)->ip_blkno, &di_bh, OCFS2_BH_CACHED, inode); if (ret) { mlog_errno(ret); goto out; } /* * Nothing to do if the requested reservation range * fits within the inode. */ if (ocfs2_size_fits_inline_data(di_bh, end)) goto out; ret = ocfs2_convert_inline_data_to_extents(inode, di_bh); if (ret) { mlog_errno(ret); goto out; } } /* * We consider both start and len to be inclusive. */ cpos = start >> OCFS2_SB(inode->i_sb)->s_clustersize_bits; clusters = ocfs2_clusters_for_bytes(inode->i_sb, start + len); clusters -= cpos; while (clusters) { ret = ocfs2_get_clusters(inode, cpos, &phys_cpos, &alloc_size, NULL); if (ret) { mlog_errno(ret); goto out; } /* * Hole or existing extent len can be arbitrary, so * cap it to our own allocation request. */ if (alloc_size > clusters) alloc_size = clusters; if (phys_cpos) { /* * We already have an allocation at this * region so we can safely skip it. */ goto next; } ret = __ocfs2_extend_allocation(inode, cpos, alloc_size, 1); if (ret) { if (ret != -ENOSPC) mlog_errno(ret); goto out; }next: cpos += alloc_size; clusters -= alloc_size; } ret = 0;out: brelse(di_bh); return ret;}static int __ocfs2_remove_inode_range(struct inode *inode, struct buffer_head *di_bh, u32 cpos, u32 phys_cpos, u32 len, struct ocfs2_cached_dealloc_ctxt *dealloc){ int ret; u64 phys_blkno = ocfs2_clusters_to_blocks(inode->i_sb, phys_cpos); struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); struct inode *tl_inode = osb->osb_tl_inode; handle_t *handle; struct ocfs2_alloc_context *meta_ac = NULL; struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; ret = ocfs2_lock_allocators(inode, di, 0, 1, NULL, &meta_ac); if (ret) { mlog_errno(ret); return ret; } mutex_lock(&tl_inode->i_mutex); if (ocfs2_truncate_log_needs_flush(osb)) { ret = __ocfs2_flush_truncate_log(osb); if (ret < 0) { mlog_errno(ret); goto out; } } handle = ocfs2_start_trans(osb, OCFS2_REMOVE_EXTENT_CREDITS); if (handle == NULL) { ret = -ENOMEM; mlog_errno(ret); goto out; } ret = ocfs2_journal_access(handle, inode, di_bh, OCFS2_JOURNAL_ACCESS_WRITE); if (ret) { mlog_errno(ret); goto out; } ret = ocfs2_remove_extent(inode, di_bh, cpos, len, handle, meta_ac, dealloc); if (ret) { mlog_errno(ret); goto out_commit; } OCFS2_I(inode)->ip_clusters -= len; di->i_clusters = cpu_to_le32(OCFS2_I(inode)->ip_clusters); ret = ocfs2_journal_dirty(handle, di_bh); if (ret) { mlog_errno(ret); goto out_commit; } ret = ocfs2_truncate_log_append(osb, handle, phys_blkno, len); if (ret) mlog_errno(ret);out_commit: ocfs2_commit_trans(osb, handle);out: mutex_unlock(&tl_inode->i_mutex); if (meta_ac) ocfs2_free_alloc_context(meta_ac); return ret;}/* * Truncate a byte range, avoiding pages within partial clusters. This * preserves those pages for the zeroing code to write to. */static void ocfs2_truncate_cluster_pages(struct inode *inode, u64 byte_start, u64 byte_len){ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); loff_t start, end; struct address_space *mapping = inode->i_mapping; start = (loff_t)ocfs2_align_bytes_to_clusters(inode->i_sb, byte_start); end = byte_start + byte_len; end = end & ~(osb->s_clustersize - 1); if (start < end) { unmap_mapping_range(mapping, start, end - start, 0); truncate_inode_pages_range(mapping, start, end - 1); }}static int ocfs2_zero_partial_clusters(struct inode *inode, u64 start, u64 len){ int ret = 0; u64 tmpend, end = start + len; struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); unsigned int csize = osb->s_clustersize; handle_t *handle; /* * The "start" and "end" values are NOT necessarily part of * the range whose allocation is being deleted. Rather, this * is what the user passed in with the request. We must zero * partial clusters here. There's no need to worry about * physical allocation - the zeroing code knows to skip holes. */ mlog(0, "byte start: %llu, end: %llu\n", (unsigned long long)start, (unsigned long long)end); /* * If both edges are on a cluster boundary then there's no * zeroing required as the region is part of the allocation to * be truncated. */ if ((start & (csize - 1)) == 0 && (end & (csize - 1)) == 0) goto out; handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); if (handle == NULL) { ret = -ENOMEM; mlog_errno(ret); goto out; } /* * We want to get the byte offset of the end of the 1st cluster. */ tmpend = (u64)osb->s_clustersize + (start & ~(osb->s_clustersize - 1)); if (tmpend > end) tmpend = end; mlog(0, "1st range: start: %llu, tmpend: %llu\n", (unsigned long long)start, (unsigned long long)tmpend); ret = ocfs2_zero_range_for_truncate(inode, handle, start, tmpend); if (ret) mlog_errno(ret); if (tmpend < end) { /* * This may make start and end equal, but the zeroing * code will skip any work in that case so there's no * need to catch it up here. */ start = end & ~(osb->s_clustersize - 1); mlog(0, "2nd range: start: %llu, end: %llu\n", (unsigned long long)start, (unsigned long long)end); ret = ocfs2_zero_range_for_truncate(inode, handle, start, end); if (ret) mlog_errno(ret); } ocfs2_commit_trans(osb, handle);out:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -