int hib_wait_on_bio_chain(struct bio **bio_chain) { struct bio *bio; struct bio *next_bio; int ret = 0; if (bio_chain == NULL) return 0; bio = *bio_chain; if (bio == NULL) return 0; while (bio) { struct page *page; next_bio = bio->bi_private; page = bio->bi_io_vec[0].bv_page; wait_on_page_locked(page); if (!PageUptodate(page) || PageError(page)) ret = -EIO; put_page(page); bio_put(bio); bio = next_bio; } *bio_chain = NULL; return ret; }
static int gfs2_read_super(struct gfs2_sbd *sdp, sector_t sector, int silent) { struct super_block *sb = sdp->sd_vfs; struct gfs2_sb *p; struct page *page; struct bio *bio; page = alloc_page(GFP_NOFS); if (unlikely(!page)) return -ENOBUFS; ClearPageUptodate(page); ClearPageDirty(page); lock_page(page); bio = bio_alloc(GFP_NOFS, 1); bio->bi_sector = sector * (sb->s_blocksize >> 9); bio->bi_bdev = sb->s_bdev; bio_add_page(bio, page, PAGE_SIZE, 0); bio->bi_end_io = end_bio_io_page; bio->bi_private = page; submit_bio(READ_SYNC | REQ_META, bio); wait_on_page_locked(page); bio_put(bio); if (!PageUptodate(page)) { __free_page(page); return -EIO; } p = kmap(page); gfs2_sb_in(sdp, p); kunmap(page); __free_page(page); return gfs2_check_sb(sdp, silent); }
/* * check a symbolic link to see whether it actually encodes a mountpoint * - sets the AFS_VNODE_MOUNTPOINT flag on the vnode appropriately */ int afs_mntpt_check_symlink(struct afs_vnode *vnode) { struct page *page; size_t size; char *buf; int ret; _enter("{%u,%u}", vnode->fid.vnode, vnode->fid.unique); /* read the contents of the symlink into the pagecache */ page = read_mapping_page(AFS_VNODE_TO_I(vnode)->i_mapping, 0, NULL); if (IS_ERR(page)) { ret = PTR_ERR(page); goto out; } ret = -EIO; wait_on_page_locked(page); buf = kmap(page); if (!PageUptodate(page)) goto out_free; if (PageError(page)) goto out_free; /* examine the symlink's contents */ size = vnode->status.size; _debug("symlink to %*.*s", size, (int) size, buf); if (size > 2 && (buf[0] == '%' || buf[0] == '#') && buf[size - 1] == '.' ) { _debug("symlink is a mountpoint"); spin_lock(&vnode->lock); vnode->flags |= AFS_VNODE_MOUNTPOINT; spin_unlock(&vnode->lock); } ret = 0; out_free: kunmap(page); page_cache_release(page); out: _leave(" = %d", ret); return ret; } /* end afs_mntpt_check_symlink() */
/** * do_bio_wait - wait for some TuxOnIce I/O to complete * @reason: The array index of the reason we're waiting. * * Wait for a particular page of I/O if we're after a particular page. * If we're not after a particular page, wait instead for all in flight * I/O to be completed or for us to have enough free memory to be able * to submit more I/O. * * If we wait, we also update our statistics regarding why we waited. **/ static void do_bio_wait(int reason) { struct page *was_waiting_on = waiting_on; /* On SMP, waiting_on can be reset, so we make a copy */ if (was_waiting_on) { wait_on_page_locked(was_waiting_on); atomic_inc(&reasons[reason]); } else { atomic_inc(&reasons[reason]); wait_event(num_in_progress_wait, !atomic_read(&toi_io_in_progress) || nr_unallocated_buffer_pages() > free_mem_throttle); } }
static struct page * dir_get_page(struct inode *dir, unsigned long n) { struct address_space *mapping = dir->i_mapping; struct page *page = read_mapping_page(mapping, n, NULL); if (!IS_ERR(page)) { wait_on_page_locked(page); kmap(page); if (!PageUptodate(page)) goto fail; } return page; fail: dir_put_page(page); return ERR_PTR(-EIO); }
/** * ecryptfs_get1page * * Get one page from cache or lower f/s, return error otherwise. * * Returns unlocked and up-to-date page (if ok), with increased * refcnt. */ static struct page *ecryptfs_get1page(struct file *file, int index) { struct page *page; struct dentry *dentry; struct inode *inode; struct address_space *mapping; dentry = file->f_path.dentry; inode = dentry->d_inode; mapping = inode->i_mapping; page = read_cache_page(mapping, index, (filler_t *)mapping->a_ops->readpage, (void *)file); if (IS_ERR(page)) goto out; wait_on_page_locked(page); out: return page; }
/* get the link contents into pagecache */ static char *ocfs2_page_getlink(struct dentry * dentry, struct page **ppage) { struct page * page; struct address_space *mapping = dentry->d_inode->i_mapping; page = read_mapping_page(mapping, 0, NULL); if (IS_ERR(page)) goto sync_fail; wait_on_page_locked(page); if (!PageUptodate(page)) goto async_fail; *ppage = page; return kmap(page); async_fail: page_cache_release(page); return ERR_PTR(-EIO); sync_fail: return (char*)page; }
struct page *find_data_page(struct inode *inode, pgoff_t index) { struct address_space *mapping = inode->i_mapping; struct page *page; page = find_get_page(mapping, index); if (page && PageUptodate(page)) return page; f2fs_put_page(page, 0); page = get_read_data_page(inode, index, READ_SYNC); if (IS_ERR(page)) return page; if (PageUptodate(page)) return page; wait_on_page_locked(page); if (unlikely(!PageUptodate(page))) { f2fs_put_page(page, 0); return ERR_PTR(-EIO); } return page; }
/* * get a page into the pagecache */ static struct page *afs_dir_get_page(struct inode *dir, unsigned long index) { struct page *page; _enter("{%lu},%lu",dir->i_ino,index); page = read_cache_page(dir->i_mapping,index, (filler_t*)dir->i_mapping->a_ops->readpage,NULL); if (!IS_ERR(page)) { wait_on_page_locked(page); kmap(page); if (!PageUptodate(page)) goto fail; if (!PageChecked(page)) afs_dir_check_page(dir,page); if (PageError(page)) goto fail; } return page; fail: afs_dir_put_page(page); return ERR_PTR(-EIO); } /* end afs_dir_get_page() */
/** * submit - submit BIO request. * @rw: READ or WRITE. * @off physical offset of page. * @page: page we're reading or writing. * @bio_chain: list of pending biod (for async reading) * * Straight from the textbook - allocate and initialize the bio. * If we're reading, make sure the page is marked as dirty. * Then submit it and, if @bio_chain == NULL, wait. */ static int submit(int rw, struct block_device *bdev, sector_t sector, struct page *page, struct bio **bio_chain) { const int bio_rw = rw | REQ_SYNC; struct bio *bio; bio = bio_alloc(__GFP_WAIT | __GFP_HIGH, 1); bio->bi_sector = sector; bio->bi_bdev = bdev; bio->bi_end_io = end_swap_bio_read; if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) { printk(KERN_ERR "PM: Adding page to bio failed at %llu\n", (unsigned long long)sector); bio_put(bio); return -EFAULT; } lock_page(page); bio_get(bio); if (bio_chain == NULL) { submit_bio(bio_rw, bio); wait_on_page_locked(page); if (rw == READ) bio_set_pages_dirty(bio); bio_put(bio); } else { if (rw == READ) get_page(page); /* These pages are freed later */ bio->bi_private = *bio_chain; *bio_chain = bio; submit_bio(bio_rw, bio); } return 0; }
/* read a page from a file, pinning it into cache, and return bytes_read */ static struct page *read_page(struct file *file, unsigned long index, unsigned long *bytes_read) { struct inode *inode = file->f_mapping->host; struct page *page = NULL; loff_t isize = i_size_read(inode); unsigned long end_index = isize >> PAGE_SHIFT; PRINTK("read bitmap file (%dB @ %Lu)\n", (int)PAGE_SIZE, (unsigned long long)index << PAGE_SHIFT); page = read_cache_page(inode->i_mapping, index, (filler_t *)inode->i_mapping->a_ops->readpage, file); if (IS_ERR(page)) goto out; wait_on_page_locked(page); if (!PageUptodate(page) || PageError(page)) { put_page(page); page = ERR_PTR(-EIO); goto out; } if (index > end_index) /* we have read beyond EOF */ *bytes_read = 0; else if (index == end_index) /* possible short read */ *bytes_read = isize & ~PAGE_MASK; else *bytes_read = PAGE_SIZE; /* got a full page */ out: if (IS_ERR(page)) printk(KERN_ALERT "md: bitmap read error: (%dB @ %Lu): %ld\n", (int)PAGE_SIZE, (unsigned long long)index << PAGE_SHIFT, PTR_ERR(page)); return page; }
/* * create a vfsmount to be automounted */ static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt) { struct afs_super_info *super; struct vfsmount *mnt; struct page *page = NULL; size_t size; char *buf, *devname = NULL, *options = NULL; int ret; kenter("{%s}", mntpt->d_name.name); BUG_ON(!mntpt->d_inode); ret = -EINVAL; size = mntpt->d_inode->i_size; if (size > PAGE_SIZE - 1) goto error; ret = -ENOMEM; devname = (char *) get_zeroed_page(GFP_KERNEL); if (!devname) goto error; options = (char *) get_zeroed_page(GFP_KERNEL); if (!options) goto error; /* read the contents of the AFS special symlink */ page = read_mapping_page(mntpt->d_inode->i_mapping, 0, NULL); if (IS_ERR(page)) { ret = PTR_ERR(page); goto error; } ret = -EIO; wait_on_page_locked(page); if (!PageUptodate(page) || PageError(page)) goto error; buf = kmap(page); memcpy(devname, buf, size); kunmap(page); page_cache_release(page); page = NULL; /* work out what options we want */ super = AFS_FS_S(mntpt->d_sb); memcpy(options, "cell=", 5); strcpy(options + 5, super->volume->cell->name); if (super->volume->type == AFSVL_RWVOL) strcat(options, ",rwpath"); /* try and do the mount */ kdebug("--- attempting mount %s -o %s ---", devname, options); mnt = vfs_kern_mount(&afs_fs_type, 0, devname, options); kdebug("--- mount result %p ---", mnt); free_page((unsigned long) devname); free_page((unsigned long) options); kleave(" = %p", mnt); return mnt; error: if (page) page_cache_release(page); if (devname) free_page((unsigned long) devname); if (options) free_page((unsigned long) options); kleave(" = %d", ret); return ERR_PTR(ret); } /* end afs_mntpt_do_automount() */
/* * We completely avoid races by reading each swap page in advance, * and then search for the process using it. All the necessary * page table adjustments can then be made atomically. */ static int try_to_unuse(unsigned int type) { struct swap_info_struct * si = &swap_info[type]; struct mm_struct *start_mm; unsigned short *swap_map; unsigned short swcount; struct page *page; swp_entry_t entry; unsigned int i = 0; int retval = 0; int reset_overflow = 0; int shmem; /* * When searching mms for an entry, a good strategy is to * start at the first mm we freed the previous entry from * (though actually we don't notice whether we or coincidence * freed the entry). Initialize this start_mm with a hold. * * A simpler strategy would be to start at the last mm we * freed the previous entry from; but that would take less * advantage of mmlist ordering, which clusters forked mms * together, child after parent. If we race with dup_mmap(), we * prefer to resolve parent before child, lest we miss entries * duplicated after we scanned child: using last mm would invert * that. Though it's only a serious concern when an overflowed * swap count is reset from SWAP_MAP_MAX, preventing a rescan. */ start_mm = &init_mm; atomic_inc(&init_mm.mm_users); /* * Keep on scanning until all entries have gone. Usually, * one pass through swap_map is enough, but not necessarily: * there are races when an instance of an entry might be missed. */ while ((i = find_next_to_unuse(si, i)) != 0) { if (signal_pending(current)) { retval = -EINTR; break; } /* * Get a page for the entry, using the existing swap * cache page if there is one. Otherwise, get a clean * page and read the swap into it. */ swap_map = &si->swap_map[i]; entry = swp_entry(type, i); page = read_swap_cache_async(entry, NULL, 0); if (!page) { /* * Either swap_duplicate() failed because entry * has been freed independently, and will not be * reused since sys_swapoff() already disabled * allocation from here, or alloc_page() failed. */ if (!*swap_map) continue; retval = -ENOMEM; break; } /* * Don't hold on to start_mm if it looks like exiting. */ if (atomic_read(&start_mm->mm_users) == 1) { mmput(start_mm); start_mm = &init_mm; atomic_inc(&init_mm.mm_users); } /* * Wait for and lock page. When do_swap_page races with * try_to_unuse, do_swap_page can handle the fault much * faster than try_to_unuse can locate the entry. This * apparently redundant "wait_on_page_locked" lets try_to_unuse * defer to do_swap_page in such a case - in some tests, * do_swap_page and try_to_unuse repeatedly compete. */ wait_on_page_locked(page); wait_on_page_writeback(page); lock_page(page); wait_on_page_writeback(page); /* * Remove all references to entry. * Whenever we reach init_mm, there's no address space * to search, but use it as a reminder to search shmem. */ shmem = 0; swcount = *swap_map; if (swcount > 1) { if (start_mm == &init_mm) shmem = shmem_unuse(entry, page); else retval = unuse_mm(start_mm, entry, page); } if (*swap_map > 1) { int set_start_mm = (*swap_map >= swcount); struct list_head *p = &start_mm->mmlist; struct mm_struct *new_start_mm = start_mm; struct mm_struct *prev_mm = start_mm; struct mm_struct *mm; atomic_inc(&new_start_mm->mm_users); atomic_inc(&prev_mm->mm_users); spin_lock(&mmlist_lock); while (*swap_map > 1 && !retval && (p = p->next) != &start_mm->mmlist) { mm = list_entry(p, struct mm_struct, mmlist); if (!atomic_inc_not_zero(&mm->mm_users)) continue; spin_unlock(&mmlist_lock); mmput(prev_mm); prev_mm = mm; cond_resched(); swcount = *swap_map; if (swcount <= 1) ; else if (mm == &init_mm) { set_start_mm = 1; shmem = shmem_unuse(entry, page); } else retval = unuse_mm(mm, entry, page); if (set_start_mm && *swap_map < swcount) { mmput(new_start_mm); atomic_inc(&mm->mm_users); new_start_mm = mm; set_start_mm = 0; } spin_lock(&mmlist_lock); } spin_unlock(&mmlist_lock); mmput(prev_mm); mmput(start_mm); start_mm = new_start_mm; } if (retval) { unlock_page(page); page_cache_release(page); break; } /* * How could swap count reach 0x7fff when the maximum * pid is 0x7fff, and there's no way to repeat a swap * page within an mm (except in shmem, where it's the * shared object which takes the reference count)? * We believe SWAP_MAP_MAX cannot occur in Linux 2.4. * * If that's wrong, then we should worry more about * exit_mmap() and do_munmap() cases described above: * we might be resetting SWAP_MAP_MAX too early here. * We know "Undead"s can happen, they're okay, so don't * report them; but do report if we reset SWAP_MAP_MAX. */ if (*swap_map == SWAP_MAP_MAX) { spin_lock(&swap_lock); *swap_map = 1; spin_unlock(&swap_lock); reset_overflow = 1; } /* * If a reference remains (rare), we would like to leave * the page in the swap cache; but try_to_unmap could * then re-duplicate the entry once we drop page lock, * so we might loop indefinitely; also, that page could * not be swapped out to other storage meanwhile. So: * delete from cache even if there's another reference, * after ensuring that the data has been saved to disk - * since if the reference remains (rarer), it will be * read from disk into another page. Splitting into two * pages would be incorrect if swap supported "shared * private" pages, but they are handled by tmpfs files. * * Note shmem_unuse already deleted a swappage from * the swap cache, unless the move to filepage failed: * in which case it left swappage in cache, lowered its * swap count to pass quickly through the loops above, * and now we must reincrement count to try again later. */ if ((*swap_map > 1) && PageDirty(page) && PageSwapCache(page)) { struct writeback_control wbc = { .sync_mode = WB_SYNC_NONE, }; swap_writepage(page, &wbc); lock_page(page); wait_on_page_writeback(page); } if (PageSwapCache(page)) { if (shmem) swap_duplicate(entry); else delete_from_swap_cache(page); } /* * So we could skip searching mms once swap count went * to 1, we did not mark any present ptes as dirty: must * mark page dirty so shrink_page_list will preserve it. */ SetPageDirty(page); unlock_page(page); page_cache_release(page); /* * Make sure that we aren't completely killing * interactive performance. */ cond_resched(); }
/* * Returns a pointer to a buffer containing at least LEN bytes of * filesystem starting at byte offset OFFSET into the filesystem. */ static void *cramfs_read_comm(struct super_block *sb, unsigned int offset, unsigned int len) { struct address_space *mapping = sb->s_bdev->bd_inode->i_mapping; struct page *pages[BLKS_PER_BUF]; unsigned i, blocknr, buffer; unsigned long devsize; char *data; if (!len) return NULL; blocknr = offset >> PAGE_CACHE_SHIFT; offset &= PAGE_CACHE_SIZE - 1; /* Check if an existing buffer already has the data.. */ for (i = 0; i < READ_BUFFERS; i++) { unsigned int blk_offset; if (buffer_dev[i] != sb) continue; if (blocknr < buffer_blocknr[i]) continue; blk_offset = (blocknr - buffer_blocknr[i]) << PAGE_CACHE_SHIFT; blk_offset += offset; if (blk_offset + len > BUFFER_SIZE) continue; return read_buffers[i] + blk_offset; } devsize = mapping->host->i_size >> PAGE_CACHE_SHIFT; /* Ok, read in BLKS_PER_BUF pages completely first. */ for (i = 0; i < BLKS_PER_BUF; i++) { struct page *page = NULL; if (blocknr + i < devsize) { page = read_mapping_page_async(mapping, blocknr + i, NULL); /* synchronous error? */ if (IS_ERR(page)) page = NULL; } pages[i] = page; } for (i = 0; i < BLKS_PER_BUF; i++) { struct page *page = pages[i]; if (page) { wait_on_page_locked(page); if (!PageUptodate(page)) { /* asynchronous error */ page_cache_release(page); pages[i] = NULL; } } } buffer = next_buffer; next_buffer = NEXT_BUFFER(buffer); buffer_blocknr[buffer] = blocknr; buffer_dev[buffer] = sb; data = read_buffers[buffer]; for (i = 0; i < BLKS_PER_BUF; i++) { struct page *page = pages[i]; if (page) { memcpy(data, kmap(page), PAGE_CACHE_SIZE); kunmap(page); page_cache_release(page); } else memset(data, 0, PAGE_CACHE_SIZE); data += PAGE_CACHE_SIZE; } return read_buffers[buffer] + offset; }
/* for every page of file: read page, cut part of extent pointing to this page, put data of page tree by tail item */ int extent2tail(struct file * file, struct unix_file_info *uf_info) { int result; struct inode *inode; struct page *page; unsigned long num_pages, i; unsigned long start_page; reiser4_key from; reiser4_key to; unsigned count; __u64 offset; assert("nikita-3362", ea_obtained(uf_info)); inode = unix_file_info_to_inode(uf_info); assert("nikita-3412", !IS_RDONLY(inode)); assert("vs-1649", uf_info->container != UF_CONTAINER_TAILS); assert("", !reiser4_inode_get_flag(inode, REISER4_PART_IN_CONV)); offset = 0; if (reiser4_inode_get_flag(inode, REISER4_PART_MIXED)) { /* * file is marked on disk as there was a conversion which did * not complete due to either crash or some error. Find which * offset tail conversion stopped at */ result = find_start(inode, EXTENT_POINTER_ID, &offset); if (result == -ENOENT) { /* no extent found, everything is converted */ uf_info->container = UF_CONTAINER_TAILS; complete_conversion(inode); return 0; } else if (result != 0) /* some other error */ return result; } reiser4_inode_set_flag(inode, REISER4_PART_IN_CONV); /* number of pages in the file */ num_pages = (inode->i_size + - offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; start_page = offset >> PAGE_CACHE_SHIFT; inode_file_plugin(inode)->key_by_inode(inode, offset, &from); to = from; result = 0; for (i = 0; i < num_pages; i++) { __u64 start_byte; result = reserve_extent2tail_iteration(inode); if (result != 0) break; if (i == 0 && offset == 0) { reiser4_inode_set_flag(inode, REISER4_PART_MIXED); reiser4_update_sd(inode); } page = read_mapping_page(inode->i_mapping, (unsigned)(i + start_page), NULL); if (IS_ERR(page)) { result = PTR_ERR(page); break; } wait_on_page_locked(page); if (!PageUptodate(page)) { page_cache_release(page); result = RETERR(-EIO); break; } /* cut part of file we have read */ start_byte = (__u64) ((i + start_page) << PAGE_CACHE_SHIFT); set_key_offset(&from, start_byte); set_key_offset(&to, start_byte + PAGE_CACHE_SIZE - 1); /* * reiser4_cut_tree_object() returns -E_REPEAT to allow atom * commits during over-long truncates. But * extent->tail conversion should be performed in one * transaction. */ result = reiser4_cut_tree(reiser4_tree_by_inode(inode), &from, &to, inode, 0); if (result) { page_cache_release(page); break; } /* put page data into tree via tail_write */ count = PAGE_CACHE_SIZE; if ((i == (num_pages - 1)) && (inode->i_size & ~PAGE_CACHE_MASK)) /* last page can be incompleted */ count = (inode->i_size & ~PAGE_CACHE_MASK); while (count) { loff_t pos = start_byte; assert("edward-1537", file != NULL && file->f_dentry != NULL); assert("edward-1538", file->f_dentry->d_inode == inode); result = reiser4_write_tail(file, inode, (char __user *)kmap(page), count, &pos); reiser4_free_file_fsdata(file); if (result <= 0) { warning("", "reiser4_write_tail failed"); page_cache_release(page); reiser4_inode_clr_flag(inode, REISER4_PART_IN_CONV); return result; } count -= result; } /* release page */ lock_page(page); /* page is already detached from jnode and mapping. */ assert("vs-1086", page->mapping == NULL); assert("nikita-2690", (!PagePrivate(page) && jprivate(page) == 0)); /* waiting for writeback completion with page lock held is * perfectly valid. */ wait_on_page_writeback(page); reiser4_drop_page(page); /* release reference taken by read_cache_page() above */ page_cache_release(page); drop_exclusive_access(uf_info); /* * throttle the conversion. * FIXME-EDWARD: Calculate and pass the precise number * of pages that was dirtied */ reiser4_throttle_write(inode, 1); get_exclusive_access(uf_info); /* * nobody is allowed to complete conversion but a process which * started it */ assert("", reiser4_inode_get_flag(inode, REISER4_PART_MIXED)); } reiser4_inode_clr_flag(inode, REISER4_PART_IN_CONV); if (i == num_pages) { /* file is converted to formatted items */ assert("vs-1698", reiser4_inode_get_flag(inode, REISER4_PART_MIXED)); assert("vs-1260", inode_has_no_jnodes(reiser4_inode_data(inode))); uf_info->container = UF_CONTAINER_TAILS; complete_conversion(inode); return 0; } /* * conversion is not complete. Inode was already marked as * REISER4_PART_MIXED and stat-data were updated at the first * iteration of the loop above. */ warning("nikita-2282", "Partial conversion of %llu: %lu of %lu: %i", (unsigned long long)get_inode_oid(inode), i, num_pages, result); /* this flag should be cleared, otherwise get_exclusive_access_careful() will fall into infinite loop */ assert("edward-1550", !reiser4_inode_get_flag(inode, REISER4_PART_IN_CONV)); return result; }
ssize_t GSFS_file_read (struct file *filp, char __user *charp, size_t len, loff_t *off){ struct inode *inode=filp->f_mapping->host; struct GSFS_inode *inf=(struct GSFS_inode*)inode->i_private; sector_t sec_start, sec_end, sec_len; struct page **res, **res2, **restemp; unsigned int *pn, *pn2, *pntemp; int i, odirect=filp->f_flags&O_SYNC, j, lock, pncount, pn2count; unsigned long pagestartbyte=0, pageendbyte, bufstart, bytes_in_first_buf_page; unsigned long pagelen; size_t rlen; //char *dest, // *src; gwf(printk("<0>" "File read with inode :%lu size:%lu offset:%llu , off:%llu, charp:%lx, pid:%u\n",inode->i_ino,len,*off,filp->f_pos,(unsigned long)charp,current->pid)); if((*off>=inode->i_size)){ gwf(printk("<0>" "File read ended for *pos<size with inode :%lu size:%lu offset:%llu , off:%llu, charp:%lx, pid:%u\n",inode->i_ino,len,*off,filp->f_pos,(unsigned long)charp,current->pid)); return 0; } if(!access_ok(VERIFY_WRITE,charp,len)){ gwf(printk("<0>" "File read ended for access_nok with inode :%lu size:%lu offset:%llu , off:%llu, charp:%lx, pid:%u\n",inode->i_ino,len,*off,filp->f_pos,(unsigned long)charp,current->pid)); return -EIO; } sec_start=(*off)>>Block_Size_Bits; if((*off+len)>inode->i_size) len=inode->i_size-*off; sec_end=(*off+len-1)>>Block_Size_Bits; sec_len=sec_end-sec_start+1; bytes_in_first_buf_page=((1+~((*off)&((unsigned long)Block_Size-1)))&(Block_Size-1)); if(!bytes_in_first_buf_page) bytes_in_first_buf_page=Block_Size; pn=kzalloc(sec_len*sizeof(unsigned int),GFP_KERNEL); pn2=kzalloc(sec_len*sizeof(unsigned int),GFP_KERNEL); res=kzalloc(sec_len*sizeof(struct page*),GFP_KERNEL); res2=kzalloc(sec_len*sizeof(struct page*),GFP_KERNEL); for(i=sec_start,j=0;i<=sec_end;i++,j++) pn[j]=i; gwf(printk("<0>" "GSFS_file_read: sec_start:%lu, sec_end:%lu, sec_len:%lu, bytes_in_first_buf_page: %lu\n", sec_start,sec_end,sec_len,bytes_in_first_buf_page)); pncount=GSFS_get_data_pages_of_inode(inode, pn, sec_len ,res,odirect); //printk("<0>" "res[%u]=%d \n",j,res[j]); rlen=0; pn2count=0; lock=0; do{ for(j=0;j<pncount;j++){ //printk("<0>" "res[%u]=%lx \n",j,res[j]); if(unlikely(!res[j])) continue; if(lock && PageLocked(res[j])){ //printk("<0>" "Locking for j:%u\n",j); wait_on_page_locked(res[j]); lock=0; } else if(PageLocked(res[j])){ pn2[pn2count]=pn[j]; res2[pn2count]=res[j]; pn2count++; continue; } //the page is available for writing to buffer if(pn[j]==sec_start){ pagestartbyte=((*off)&(Block_Size-1)); bufstart=(unsigned long)charp; } else{ pagestartbyte=0; bufstart=(unsigned long)(charp)+bytes_in_first_buf_page+((pn[j]-sec_start-1)<<Block_Size_Bits); } if(pn[j]==sec_end) pageendbyte=((*off+len-1)&(Block_Size-1)); else pageendbyte=Block_Size-1; pagelen=(unsigned long)(pageendbyte-pagestartbyte+1); if(inf->igflags & igflag_secure){ struct GSFS_page *gp=(struct GSFS_page*)page_private(res[j]); if(unlikely(!gp || !gp->sip) || unlikely(!(gp->sip->spflags & spflag_page_is_ready_for_read)) ){ //printk("<0>" "page is not ready for inode:%lu, index: %lu\n", inode->i_ino, res[j]->index); //if(gp && gp->sip) // printk("<0>" "and flags:%d\n",gp->sip->spflags); goto add_cont; } } i=__copy_to_user_inatomic((void*)bufstart,page_address(res[j])+pagestartbyte,pagelen); add_cont: rlen+=(pagelen-i); mark_page_accessed(res[j]); /* dest=(char*)bufstart; src=(char*)pagestartbyte; for(i=0;i<pagelen;i++) dest[i]=src[i]; */ //printk("<0>" "asdfasd%s",dest); //rlen+=i; GSFS_put_data_page_of_inode(inode,res[j]); //gwf(printk("<0>" "file read for inode:%lu, j:%u pn[j]:%u pagestartbyte:%lx bufstart:%lx pagelen:%lu i:%u sec_start:%lu\n", // inode->i_ino, j, pn[j],(unsigned long)pagestartbyte,(unsigned long)bufstart,pagelen,i,sec_start)); } lock=1; pncount=pn2count; pn2count=0; pntemp=pn2; pn2=pn; pn=pntemp; restemp=res2; res2=res; res=restemp; gwf(printk("<0>" "file read for inode:%lu pncount:%u\n",inode->i_ino,pncount)); }while(pncount); kfree(pn); kfree(pn2); kfree(res); kfree(res2); (*off)+=rlen; gwf(printk("<0>" "file read ends rlen=%lu len:%lu\n",rlen,len)); return rlen; }
ssize_t GSFS_file_write(struct file *filp, const char __user *buf, size_t len, loff_t *off){ struct inode *inode=filp->f_mapping->host; struct address_space *mapping=filp->f_mapping; sector_t sec_start, sec_end, sec_len; unsigned long bufstart, bytes_in_first_buf_page, bytes_in_last_buf_page, pagestartbyte, pageendbyte, pagelen; size_t rlen; struct page *res[2], *page, **pages; unsigned int i, j, pages_count, start_read, end_read; gwf(printk("<0>" "File write with inode :%lu len:%lu offset:%llu , filepos:%llu, buf:%lx inode_size:%llu, pid:%u\n",inode->i_ino,len,*off,filp->f_pos,(unsigned long)buf,inode->i_size,current->pid)); if(unlikely(!access_ok(VERIFY_READ,buf,len))) return -1; mutex_lock(&inode->i_mutex); if((*off+len)>inode->i_size){ if((*off+len)>inode->i_sb->s_maxbytes) return -1; inode->i_size=(*off+len); GSFS_truncate(inode); } if(filp->f_flags & O_APPEND) *off=inode->i_size; current->backing_dev_info=mapping->backing_dev_info; file_remove_suid(filp); file_update_time(filp); //inode_inc_iversion(inode); sec_start=(*off)>>Block_Size_Bits; sec_end=(*off+len-1)>>Block_Size_Bits; sec_len=sec_end-sec_start+1; pages=kzalloc(sizeof(struct page*) * sec_len, GFP_KERNEL); bytes_in_first_buf_page=Block_Size-((*off)&((unsigned long)Block_Size-1)); bytes_in_last_buf_page=((*off+len)&((unsigned long)Block_Size-1)); if(bytes_in_last_buf_page==0) bytes_in_last_buf_page=Block_Size; start_read=(bytes_in_first_buf_page!=Block_Size)?1:0; end_read=(bytes_in_last_buf_page!=Block_Size && inode->i_size>(*off+len))?1:0; gwf(printk("<0>" "GSFS write bytes_in_first_buf_page:%lu, bytes_in_last_buf_page:%lu\n",bytes_in_first_buf_page,bytes_in_last_buf_page)); gwf(printk("<0>" "GSFS write start_read:%u, end_read:%u, sec_start:%lu, sec_end:%lu\n",start_read,end_read,sec_start,sec_end)); if(sec_start==sec_end){ if(start_read || end_read){ res[0]=GSFS_get_data_page_of_inode_with_read(inode, sec_start); gwf(printk("<0>" "sec_start==sec_end, start_read || end_read , res[0]=%lx",(unsigned long)res[0])); } else{ res[0]=GSFS_get_locked_data_page_of_inode_without_read(inode,sec_start); if(likely(res[0])) unlock_page(res[0]); gwf(printk("<0>" "sec_start==sec_end, !(start_read || end_read) , res[0]=%lx",(unsigned long)res[0])); } res[1]=0; if(unlikely(!res[0])){ gwf(printk("<0>" "GSFS write len:-1\n")); mutex_unlock(&inode->i_mutex); printk("<1>" "GSFS write len:-1\n"); kfree(pages); return len; } } else{ if(start_read){ res[0]=GSFS_get_data_page_of_inode_with_read(inode, sec_start); gwf(printk("<0>" "sec_start!=sec_end, start_read, res[0]=%lx",(unsigned long)res[0])); } else{ res[0]=GSFS_get_locked_data_page_of_inode_without_read(inode,sec_start); if(likely(res[0])) unlock_page(res[0]); gwf(printk("<0>" "sec_start!=sec_end, !start_read, res[0]=%lx",(unsigned long)res[0])); } } pages_count=0; if(sec_len>1) for(i=sec_start+1;i<=sec_end-1;i++) pages[pages_count++]=GSFS_get_locked_data_page_of_inode_without_read(inode,i); if(sec_start != sec_end){ if(end_read){ res[1]=GSFS_get_data_page_of_inode_with_read(inode,sec_end); gwf(printk("<0>" "sec_start!=sec_end, end_read, res[1]=%lx",(unsigned long)res[1])); } else{ res[1]=GSFS_get_locked_data_page_of_inode_without_read(inode,sec_end); if(likely(res[1])) unlock_page(res[1]); gwf(printk("<0>" "sec_start!=sec_end, !end_read, res[1]=%lx",(unsigned long)res[1])); } if(unlikely(!res[0] || !res[1])){ gwf(printk("<0>" "GSFS write len:-1\n")); printk("<1>" "GSFS write len:-1\n"); mutex_unlock(&inode->i_mutex); kfree(pages); return len; } } rlen=0; bufstart=(unsigned long)buf+bytes_in_first_buf_page; pagelen=Block_Size; //100% expected complete pages that should be copied pages_count=0; if(sec_len>1) for(i=sec_start+1;i<=sec_end-1;i++){ gwf(printk("<0>" "write page complete pages, i:%u, bufstart:%lx, rlen=%lu\n",i,bufstart,rlen)); page=pages[pages_count++]; if(unlikely(!page)) goto buf_cont; j=__copy_from_user_inatomic(page_address(page),(void*)bufstart,pagelen); rlen+=(Block_Size-j); mark_page_accessed(page); set_page_dirty(page); put_page(page); unlock_page(page); buf_cont: bufstart+=pagelen; } //first and last page that are not surely complete for(i=0;i<2 && res[i];i++){ page=res[i]; wait_on_page_locked(page); lock_page(page); if(page->index==sec_start){ bufstart=(unsigned long)buf; pagestartbyte=Block_Size-bytes_in_first_buf_page; if(sec_start==sec_end) pageendbyte=pagestartbyte+len-1; else pageendbyte=Block_Size-1; } else{ bufstart=(unsigned long)buf+bytes_in_first_buf_page+((sec_len-2)<<Block_Size_Bits); pageendbyte=bytes_in_last_buf_page-1; pagestartbyte=0; } gwf(printk("<0>" "gsfs_write for first and last page, i=%u, page:%lx, bufstart:%lx, pagestartbyte:%lu, pageendbyte:%lu\n", i,(unsigned long)page,bufstart,pagestartbyte,pageendbyte)); pagelen=pageendbyte-pagestartbyte+1; j=__copy_from_user_inatomic(page_address(page)+pagestartbyte,(void*)bufstart,pagelen); rlen+=(pagelen-j); mark_page_accessed(page); set_page_dirty(page); put_page(page); unlock_page(page); } mutex_unlock(&inode->i_mutex); (*off)+=rlen; gwf(printk("<0>" "GSFS write rlen:%lu\n",rlen)); kfree(pages); if(filp->f_flags & O_SYNC){ write_inode_now(inode,1); } return rlen; }