static int lfs_readpage(struct file *file, struct page *page) { struct inode *inode = page->mapping->host; sector_t iblock, block; unsigned int blocksize; struct buffer_head *bh, *head; blocksize = 1 << inode->i_blkbits; if (!page_has_buffers(page)) create_empty_buffers(page, blocksize, 0); head = page_buffers(page); bh = head; iblock = (sector_t)page->index << (PAGE_CACHE_SHIFT - inode->i_blkbits); do { struct buffer_head *bh_temp; block = lfs_disk_block(inode, iblock); dprintk("searching for block %Lu in segments: ", (long long unsigned int)block); bh_temp = lfs_read_block(inode, iblock); if(bh_temp) { dprintk("FOUND\n"); memcpy(bh->b_data, bh_temp->b_data, LFS_BSIZE); set_buffer_uptodate(bh); brelse(bh_temp); } else dprintk("NOT FOUND\n"); } while (iblock++, (bh = bh->b_this_page) != head); return block_read_full_page(page, lfs_map_block); }
/* Reads the seguse entry for the corresponding segment and returns the * buffer head containing it. Note that *pseguse points to the segusage within * the returned buffer head data */ static struct buffer_head *segusetbl_read_entry( struct super_block *sb, int segnum, struct segusage **pseguse) { int offset, iblock; struct buffer_head *bh; struct inode *inode = SEGUSETBL_INODE(sb); if(segnum > nseguse(inode) - 1) /* new entry */ return NULL; /* read the block from the disk */ iblock = get_iblock_nr(segnum); //dprintk("iblock for segusetable = %d\n", iblock); bh = lfs_read_block(inode, iblock); if(!bh) return NULL; offset = LFS_CI_SIZE + LFS_SEGUSE_SIZE * segnum; offset -= iblock * LFS_BSIZE; *pseguse = (struct segusage *)((char *)bh->b_data + offset); return bh; /* caller has to release the bh, after done with *pseguse */ }
static int lfs_readdir (struct file * f, void * dirent, filldir_t filldir) { lfs_dirent *de; int block; int reclen = LFS_DIRENT_RECLEN; unsigned int offset; struct buffer_head * bh; struct inode * dir = f->f_dentry->d_inode; while (f->f_pos < dir->i_size) { offset = f->f_pos & (LFS_BSIZE-1); block = f->f_pos >> LFS_BSIZE_BITS; bh = lfs_read_block(dir, block); if (!bh) goto err_eio; do { //dprintk("block = %d, offset = %d\n", block, offset); de = (lfs_dirent *)(bh->b_data + offset); if (de->inode) { //dprintk("Filling entries for %d %s %d\n", de->inode, de->name, de->name_len); if (filldir(dirent, de->name, de->name_len, f->f_pos, de->inode, DT_UNKNOWN) < 0) { brelse(bh); goto done; } } offset += reclen; f->f_pos += reclen; } while (offset < LFS_BSIZE && f->f_pos < dir->i_size); brelse(bh); } done: return 0; err_eio: return -EIO; }
/* FIXME: Ugliest function of all in LFS, need I say more? */ static ssize_t lfs_file_write( struct file *file, const char __user *buf, size_t count, loff_t *ppos) { loff_t pos; struct page *page; ssize_t res, written, bytes; struct inode *inode = file->f_dentry->d_inode; struct super_block *sb = inode->i_sb; struct segment *segp = LFS_SBI(sb)->s_curr; //dprintk("lfs_file_write called for %lu at pos %Lu\n", inode->i_ino, *ppos); if(file->f_flags & O_DIRECT) { dprintk("The file is requesting direct IO\n"); return -EINVAL; } if (unlikely(count < 0 )) return -EINVAL; if (unlikely(!access_ok(VERIFY_READ, buf, count))) return -EFAULT; //down(&inode->i_sem); /* lock the file */ mutex_lock(&inode->i_mutex); //BrechREiZ: We need this for Kernel 2.6.17 lfs_lock(sb); pos = *ppos; res = generic_write_checks(file, &pos, &count, 0); if (res) goto out; if(count == 0) goto out; res = remove_suid(file->f_dentry); if(res) goto out; //inode_update_time(inode, 1); /* update mtime and ctime */ file_update_time(inode); //BrechREiZ: We need this for Kernel 2.6.17 written = 0; do { long offset; size_t copied; int i, siblock, eiblock, boffset; sector_t block; offset = (segp->offset % BUF_IN_PAGE) * LFS_BSIZE; offset += pos & (LFS_BSIZE - 1); /* within block */ bytes = PAGE_CACHE_SIZE - offset; /* number of bytes written in this iteration */ invalidate_old_page(inode, pos); if (bytes > count) bytes = count; //dprintk("1:segp->start=%Lu,segp->offset=%d,segp->end=%Lu,offset=%lu,bytes=%d\n", segp->start, segp->offset, segp->end,offset,bytes); siblock = pos >> LFS_BSIZE_BITS; eiblock = (pos + bytes - 1) >> LFS_BSIZE_BITS; //dprintk("writing %d bytes at offset %ld (pos = %Lu)\n", bytes, offset, pos); //dprintk("siblock = %d, eiblock = %d\n", siblock, eiblock); /* * Bring in the user page that we will copy from _first_. * Otherwise there's a nasty deadlock on copying from the * same page as we're writing to, without it being marked * up-to-date. */ fault_in_pages_readable(buf, bytes); page = get_seg_page(segp); if (!page) { res = -ENOMEM; break; } /* fill the page with current inode blocks if any */ boffset = offset / LFS_BSIZE;; for(i = siblock; i <= eiblock; ++i, ++boffset) { struct buffer_head *bh; //dprintk("Asking for block %d\n", i); bh = lfs_read_block(inode, i); if(!bh) /* new block */ break; //dprintk("boffset = %d\n", boffset); memcpy(page_address(page) + LFS_BSIZE * boffset, bh->b_data, LFS_BSIZE); brelse(bh); } copied = __copy_from_user(page_address(page) + offset, buf, bytes); flush_dcache_page(page); block = segp->start + segp->offset; for(i = siblock;i <= eiblock; ++i, ++block) segsum_update_finfo(segp, inode->i_ino, i, block); block = segp->start + segp->offset; segp->offset += (bytes - 1)/LFS_BSIZE + 1; //dprintk("2:segp->start=%Lu,segp->offset=%d,segp->end=%Lu,offset=%lu,bytes=%d\n", //segp->start, segp->offset, segp->end,offset,bytes); BUG_ON(segp->start + segp->offset > segp->end); if(segp->start + segp->offset == segp->end) { dprintk("allocating new segment\n"); /* This also is going to write the previous segment */ segment_allocate_new(inode->i_sb, segp, segp->start + segp->offset); segp = LFS_SBI(sb)->s_curr; } /* update the inode */ for(i = siblock;i <= eiblock; ++i, ++block) update_inode(inode, i, block); //dprintk("start=%Lu,offset=%d,end=%Lu\n", segp->start, segp->offset, segp->end); segusetbl_add_livebytes(sb, segp->segnum, bytes); written += bytes; buf += bytes; pos += bytes; count -= bytes; } while(count); *ppos = pos; if(pos > inode->i_size) i_size_write(inode, pos); if(written) mark_inode_dirty(inode); lfs_unlock(sb); //up(&inode->i_sem); mutex_unlock(&inode->i_mutex); //BrechREiZ: and unlocking... return written ? written : res; out: lfs_unlock(sb); //up(&inode->i_sem); mutex_unlock(&inode->i_mutex); //BrechREiZ: and unlocking... return res; }