static void *cramfs_read_nand(struct super_block *sb, unsigned int offset, unsigned int len) { unsigned i, blocknr, buffer; char *data; struct cramfs_sb_info *sbi = sb->s_fs_info; struct mtd_info *mtd = sbi->mtd; unsigned mblock, moffset, pblock, maddr; int retv; size_t dummy; if (!len) return NULL; blocknr = offset >> PAGE_CACHE_SHIFT; /* 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 & (PAGE_CACHE_SIZE - 1)); if (blk_offset + len > BUFFER_SIZE) continue; return read_buffers[i] + blk_offset; } buffer = next_buffer; next_buffer = NEXT_BUFFER(buffer); buffer_blocknr[buffer] = blocknr; buffer_dev[buffer] = sb; mblock = offset / mtd->erasesize; moffset = (offset & (mtd->erasesize - 1)) & (~(PAGE_CACHE_SIZE - 1)); offset &= (PAGE_CACHE_SIZE - 1); pblock = get_block_map(sb, mblock); maddr = pblock * mtd->erasesize + moffset; data = read_buffers[buffer]; if (moffset + BUFFER_SIZE <= mtd->erasesize) { retv = mtd->read(mtd, maddr, BUFFER_SIZE, &dummy, data); } else { int read_size; read_size = mtd->erasesize - moffset; retv = mtd->read(mtd, maddr, read_size, &dummy, data); pblock = get_block_map(sb, mblock + 1); maddr = pblock * mtd->erasesize; retv = mtd->read(mtd, maddr, (BUFFER_SIZE - read_size), &dummy, data + read_size); } return read_buffers[buffer] + offset; }
/*===========================================================================* * fs_rdlink * *===========================================================================*/ int fs_rdlink() { struct buf *bp = NULL; /* buffer containing link text */ char* link_text; /* either bp->b_data or rip->i_block */ register struct inode *rip; /* target inode */ register int r; /* return value */ size_t copylen; copylen = min( (size_t) fs_m_in.REQ_MEM_SIZE, UMAX_FILE_POS); /* Temporarily open the file. */ if( (rip = get_inode(fs_dev, (ino_t) fs_m_in.REQ_INODE_NR)) == NULL) return(EINVAL); if (rip->i_size >= MAX_FAST_SYMLINK_LENGTH) { /* normal symlink */ if(!(bp = get_block_map(rip, 0))) { r = EIO; } else { link_text = b_data(bp); r = OK; } } else { /* fast symlink, stored in inode */ link_text = (char*) rip->i_block; r = OK; } if (r == OK) { /* Passed all checks */ /* We can safely cast to unsigned, because copylen is guaranteed to be below max file size */ copylen = min( copylen, (unsigned) rip->i_size); r = sys_safecopyto(VFS_PROC_NR, (cp_grant_id_t) fs_m_in.REQ_GRANT, (vir_bytes) 0, (vir_bytes) link_text, (size_t) copylen); put_block(bp, DIRECTORY_BLOCK); if (r == OK) fs_m_out.RES_NBYTES = copylen; } put_inode(rip); return(r); }
/*===========================================================================* * fs_rdlink * *===========================================================================*/ ssize_t fs_rdlink(ino_t ino_nr, struct fsdriver_data *data, size_t bytes) { struct buf *bp = NULL; /* buffer containing link text */ char* link_text; /* either bp->b_data or rip->i_block */ register struct inode *rip; /* target inode */ register int r; /* return value */ /* Temporarily open the file. */ if( (rip = get_inode(fs_dev, ino_nr)) == NULL) return(EINVAL); if (rip->i_size >= MAX_FAST_SYMLINK_LENGTH) { /* normal symlink */ if(!(bp = get_block_map(rip, 0))) { r = EIO; } else { link_text = b_data(bp); r = OK; } } else { /* fast symlink, stored in inode */ link_text = (char*) rip->i_block; r = OK; } if (r == OK) { /* Passed all checks */ if (bytes > rip->i_size) bytes = rip->i_size; r = fsdriver_copyout(data, 0, link_text, bytes); put_block(bp, DIRECTORY_BLOCK); if (r == OK) r = bytes; } put_inode(rip); return(r); }