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

📄 myfsfile.c

📁 一个LINUX下一个框架文件系统,运行编译环境:RED HAT LINUX7.3
💻 C
字号:
#include "common.h"
#include "mytypes.h"

/* external variables */
int myfs_maxsz;

extern struct myfs_inode *myfs_inop(struct inode *ino);

/* file operations */
static int myfs_readpage(struct file *file, struct page * page);
static ssize_t myfs_file_read(struct file *file, char *buf, size_t count,
	loff_t *ppos);
static ssize_t myfs_file_write(struct file *file, const char *buf,
	size_t count, loff_t *ppos);
static void myfs_file_truncate(struct inode *);
static int myfs_file_mmap(struct file *, struct vm_area_struct *);
static loff_t myfs_file_llseek(struct file *, loff_t, int);

int myfs_file_create(struct inode *dir, struct dentry *entry, int mode);
int myfs_open(struct inode *inode, struct file *file);
int myfs_release(struct inode *inode, struct file *f);


struct address_space_operations myfs_file_aops = {
	readpage:      myfs_readpage     /* readpage */
};

struct inode_operations myfs_file_inode_operations = {
	create:     myfs_file_create,      /* create */
//	rename:     myfs_rename,           /* rename */
	truncate:   myfs_file_truncate,    /* truncate */
//	revalidate: myfs_revalidate_inode, /* revalidate */
//	setattr:    myfs_notify_change     /* setattr */
};

/* file_operations notes:
 *
 * we're going to use mm/filemap.c:generic_file_mmap() here.  It will 
 * rely on our readpage function to work, so we'll have to get that
 * going.
 *
 */
struct file_operations myfs_file_operations = {
	llseek:  myfs_file_llseek,/* lseek */
	read:    myfs_file_read,  /* read */
	write:   myfs_file_write, /* write */
	mmap:    myfs_file_mmap,  /* mmap - we'll try the default */
	open:    myfs_open,       /* open called on first open instance of file */
	release: myfs_release,    /* release called when last open instance closed */
//	fsync:   myfs_fsync       /* fsync */
};

/* myfs_file_truncate()
 *
 * This is called from fs/open.c:do_truncate() and is called AFTER
 * the notify_change.  The notify_change MUST use inode_setattr() or
 * some similar method to get the updated size into the inode, or we
 * won't have it to use.
 *
 * Perhaps notify_change() should be setting the inode values but isn't?
 */
static void myfs_file_truncate(struct inode *inode)
{
	int error;
//	struct myfs_meta meta;

	printk( "myfs_truncate called for %s, size = %Ld\n",
	myfs_inop(inode)->name, (long long) inode->i_size);

/*	memset(&meta, 0, sizeof(meta));
	meta.valid = V_SIZE;
	meta.size = inode->i_size;

	if ((error = ll_myfs_setmeta(myfs_inop(inode), &meta, current->fsuid,
		current->fsgid)) != 0) {
		PERROR("myfs_truncate failed\n");
		return;
	}

	// if we were so inclined, we could update all our other values here,
	// since the setmeta gives us updated values back.
*/
	return;
}


/* myfs_file_mmap()
 *
 * NOTES:
 * Tried setting the VM_WRITE flag in the vma to get through our tests
 * in myfs_map_userbuf, but that didn't work.
 */
static int myfs_file_mmap(struct file *file, struct vm_area_struct *vma)
{
	int error = 0;

	printk("myfs_file_mmap called.\n");
/*	
	error = generic_file_mmap(file, vma);
*/
	return error;
}


/* myfs_readpage()
 *
 * Inside the page structure are "offset", the offset into the file, and
 * the page address, which can be found with "page_address(page)".
 *
 * See fs/nfs/read.c for readpage example.
 */
static int myfs_readpage(struct file *file, struct page *page)
{
	int error = 0;
//	struct inode *inode;
//	char *buf;
//	myfs_off_t offset;
//	size_t count = PAGE_SIZE;

	printk( "myfs_readpage is called!\n" );

/*	// from generic_readpage()
	atomic_inc(&page->count);
	set_bit(PG_locked, &page->flags);
#if 0
	// NOTE: THIS WAS COMMENTED OUT IN 2.4 CODE; I JUST WENT AHEAD AND
	// COMMENTED IT OUT HERE TOO...
	set_bit(PG_free_after, &page->flags); // not necessary ???
#endif
	
	// from brw_page()
	clear_bit(PG_uptodate, &page->flags);
	clear_bit(PG_error, &page->flags);

#ifdef HAVE_KMAP
	// this should help readpage work correctly for big mem machines
	buf = (char *)kmap(page);
#else
	buf = (char *)page_address(page);
#endif

#ifdef HAVE_LINUX_STRUCT_PAGE_OFFSET
	// THIS WORKED FOR 2.2.15 and before... 
	offset = page->offset;
#else
	// THIS HOPEFULLY WILL WORK NOW (IT'S WHAT PHIL HAD IN 2.4) 
	offset = ((loff_t)page->index) << PAGE_CACHE_SHIFT;
#if 0
	// THIS IS WHAT I HAD BEFORE
	offset = pgoff2loff(page->index);
#endif
#endif

	inode = file->f_dentry->d_inode;

	memset(buf, 0, count);

	printk(D_FILE, "myfs_readpage called for %s (%ld), offset %ld, size %ld\n",
	myfs_inop(inode)->name, (unsigned long) myfs_inop(inode)->handle,
	(long) offset, (long) count);

	error = ll_myfs_file_read(myfs_inop(inode), buf, count, &offset, 1);
	if (error <= 0) goto myfs_readpage_error;

	// from brw_page()
	set_bit(PG_uptodate, &page->flags);
myfs_readpage_error:
#ifdef HAVE_KMAP
	kunmap(page);
#endif
#ifdef HAVE_UNLOCKPAGE
	// this supposedly helps prevent smp races in 2.4 
	UnlockPage(page);
#else
	// from brw_page() 
	clear_bit(PG_locked, &page->flags);
	wake_up(&page->wait);
#endif
#if 0
	free_page(page_address(page)); // NFS does this 
#endif
	__free_page(page); // after_unlock_page() does this
*/
	return error;
}


/* myfs_file_read(file, buf, count, ppos)
 *
 * Notes:
 * - generally the pointer to the position passed in is a pointer to
 * 	file->f_pos, so that doesn't need to be updated as well.
 *
 * TODO: Combine with myfs_file_write() to save space.
 */
static ssize_t myfs_file_read(struct file *file, char *cbuf, size_t count,
	loff_t *ppos)
{
	int error = 0, retsz = 0;
//	struct inode *inode;
//	myfs_off_t myfs_pos = *ppos;
//	size_t xfersize;
//	char *buf = (char *) cbuf;

	printk( "myfs_file_read is called!\n" );

/*	// should we error check here? do we know for sure that the dentry is
	// there?

	inode = file->f_dentry->d_inode;

	printk(D_FILE, "myfs_file_read called for %s (%ld), offset %ld, size %ld\n",
	myfs_inop(inode)->name, (unsigned long) myfs_inop(inode)->handle,
	(long) myfs_pos, (long) count);

	if (access_ok(VERIFY_WRITE, buf, count) == 0){
		return -EFAULT;
	}

	if (count == 0){
		return 0;
	}

	// split our operation into blocks of myfs_maxsz or smaller
	do {
		xfersize = (count < myfs_maxsz) ? count : myfs_maxsz;

		error = ll_myfs_file_read(myfs_inop(inode), buf, xfersize, &myfs_pos, 0);
		if (error <= 0){
			return error;
		}
		retsz += error;

		// position is updated by ll_myfs_file_read()
		count -= xfersize;
		buf += xfersize;
	} while (count > 0);

	*ppos = myfs_pos;
*/
	return retsz;
}

/* myfs_file_write(file, buf, count, ppos)
 *
 * Notes:
 * - generally the pointer to the position passed in is a pointer to
 * 	file->f_pos, so that doesn't need to be updated as well.
 */
static ssize_t myfs_file_write(struct file *file, const char *cbuf,
size_t count, loff_t *ppos)
{
	int error = 0, retsz = 0;
//	struct inode *inode;
//	myfs_off_t myfs_pos = *ppos;
//	size_t xfersize;
//	char *buf = (char *) cbuf;

	printk( "myfs_file_write is called!\n" );
/*
	// should we error check here? do we know for sure that the dentry is
	// there?

	inode = file->f_dentry->d_inode;

	printk(D_FILE, "myfs_file_write called for %s (%ld), offset %ld, size %ld\n",
	myfs_inop(inode)->name, (unsigned long) myfs_inop(inode)->handle,
	(long) myfs_pos, (long) count);


	if	(access_ok(VERIFY_READ, (char *)buf, count) == 0){
		return -EFAULT;
	}

	if (count == 0){
		return 0;
	}

	// split our operation into blocks of myfs_maxsz or smaller
	do {
		xfersize = (count < myfs_maxsz) ? count : myfs_maxsz;

		error = ll_myfs_file_write(myfs_inop(inode), buf, xfersize, &myfs_pos, 0);
		if (error <= 0){
			return error;
		}
		retsz += error;

		// position is updated by ll_myfs_file_write()
		count -= xfersize;
		buf += xfersize;
	} while (count > 0);

	*ppos = myfs_pos;
	if (myfs_pos > inode->i_size)
		inode->i_size = myfs_pos;
*/
	return retsz;
}

/* myfs_release()
 *
 * Called when the last open file reference for a given file is
 * finished.  We use this as an opportunity to tell the daemon to close
 * the file when it wants to.
 */
int myfs_release(struct inode *inode, struct file *f)
{
	int error = 0;
//	struct myfs_inode *pinode;

	printk( "myfs_release is called !\n" );
/*
	pinode = myfs_inop(inode);

	printk(D_FILE, "myfs_release called for %s (%ld)\n", pinode->name,
	(unsigned long) pinode->handle);

	error = ll_myfs_hint(pinode, HINT_CLOSE);
*/	
	return error;
}


/* myfs_open()
 *
 * Called from fs/open.c:filep_open()
 *
 * NOTES:
 * Truncation and creation are handled by fs/namei.c:open_namei()
 * We need to take care of O_APPEND here.
 *
 * The inode for the file is not necessarily up to date.  This is
 * important in the O_APPEND case because we need to have the most
 * recent size, so we're going to force a revalidate_inode() in the case
 * of an append.
 */
int myfs_open(struct inode *inode, struct file *file)
{
	int error = 0;

	printk( "myfs_open is called!\n" );
/*
#ifdef NEED_TO_LOCK_KERNEL
	lock_kernel();
#endif

	if ((file->f_flags & O_APPEND)) {
		// force a revalidate
		printk(D_FILE, "myfs_open: getting most up to date size\n");

		if ((error = myfs_revalidate_inode(file->f_dentry)) < 0) {
#ifdef NEED_TO_LOCK_KERNEL
			unlock_kernel();
#endif
			return error;
		}

		// set the file position to point to one byte past the last byte
		// in the file
		file->f_pos = inode->i_size;
	}
#ifdef NEED_TO_LOCK_KERNEL
	unlock_kernel();
#endif
*/
	return error;
}

/* myfs_file_create()
 */
int myfs_file_create(struct inode *dir, struct dentry *entry, int mode)
{
	int error = 0, len_dir, len_file;
//	struct inode *inode;
//	struct myfs_meta meta;
//	struct myfs_phys phys;
//	struct myfs_inode *pinode;
//	char *ptr;

	printk("myfs_file_create called for %ld\n", dir->i_ino);

/*	len_dir = strlen(myfs_inop(dir)->name);
	len_file = entry->d_name.len;
	if ((pinode = (struct myfs_inode *) kmalloc(sizeof(struct myfs_inode)
	+ len_dir + len_file + 2, GFP_KERNEL)) == NULL){
		d_drop(entry);
		return -ENOMEM;
	}

	// build myfs_inode name field first
	pinode->name = (int8_t *)pinode + sizeof(struct myfs_inode);
	ptr = pinode->name;
	strcpy(ptr, myfs_inop(dir)->name);
	ptr += len_dir;
	*ptr = '/';
	ptr++;
	strcpy(ptr, entry->d_name.name);

	// do the create
	meta.valid = V_MODE | V_UID | V_GID | V_TIMES;
	meta.uid = current->fsuid;
	meta.gid = current->fsgid;
	meta.mode = mode;
	meta.mtime = meta.atime = meta.ctime = CURRENT_TIME;

	phys.blksize = DEFAULT_BLKSIZE;
	phys.dist = DEFAULT_DIST;
	phys.nodect = DEFAULT_NODECT;
	
	printk(D_FILE, "myfs_file_create calling ll_myfs_create\n");
	if ((error = ll_myfs_create(myfs_sbp(dir->i_sb), pinode->name,
	len_dir + len_file + 1, &meta, &phys)) < 0)
	{
		kfree(pinode);
		d_drop(entry);
		return error;
	}

	// do a lookup so we can fill in the inode
	printk(D_FILE, "myfs_file_create calling ll_myfs_lookup\n");
	if ((error = ll_myfs_lookup(myfs_sbp(dir->i_sb), pinode->name,
	len_dir + len_file + 1, &meta)) < 0)
	{
		kfree(pinode);
		d_drop(entry);
		return error;
	}

	// fill in inode structure and remainder of myfs_inode
	if ((inode = iget(dir->i_sb, meta.handle)) == NULL) {
		kfree(pinode);
		d_drop(entry);
		return -ENOMEM;
	}

	pinode->handle = inode->i_ino;
	pinode->super = myfs_sbp(inode->i_sb);
	myfs_meta_to_inode(&meta, inode);
	inode->u.generic_ip = pinode;

	d_instantiate(entry, inode); // do I know what this does?  nope!

	printk(D_FILE, "myfs_file_create: saved name is %s\n",
	myfs_inop(inode)->name);

	if (S_ISDIR(inode->i_mode)) {
		inode->i_op = &myfs_dir_inode_operations;
#ifdef HAVE_LINUX_STRUCT_INODE_I_FOP
		inode->i_fop = &myfs_dir_operations;
#endif
	}
   else if (S_ISREG(inode->i_mode)) {
		inode->i_op = &myfs_file_inode_operations;
#ifdef HAVE_LINUX_STRUCT_INODE_I_FOP
		inode->i_fop = &myfs_file_operations;
#endif
#ifdef HAVE_LINUX_STRUCT_ADDRESS_SPACE_OPERATIONS
		inode->i_data.a_ops = &myfs_file_aops;
#endif
	}
   else {
		inode->i_op = NULL;
#ifdef HAVE_LINUX_STRUCT_INODE_I_FOP
		inode->i_fop = NULL;
#endif
	}
*/
	return 0;
}			     

/* myfs_file_llseek()
 *
 * NOTES: we mainly implement this so that we have the opportunity to
 * update our metadata information (ie file size) when lseek is called
 * with SEEK_END.  generic_file_llseek() relies on the inode's size
 * field being up to date and therefore is not always suitable in that
 * case
 */
static loff_t myfs_file_llseek(struct file *file, loff_t offset, int
	origin)
{
	long long retval;
	int error;

	printk( "myfs_file_llseek is called!\n" );
/*
	switch (origin) {
		case 2:
			// force a revalidate
			printk(D_FILE, "myfs_file_llseek: getting most up to date size\n");
			if ((error = myfs_revalidate_inode(file->f_dentry)) < 0) {
				return error;
			}

			offset += file->f_dentry->d_inode->i_size;
			break;
		case 1:
			offset += file->f_pos;
	}

	retval = -EINVAL;
#ifdef HAVE_LINUX_STRUCT_SUPER_BLOCK_S_MAXBYTES
	if (offset>=0 && offset<=file->f_dentry->d_inode->i_sb->s_maxbytes) {
#else
	if (offset>=0){
#endif
		if (offset != file->f_pos) {
			file->f_pos = offset;
			file->f_reada = 0;
		}
		retval = offset;
	}
*/	
	return retval;
}

/*
 * Local variables:
 *  c-indent-level: 3
 *  c-basic-offset: 3
 *  tab-width: 3
 * End:
 */

⌨️ 快捷键说明

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