📄 file.c
字号:
/* * Copyright (c) 1997-2003 Erez Zadok * Copyright (c) 2001-2003 Stony Brook University * Copyright (c) 1997-2000 Columbia University * * For specific licensing information, see the COPYING file distributed with * this package, or get one from ftp://ftp.filesystems.org/pub/fist/COPYING. * * This Copyright notice must be kept intact and distributed with all * fistgen sources INCLUDING sources generated by fistgen. *//* * $Id: file.c,v 1.16 2002/12/27 20:18:59 ezk Exp $ */#ifdef HAVE_CONFIG_H# include <config.h>#endif /* HAVE_CONFIG_H */#ifdef FISTGEN# include "fist_wrapfs.h"#endif /* FISTGEN */#include "fist.h"#include "wrapfs.h"/******************* * File Operations * *******************/STATIC loff_twrapfs_llseek(file_t *file, loff_t offset, int origin){ loff_t err; file_t *hidden_file = ftohf(file); print_entry_location(); fist_dprint(6, "wrapfs_llseek: file=%x, offset=0x%x, origin=%d\n", (int) file, (int) offset, origin); // fist_print_file("LLSEEK Before file", file); // fist_print_file("LLSEEK Before hidden_file", hidden_file); /* always set hidden position to this one */ hidden_file->f_pos = file->f_pos; if (file->f_reada) { /* update readahead information if needed */ hidden_file->f_reada = file->f_reada; hidden_file->f_ramax = file->f_ramax; hidden_file->f_raend = file->f_raend; hidden_file->f_ralen = file->f_ralen; hidden_file->f_rawin = file->f_rawin; } ASSERT(hidden_file->f_reada == file->f_reada); ASSERT(hidden_file->f_ramax == file->f_ramax); ASSERT(hidden_file->f_raend == file->f_raend); ASSERT(hidden_file->f_ralen == file->f_ralen); ASSERT(hidden_file->f_rawin == file->f_rawin); if (hidden_file->f_op && hidden_file->f_op->llseek) { err = hidden_file->f_op->llseek(hidden_file, offset, origin); } else { err = default_llseek(hidden_file, offset, origin); } if (err < 0) { goto out; } if (err != file->f_pos) { file->f_pos = err; // ION maybe this? // file->f_pos = hidden_file->f_pos; file->f_reada = 0; file->f_version = ++global_event; }out: // fist_print_file("LLSEEK After file", file); // fist_print_file("LLSEEK After hidden_file", hidden_file); print_exit_status(err); return err;}STATIC ssize_twrapfs_dir_read(file_t *file, char *buf, size_t count, loff_t *ppos){ return -EISDIR;}/* * generic_file_read updates the atime of upper layer inode. * But, it doesn't give us a chance to update the atime of * the lower layer inode. This function is a wrapper to * generic_file_read. it Updates the atime of the lower level * inode if generic_file_read returns without any errors * this function should be used only for file reads and not * for directory reads. */STATIC ssize_twrapfs_read(file_t *file, char* buf, size_t count, loff_t *ppos){ int err = 0; print_entry_location(); err = generic_file_read(file, buf, count, ppos); if (err >= 0) UPDATE_ATIME(itohi(file->f_dentry->d_inode)); print_exit_status(err); return err;}/* * Adapted from 2.1 generic_file_write */STATIC ssize_twrapfs_write(file_t *file, const char *buf, size_t count, loff_t *ppos){ file_t *hidden_file; page_t *page, **hash; unsigned long page_cache = 0; unsigned long pgpos, orig_pgpos, offset; unsigned long bytes, written; size_t bytes_to_write; loff_t pos, orig_pos, tmp_pos; ssize_t status; long didread; mm_segment_t old_fs; char *hidden_buffer; inode_t *inode = file->f_dentry->d_inode; inode_t *hidden_inode = itohi(inode); print_entry_location(); /* check that offsets are correct */ ASSERT(file != NULL); ASSERT(ppos != NULL); pos = *ppos; written = 0; status = 0; old_fs = get_fs(); hidden_file = ftohf(file); ASSERT(hidden_file != NULL); hidden_buffer = kmalloc(PAGE_SIZE, GFP_KERNEL); if (!hidden_buffer) { printk("Out of memory.\n"); status = -ENOMEM; goto out; } /* we don't want anybody to do updates while we write, so lock the inode */ down(&hidden_inode->i_sem); if (file->f_flags & O_APPEND) pos = inode->i_size; fist_dprint(6, "EZK: WRITE: initial values: pos %ld, count %d\n", (long) pos, count); fist_print_file("EZK: WRITE file IN", file); /* we need to handle sparse files differently */ orig_pos = pos; orig_pgpos = orig_pos & PAGE_MASK; if (pos > inode->i_size) pos = inode->i_size; while (count) { fist_dprint(7, "WRITE: pos %ld, written %ld, count %d, buf 0x%lx\n", (long) pos, written, count, (long) buf); /* * Try to find the page in the cache. If it isn't there, * allocate a free page. */ offset = (pos & ~PAGE_MASK); pgpos = pos & PAGE_MASK; if ((bytes = PAGE_SIZE - offset) > count && pgpos >= orig_pgpos) bytes = count; hash = page_hash(inode, pgpos); if (!(page = __find_page(inode, pgpos, *hash))) { if (!page_cache) { page_cache = __get_free_page(GFP_KERNEL); if (page_cache) continue; status = -ENOMEM; break; } page = mem_map + MAP_NR(page_cache); add_to_page_cache(page, inode, pgpos, hash); page_cache = 0; } /* * Note: setting of the PG_locked bit is handled * below the i_op->xxx interface. */ didread = 0; page_wait: wait_on_page(page); if (PageUptodate(page)) goto do_update_page; /* * The page is not up-to-date ... if we're writing less * than a full page of data, we may have to read it first. * But if the page is past the current end of file, we must * clear it before updating. */ if (bytes < PAGE_SIZE) { if (pgpos < inode->i_size) { status = -EIO; if (didread >= 2) goto done_with_page; /* call our own readpage function */ status = inode->i_op->readpage(file, page); if (status < 0) goto done_with_page; didread++; goto page_wait; } else { /* Must clear for partial writes */ fist_dprint(7, "WRITE1: clearing page at offset 0x%x\n", (int) pgpos); memset((void *) page_address(page), 0, PAGE_SIZE); } } else if (pos < orig_pos) { /* Must clear for sparse files */ fist_dprint(7, "WRITE2: clearing page at offset 0x%x\n", (int) pgpos); memset((void *) page_address(page), 0, PAGE_SIZE); } /* * N.B. We should defer setting PG_uptodate at least until * the data is copied. A failure in i_op->updatepage() could * leave the page with garbage data. */ set_bit(PG_uptodate, &page->flags); do_update_page: /* Alright, the page is there. Now update it. */ fist_dprint(7, "WRITE: count %d, pos %ld, offset %ld, pgpos 0x%x, bytes %d\n", count, (int) pos, (int) offset, (int) pgpos, (int) bytes); if (pgpos < orig_pgpos) /* nothing to do, not even copy_from_user */ goto encode_page; if (pgpos == orig_pgpos) { /* * this is the only interesting case, * we have to shift from orig_pos to pos somehow */ pos = orig_pos; offset = pos & ~PAGE_MASK; if ((bytes = PAGE_SIZE - offset) > count) bytes = count; }#if 0 status = inode->i_op->updatepage(file, page, buf, offset, bytes, sync);#else fist_dprint(7, "WRITE: copying %ld bytes at offset %ld\n", bytes, offset); copy_from_user((char *) (page_address(page) + offset), buf, bytes); encode_page: wrapfs_encode_block((char *) page_address(page), hidden_buffer, PAGE_SIZE, inode, inode->i_sb); hidden_file->f_pos = pgpos; /* is this needed? */ if (inode->i_size < pgpos + PAGE_SIZE) if (inode->i_size > pos + bytes) bytes_to_write = inode->i_size - pgpos; else bytes_to_write = offset + bytes; else bytes_to_write = PAGE_SIZE; fist_dprint(7, "WRITE: writing at pgpos %ld, size %ld\n", pgpos, bytes_to_write); /* switch to kernel space */ set_fs(KERNEL_DS); tmp_pos = pgpos; status = hidden_file->f_op->write(hidden_file, hidden_buffer, bytes_to_write, &tmp_pos); fist_dprint(7, "WROTE: tmp_pos %ld, status %d\n", (int) tmp_pos, (int) status); /* switch back to user space */ set_fs(old_fs);#endif /* the rest of the code must not see that we are writing extra bytes */ /* do not adjust status if only filling up holes */ if (status > 0 && pgpos >= orig_pgpos) { if (status < offset) { status = 0; } else { status -= offset; if (status > bytes) status = bytes; } } done_with_page: __free_page(page); if (status < 0) break; /* do not adjust these variables if only filling up holes */ if (pgpos >= orig_pgpos) { written += status; count -= status; buf += status; } pos += status; } // MAJOR HACK /* * because pread() does not have any way to tell us that it is * our caller, then we don't know for sure if we have to update * the file positions. This hack relies on read() having passed us * the "real" pointer of its struct file's f_pos field. */ if (ppos == &file->f_pos) hidden_file->f_pos = *ppos = pos; // file->f_pos = pos; if (pos > inode->i_size) { inode->i_size = pos; /* update the number of disk blocks allocated */ inode->i_blocks = hidden_inode->i_blocks; } /* for write operations, mtime and ctime must be updated */ fist_copy_attr_times(inode, hidden_inode); up(&hidden_inode->i_sem); kfree_s(hidden_buffer, PAGE_SIZE); if (page_cache) free_page(page_cache); status = written ? written : status;out: print_exit_status(status); // fist_print_file("WRITE file", file); // fist_print_file("WRITE hidden_file", hidden_file); // fist_set_debug_value(0); return status;}#ifdef FIST_FILTER_NAMEstruct wrapfs_getdents_callback { void *dirent; dentry_t *dentry; filldir_t filldir;};/* copied from generic filldir in fs/readir.c */STATIC intwrapfs_filldir(void *dirent, const char *name, int namlen, off_t offset, ino_t ino){ struct wrapfs_getdents_callback *buf = (struct wrapfs_getdents_callback *) dirent; int err; char *decoded_name; int decoded_length; decoded_length = wrapfs_decode_filename(name, namlen, &decoded_name, SKIP_DOTS, buf->dentry->d_inode, buf->dentry->d_sb); if (decoded_length < 0) return 0; /* no error, just skip the entry */ FIST_OP_READDIR_CALL; err = buf->filldir(buf->dirent, decoded_name, decoded_length, offset, ino); kfree_s(decoded_name, decoded_length); return err;}#endif /* FIST_FILTER_NAME */STATIC intwrapfs_readdir(file_t *file, void *dirent, filldir_t filldir){ int err = -ENOTDIR; file_t *hidden_file = ftohf(file); inode_t *inode = file->f_dentry->d_inode; inode_t *hidden_inode = itohi(inode);#ifdef FIST_FILTER_NAME struct wrapfs_getdents_callback buf;#endif /* FIST_FILTER_NAME */ print_entry_location(); fist_checkinode(inode, "wrapfs_readdir"); if (!hidden_file || !hidden_file->f_op || !hidden_file->f_op->readdir) goto out; down(&hidden_inode->i_sem);#ifdef FIST_FILTER_NAME /* prepare for callback */ buf.dirent = dirent; buf.dentry = file->f_dentry; buf.filldir = filldir; err = hidden_file->f_op->readdir(hidden_file, (void *) &buf, wrapfs_filldir);#else /* not FIST_FILTER_NAME */ err = hidden_file->f_op->readdir(hidden_file, dirent, filldir);#endif /* not FIST_FILTER_NAME */ up(&hidden_inode->i_sem); file->f_pos = hidden_file->f_pos; if (err > 0) fist_copy_attr_atime(inode, hidden_inode);out: fist_checkinode(inode, "post wrapfs_readdir"); print_exit_status(err); return err;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -