⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 file.c

📁 ocfs1.4.1 oracle分布式文件系统
💻 C
📖 第 1 页 / 共 5 页
字号:
/* -*- 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>#ifndef NO_SPLICE_HEADER#include <linux/splice.h>#else#include <linux/pipe_fs_i.h>#endif#include <linux/mount.h>#include <linux/writeback.h>#ifndef NO_FALLOCATE#include <linux/falloc.h>#endif#define MLOG_MASK_PREFIX ML_INODE#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 "buffer_head_io.h"static int ocfs2_sync_inode(struct inode *inode){	filemap_fdatawrite(inode->i_mapping);	return sync_mapping_buffers(inode->i_mapping);}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;}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;	}}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);	mlog_entry("(0x%p, 0x%p, '%.*s')\n", inode, file,		   filp_dentry(file)->d_name.len, filp_dentry(file)->d_name.name);	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:	mlog_exit(status);	return status;}static int ocfs2_file_release(struct inode *inode, struct file *file){	struct ocfs2_inode_info *oi = OCFS2_I(inode);	mlog_entry("(0x%p, 0x%p, '%.*s')\n", inode, file,		   filp_dentry(file)->d_name.len,		   filp_dentry(file)->d_name.name);	spin_lock(&oi->ip_lock);	if (!--oi->ip_open_count)		oi->ip_flags &= ~OCFS2_INODE_OPEN_DIRECT;	spin_unlock(&oi->ip_lock);	ocfs2_free_file_private(inode, file);	mlog_exit(0);	return 0;}static int ocfs2_dir_open(struct inode *inode, struct file *file){	return ocfs2_init_file_private(inode, file);}static int ocfs2_dir_release(struct inode *inode, struct file *file){	ocfs2_free_file_private(inode, file);	return 0;}static int ocfs2_sync_file(struct file *file,			   struct dentry *dentry,			   int datasync){	int err = 0;	journal_t *journal;	struct inode *inode = dentry->d_inode;	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);	mlog_entry("(0x%p, 0x%p, %d, '%.*s')\n", file, dentry, datasync,		   dentry->d_name.len, dentry->d_name.name);	err = ocfs2_sync_inode(dentry->d_inode);	if (err)		goto bail;	journal = osb->journal->j_journal;	err = journal_force_commit(journal);bail:	mlog_exit(err);	return (err < 0) ? -EIO : 0;}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;	if ((now.tv_sec - inode->i_atime.tv_sec <= osb->s_atime_quantum))		return 0;	else		return 1;}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;	mlog_entry_void();	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) {		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;	di->i_atime = cpu_to_le64(inode->i_atime.tv_sec);	di->i_atime_nsec = cpu_to_le32(inode->i_atime.tv_nsec);	ret = ocfs2_journal_dirty(handle, bh);	if (ret < 0)		mlog_errno(ret);out_commit:	ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle);out:	mlog_exit(ret);	return ret;}static int ocfs2_set_inode_size(handle_t *handle,				struct inode *inode,				struct buffer_head *fe_bh,				u64 new_i_size){	int status;	mlog_entry_void();	i_size_write(inode, new_i_size);	inode->i_blocks = ocfs2_inode_sector_count(inode);	inode->i_ctime = inode->i_mtime = CURRENT_TIME;	status = ocfs2_mark_inode_dirty(handle, inode, fe_bh);	if (status < 0) {		mlog_errno(status);		goto bail;	}bail:	mlog_exit(status);	return status;}static 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 (handle == NULL) {		ret = -ENOMEM;		mlog_errno(ret);		goto out;	}	ret = ocfs2_set_inode_size(handle, inode, di_bh,				   new_i_size);	if (ret < 0)		mlog_errno(ret);	ocfs2_commit_trans(osb, handle);out:	return ret;}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;	mlog_entry_void();	/* 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(handle, 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;	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);	status = ocfs2_journal_dirty(handle, fe_bh);	if (status < 0)		mlog_errno(status);out_commit:	ocfs2_commit_trans(osb, handle);out:	mlog_exit(status);	return status;}static 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);	struct ocfs2_truncate_context *tc = NULL;	mlog_entry("(inode = %llu, new_i_size = %llu\n",		   (unsigned long long)OCFS2_I(inode)->ip_blkno,		   (unsigned long long)new_i_size);	fe = (struct ocfs2_dinode *) di_bh->b_data;	if (!OCFS2_IS_VALID_DINODE(fe)) {		OCFS2_RO_ON_INVALID_DINODE(inode->i_sb, fe);		status = -EIO;		goto bail;	}	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)) {		mlog(0, "asked to truncate file with size (%llu) to size (%llu)!\n",		     (unsigned long long)le64_to_cpu(fe->i_size),		     (unsigned long long)new_i_size);		status = -EINVAL;		mlog_errno(status);		goto bail;	}	mlog(0, "inode %llu, i_size = %llu, new_i_size = %llu\n",	     (unsigned long long)le64_to_cpu(fe->i_blkno),	     (unsigned long long)le64_to_cpu(fe->i_size),	     (unsigned long long)new_i_size);	/* lets handle the simple truncate cases before doing any more	 * cluster locking. */	if (new_i_size == le64_to_cpu(fe->i_size))		goto bail;	down_write(&OCFS2_I(inode)->ip_alloc_sem);	/*	 * 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_prepare_truncate(osb, inode, di_bh, &tc);	if (status < 0) {		mlog_errno(status);		goto bail_unlock_sem;	}	status = ocfs2_commit_truncate(osb, inode, di_bh, tc);	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:	mlog_exit(status);	return status;}/* * 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. * * Will return -EAGAIN, and a reason if a restart is needed. * If passed in, *reason will always be set, even in error. */int ocfs2_do_extend_allocation(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 status = 0;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -