/* Primary function to update the seguse_table. Updates the segusage entry for * the partiulcar segment. */ void segusetbl_update_entry(struct super_block *sb, int segnum, struct segusage *seguse) { int offset; sector_t newblock; struct buffer_head *bh; struct inode *inode = SEGUSETBL_INODE(sb); struct segusage *pseguse = NULL; if(is_new_segment(segnum, inode)) inode->i_size += LFS_SEGUSE_SIZE; bh = segusetbl_read_entry(sb, segnum, &pseguse); /* update the seguse_table */ if(bh) { /* updating the in-memory contents */ //dprintk("Updating in-memory contents\n"); offset = LFS_CI_SIZE + LFS_SEGUSE_SIZE * segnum; offset = offset % LFS_BSIZE; //dprintk("Updating at offset = %d\n", offset); newblock = segment_write_block_from_bh( sb, seguse, LFS_SEGUSE_SIZE, offset, bh); if(newblock != bh->b_blocknr) update_inode(inode, get_iblock_nr(segnum), newblock); brelse(bh); } else { /* new seguse entry */ offset = 0; newblock = segment_write_block( sb, seguse, LFS_SEGUSE_SIZE, offset, 0); update_inode(inode, get_iblock_nr(segnum), newblock); //dprintk("updating %Lu to %Lu block\n", get_iblock_nr(segp), newblock); } mark_inode_dirty(inode); }
bool recover_inline_data(struct inode *inode, struct page *npage) { struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct f2fs_inode *ri = NULL; void *src_addr, *dst_addr; struct page *ipage; /* * The inline_data recovery policy is as follows. * [prev.] [next] of inline_data flag * o o -> recover inline_data * o x -> remove inline_data, and then recover data blocks * x o -> remove inline_data, and then recover inline_data * x x -> recover data blocks */ if (IS_INODE(npage)) ri = F2FS_INODE(npage); if (f2fs_has_inline_data(inode) && ri && (ri->i_inline & F2FS_INLINE_DATA)) { process_inline: ipage = get_node_page(sbi, inode->i_ino); f2fs_bug_on(sbi, IS_ERR(ipage)); f2fs_wait_on_page_writeback(ipage, NODE); src_addr = inline_data_addr(npage); dst_addr = inline_data_addr(ipage); memcpy(dst_addr, src_addr, MAX_INLINE_DATA); set_inode_flag(F2FS_I(inode), FI_INLINE_DATA); set_inode_flag(F2FS_I(inode), FI_DATA_EXIST); update_inode(inode, ipage); f2fs_put_page(ipage, 1); return true; } if (f2fs_has_inline_data(inode)) { ipage = get_node_page(sbi, inode->i_ino); f2fs_bug_on(sbi, IS_ERR(ipage)); truncate_inline_inode(ipage, 0); f2fs_clear_inline_inode(inode); update_inode(inode, ipage); f2fs_put_page(ipage, 1); } else if (ri && (ri->i_inline & F2FS_INLINE_DATA)) { truncate_blocks(inode, 0, false); goto process_inline; } return false; }
void f2fs_drop_nlink(struct inode *dir, struct inode *inode, struct page *page) { struct f2fs_sb_info *sbi = F2FS_I_SB(dir); down_write(&F2FS_I(inode)->i_sem); if (S_ISDIR(inode->i_mode)) { drop_nlink(dir); if (page) update_inode(dir, page); else update_inode_page(dir); } inode->i_ctime = CURRENT_TIME; drop_nlink(inode); if (S_ISDIR(inode->i_mode)) { drop_nlink(inode); i_size_write(inode, 0); } up_write(&F2FS_I(inode)->i_sem); update_inode_page(inode); if (inode->i_nlink == 0) add_orphan_inode(sbi, inode->i_ino); else release_orphan_inode(sbi); }
int gen_inum(MFS_Header_t **header, int offset) { int i, j, tmp_offset; MFS_Imap_t *imap_temp; void *block_ptr = (void *)(*header) + sizeof(MFS_Header_t); i = 0; while(i < 4096/ 14) { if((*header)->map[i] == -1) { imap_temp = allot_space(header, sizeof(MFS_Imap_t), &tmp_offset); for(j = 0; j < 14; j++) { imap_temp->inodes[j] = -1; } imap_temp->inodes[0] = offset; (*header)->map[i] = tmp_offset; return (i * 14) + 0; } else { imap_temp = (MFS_Imap_t *)(block_ptr + (*header)->map[i]); for(j = 0; j < 14; j++) { if(imap_temp->inodes[j] == -1) { update_inode(header, (i * 14) + j, offset); return (i * 14) + j; } } } i++; } return -1; }
int recover_inline_data(struct inode *inode, struct page *npage) { struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); struct f2fs_inode *ri = NULL; void *src_addr, *dst_addr; struct page *ipage; /* * The inline_data recovery policy is as follows. * [prev.] [next] of inline_data flag * o o -> recover inline_data * o x -> remove inline_data, and then recover data blocks * x o -> remove inline_data, and then recover inline_data * x x -> recover data blocks */ if (IS_INODE(npage)) ri = F2FS_INODE(npage); if (f2fs_has_inline_data(inode) && ri && ri->i_inline & F2FS_INLINE_DATA) { process_inline: ipage = get_node_page(sbi, inode->i_ino); f2fs_bug_on(IS_ERR(ipage)); src_addr = inline_data_addr(npage); dst_addr = inline_data_addr(ipage); memcpy(dst_addr, src_addr, MAX_INLINE_DATA); update_inode(inode, ipage); f2fs_put_page(ipage, 1); return -1; } if (f2fs_has_inline_data(inode)) { ipage = get_node_page(sbi, inode->i_ino); f2fs_bug_on(IS_ERR(ipage)); zero_user_segment(ipage, INLINE_DATA_OFFSET, INLINE_DATA_OFFSET + MAX_INLINE_DATA); clear_inode_flag(F2FS_I(inode), FI_INLINE_DATA); update_inode(inode, ipage); f2fs_put_page(ipage, 1); } else if (ri && ri->i_inline & F2FS_INLINE_DATA) { truncate_blocks(inode, 0); set_inode_flag(F2FS_I(inode), FI_INLINE_DATA); goto process_inline; } return 0; }
static int change_root_fmap (tree_s *tree, buf_s *root) { info_s *file = container(tree, info_s, in_tree); int rc; FN; file->in_inode.i_root = root->b_blkno; rc = update_inode( &file->in_inode); return rc; }
int update_inode_page(struct inode *inode) { struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); struct page *node_page; node_page = get_node_page(sbi, inode->i_ino); if (IS_ERR(node_page)) return PTR_ERR(node_page); update_inode(inode, node_page); f2fs_put_page(node_page, 1); return 0; }
void update_inode_page(struct inode *inode) { struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct page *node_page; retry: node_page = get_node_page(sbi, inode->i_ino); if (IS_ERR(node_page)) { int err = PTR_ERR(node_page); if (err == -ENOMEM) { cond_resched(); goto retry; } else if (err != -ENOENT) { f2fs_stop_checkpoint(sbi); } return; } update_inode(inode, node_page); f2fs_put_page(node_page, 1); }
int f2fs_do_tmpfile(struct inode *inode, struct inode *dir) { struct page *page; int err = 0; down_write(&F2FS_I(inode)->i_sem); page = init_inode_metadata(inode, dir, NULL); if (IS_ERR(page)) { err = PTR_ERR(page); goto fail; } /* we don't need to mark_inode_dirty now */ update_inode(inode, page); f2fs_put_page(page, 1); clear_inode_flag(F2FS_I(inode), FI_NEW_INODE); fail: up_write(&F2FS_I(inode)->i_sem); return err; }
/* * Caller should grab and release a rwsem by calling f2fs_lock_op() and * f2fs_unlock_op(). */ int __f2fs_add_link(struct inode *dir, const struct qstr *name, struct inode *inode) { unsigned int bit_pos; unsigned int level; unsigned int current_depth; unsigned long bidx, block; f2fs_hash_t dentry_hash; struct f2fs_dir_entry *de; unsigned int nbucket, nblock; size_t namelen = name->len; struct page *dentry_page = NULL; struct f2fs_dentry_block *dentry_blk = NULL; int slots = GET_DENTRY_SLOTS(namelen); struct page *page; int err = 0; int i; dentry_hash = f2fs_dentry_hash(name); level = 0; current_depth = F2FS_I(dir)->i_current_depth; if (F2FS_I(dir)->chash == dentry_hash) { level = F2FS_I(dir)->clevel; F2FS_I(dir)->chash = 0; } start: if (unlikely(current_depth == MAX_DIR_HASH_DEPTH)) return -ENOSPC; /* Increase the depth, if required */ if (level == current_depth) ++current_depth; nbucket = dir_buckets(level, F2FS_I(dir)->i_dir_level); nblock = bucket_blocks(level); bidx = dir_block_index(level, F2FS_I(dir)->i_dir_level, (le32_to_cpu(dentry_hash) % nbucket)); for (block = bidx; block <= (bidx + nblock - 1); block++) { dentry_page = get_new_data_page(dir, NULL, block, true); if (IS_ERR(dentry_page)) return PTR_ERR(dentry_page); dentry_blk = kmap(dentry_page); bit_pos = room_for_filename(dentry_blk, slots); if (bit_pos < NR_DENTRY_IN_BLOCK) goto add_dentry; kunmap(dentry_page); f2fs_put_page(dentry_page, 1); } /* Move to next level to find the empty slot for new dentry */ ++level; goto start; add_dentry: f2fs_wait_on_page_writeback(dentry_page, DATA); down_write(&F2FS_I(inode)->i_sem); page = init_inode_metadata(inode, dir, name); if (IS_ERR(page)) { err = PTR_ERR(page); goto fail; } de = &dentry_blk->dentry[bit_pos]; de->hash_code = dentry_hash; de->name_len = cpu_to_le16(namelen); memcpy(dentry_blk->filename[bit_pos], name->name, name->len); de->ino = cpu_to_le32(inode->i_ino); set_de_type(de, inode); for (i = 0; i < slots; i++) test_and_set_bit_le(bit_pos + i, &dentry_blk->dentry_bitmap); set_page_dirty(dentry_page); /* we don't need to mark_inode_dirty now */ F2FS_I(inode)->i_pino = dir->i_ino; update_inode(inode, page); f2fs_put_page(page, 1); update_parent_metadata(dir, inode, current_depth); fail: up_write(&F2FS_I(inode)->i_sem); if (is_inode_flag_set(F2FS_I(dir), FI_UPDATE_DIR)) { update_inode_page(dir); clear_inode_flag(F2FS_I(dir), FI_UPDATE_DIR); } kunmap(dentry_page); f2fs_put_page(dentry_page, 1); return err; }
static int __f2fs_setxattr(struct inode *inode, int index, const char *name, const void *value, size_t size, struct page *ipage, int flags) { struct f2fs_inode_info *fi = F2FS_I(inode); struct f2fs_xattr_entry *here, *last; void *base_addr; int found, newsize; size_t len; __u32 new_hsize; int error = -ENOMEM; if (name == NULL) return -EINVAL; if (value == NULL) size = 0; len = strlen(name); if (len > F2FS_NAME_LEN || size > MAX_VALUE_LEN(inode)) return -ERANGE; base_addr = read_all_xattrs(inode, ipage); if (!base_addr) goto exit; /* find entry with wanted name. */ here = __find_xattr(base_addr, index, len, name); found = IS_XATTR_LAST_ENTRY(here) ? 0 : 1; if ((flags & XATTR_REPLACE) && !found) { error = -ENODATA; goto exit; } else if ((flags & XATTR_CREATE) && found) { error = -EEXIST; goto exit; } last = here; while (!IS_XATTR_LAST_ENTRY(last)) last = XATTR_NEXT_ENTRY(last); newsize = XATTR_ALIGN(sizeof(struct f2fs_xattr_entry) + len + size); /* 1. Check space */ if (value) { int free; /* * If value is NULL, it is remove operation. * In case of update operation, we caculate free. */ free = MIN_OFFSET(inode) - ((char *)last - (char *)base_addr); if (found) free = free + ENTRY_SIZE(here); if (unlikely(free < newsize)) { error = -ENOSPC; goto exit; } } /* 2. Remove old entry */ if (found) { /* * If entry is found, remove old entry. * If not found, remove operation is not needed. */ struct f2fs_xattr_entry *next = XATTR_NEXT_ENTRY(here); int oldsize = ENTRY_SIZE(here); memmove(here, next, (char *)last - (char *)next); last = (struct f2fs_xattr_entry *)((char *)last - oldsize); memset(last, 0, oldsize); } new_hsize = (char *)last - (char *)base_addr; /* 3. Write new entry */ if (value) { char *pval; /* * Before we come here, old entry is removed. * We just write new entry. */ memset(last, 0, newsize); last->e_name_index = index; last->e_name_len = len; memcpy(last->e_name, name, len); pval = last->e_name + len; memcpy(pval, value, size); last->e_value_size = cpu_to_le16(size); new_hsize += newsize; } error = write_all_xattrs(inode, new_hsize, base_addr, ipage); if (error) goto exit; if (is_inode_flag_set(fi, FI_ACL_MODE)) { inode->i_mode = fi->i_acl_mode; inode->i_ctime = CURRENT_TIME; clear_inode_flag(fi, FI_ACL_MODE); } if (ipage) update_inode(inode, ipage); else update_inode_page(inode); exit: kzfree(base_addr); return error; }
int f2fs_add_inline_entry(struct inode *dir, const struct qstr *name, struct inode *inode, nid_t ino, umode_t mode) { struct f2fs_sb_info *sbi = F2FS_I_SB(dir); struct page *ipage; unsigned int bit_pos; f2fs_hash_t name_hash; size_t namelen = name->len; struct f2fs_inline_dentry *dentry_blk = NULL; struct f2fs_dentry_ptr d; int slots = GET_DENTRY_SLOTS(namelen); struct page *page = NULL; int err = 0; ipage = get_node_page(sbi, dir->i_ino); if (IS_ERR(ipage)) return PTR_ERR(ipage); dentry_blk = inline_data_addr(ipage); bit_pos = room_for_filename(&dentry_blk->dentry_bitmap, slots, NR_INLINE_DENTRY); if (bit_pos >= NR_INLINE_DENTRY) { err = f2fs_convert_inline_dir(dir, ipage, dentry_blk); if (!err) err = -EAGAIN; goto out; } if (inode) { down_write(&F2FS_I(inode)->i_sem); page = init_inode_metadata(inode, dir, name, ipage); if (IS_ERR(page)) { err = PTR_ERR(page); goto fail; } } f2fs_wait_on_page_writeback(ipage, NODE); name_hash = f2fs_dentry_hash(name); make_dentry_ptr(NULL, &d, (void *)dentry_blk, 2); f2fs_update_dentry(ino, mode, &d, name, name_hash, bit_pos); set_page_dirty(ipage); /* we don't need to mark_inode_dirty now */ if (inode) { F2FS_I(inode)->i_pino = dir->i_ino; update_inode(inode, page); f2fs_put_page(page, 1); } update_parent_metadata(dir, inode, 0); fail: if (inode) up_write(&F2FS_I(inode)->i_sem); if (is_inode_flag_set(F2FS_I(dir), FI_UPDATE_DIR)) { update_inode(dir, ipage); clear_inode_flag(F2FS_I(dir), FI_UPDATE_DIR); } out: f2fs_put_page(ipage, 1); return err; }
/* 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; }
int f2fs_add_inline_entry(struct inode *dir, const struct qstr *name, struct inode *inode) { struct f2fs_sb_info *sbi = F2FS_I_SB(dir); struct page *ipage; unsigned int bit_pos; f2fs_hash_t name_hash; struct f2fs_dir_entry *de; size_t namelen = name->len; struct f2fs_inline_dentry *dentry_blk = NULL; int slots = GET_DENTRY_SLOTS(namelen); struct page *page; int err = 0; int i; name_hash = f2fs_dentry_hash(name); ipage = get_node_page(sbi, dir->i_ino); if (IS_ERR(ipage)) return PTR_ERR(ipage); dentry_blk = inline_data_addr(ipage); bit_pos = room_for_filename(&dentry_blk->dentry_bitmap, slots, NR_INLINE_DENTRY); if (bit_pos >= NR_INLINE_DENTRY) { err = f2fs_convert_inline_dir(dir, ipage, dentry_blk); if (!err) err = -EAGAIN; goto out; } down_write(&F2FS_I(inode)->i_sem); page = init_inode_metadata(inode, dir, name, ipage); if (IS_ERR(page)) { err = PTR_ERR(page); goto fail; } f2fs_wait_on_page_writeback(ipage, NODE); de = &dentry_blk->dentry[bit_pos]; de->hash_code = name_hash; de->name_len = cpu_to_le16(namelen); memcpy(dentry_blk->filename[bit_pos], name->name, name->len); de->ino = cpu_to_le32(inode->i_ino); set_de_type(de, inode); for (i = 0; i < slots; i++) test_and_set_bit_le(bit_pos + i, &dentry_blk->dentry_bitmap); set_page_dirty(ipage); /* we don't need to mark_inode_dirty now */ F2FS_I(inode)->i_pino = dir->i_ino; update_inode(inode, page); f2fs_put_page(page, 1); update_parent_metadata(dir, inode, 0); fail: up_write(&F2FS_I(inode)->i_sem); if (is_inode_flag_set(F2FS_I(dir), FI_UPDATE_DIR)) { update_inode(dir, ipage); clear_inode_flag(F2FS_I(dir), FI_UPDATE_DIR); } out: f2fs_put_page(ipage, 1); return err; }
struct inode *f2fs_iget_nowait(struct super_block *sb, unsigned long ino) { struct f2fs_iget_args args = { .ino = ino, .on_free = 0 }; struct inode *inode = ilookup5(sb, ino, f2fs_iget_test, &args); if (inode) return inode; if (!args.on_free) return f2fs_iget(sb, ino); return ERR_PTR(-ENOENT); } static int do_read_inode(struct inode *inode) { struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); struct f2fs_inode_info *fi = F2FS_I(inode); struct page *node_page; struct f2fs_node *rn; struct f2fs_inode *ri; /* Check if ino is within scope */ check_nid_range(sbi, inode->i_ino); node_page = get_node_page(sbi, inode->i_ino); if (IS_ERR(node_page)) return PTR_ERR(node_page); rn = page_address(node_page); ri = &(rn->i); inode->i_mode = le16_to_cpu(ri->i_mode); i_uid_write(inode, le32_to_cpu(ri->i_uid)); i_gid_write(inode, le32_to_cpu(ri->i_gid)); set_nlink(inode, le32_to_cpu(ri->i_links)); inode->i_size = le64_to_cpu(ri->i_size); inode->i_blocks = le64_to_cpu(ri->i_blocks); inode->i_atime.tv_sec = le64_to_cpu(ri->i_atime); inode->i_ctime.tv_sec = le64_to_cpu(ri->i_ctime); inode->i_mtime.tv_sec = le64_to_cpu(ri->i_mtime); inode->i_atime.tv_nsec = le32_to_cpu(ri->i_atime_nsec); inode->i_ctime.tv_nsec = le32_to_cpu(ri->i_ctime_nsec); inode->i_mtime.tv_nsec = le32_to_cpu(ri->i_mtime_nsec); inode->i_generation = le32_to_cpu(ri->i_generation); fi->i_current_depth = le32_to_cpu(ri->i_current_depth); fi->i_xattr_nid = le32_to_cpu(ri->i_xattr_nid); fi->i_flags = le32_to_cpu(ri->i_flags); fi->flags = 0; fi->data_version = le64_to_cpu(F2FS_CKPT(sbi)->checkpoint_ver) - 1; fi->i_advise = ri->i_advise; fi->i_pino = le32_to_cpu(ri->i_pino); get_extent_info(&fi->ext, ri->i_ext); f2fs_put_page(node_page, 1); return 0; } struct inode *f2fs_iget(struct super_block *sb, unsigned long ino) { struct f2fs_sb_info *sbi = F2FS_SB(sb); struct inode *inode; int ret; inode = iget_locked(sb, ino); if (!inode) return ERR_PTR(-ENOMEM); if (!(inode->i_state & I_NEW)) return inode; if (ino == F2FS_NODE_INO(sbi) || ino == F2FS_META_INO(sbi)) goto make_now; ret = do_read_inode(inode); if (ret) goto bad_inode; if (!sbi->por_doing && inode->i_nlink == 0) { ret = -ENOENT; goto bad_inode; } make_now: if (ino == F2FS_NODE_INO(sbi)) { inode->i_mapping->a_ops = &f2fs_node_aops; mapping_set_gfp_mask(inode->i_mapping, GFP_F2FS_ZERO); } else if (ino == F2FS_META_INO(sbi)) { inode->i_mapping->a_ops = &f2fs_meta_aops; mapping_set_gfp_mask(inode->i_mapping, GFP_F2FS_ZERO); } else if (S_ISREG(inode->i_mode)) { inode->i_op = &f2fs_file_inode_operations; inode->i_fop = &f2fs_file_operations; inode->i_mapping->a_ops = &f2fs_dblock_aops; } else if (S_ISDIR(inode->i_mode)) { inode->i_op = &f2fs_dir_inode_operations; inode->i_fop = &f2fs_dir_operations; inode->i_mapping->a_ops = &f2fs_dblock_aops; mapping_set_gfp_mask(inode->i_mapping, GFP_HIGHUSER_MOVABLE | __GFP_ZERO); } else if (S_ISLNK(inode->i_mode)) { inode->i_op = &f2fs_symlink_inode_operations; inode->i_mapping->a_ops = &f2fs_dblock_aops; } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) { inode->i_op = &f2fs_special_inode_operations; init_special_inode(inode, inode->i_mode, inode->i_rdev); } else { ret = -EIO; goto bad_inode; } unlock_new_inode(inode); return inode; bad_inode: iget_failed(inode); return ERR_PTR(ret); } void update_inode(struct inode *inode, struct page *node_page) { struct f2fs_node *rn; struct f2fs_inode *ri; wait_on_page_writeback(node_page); rn = page_address(node_page); ri = &(rn->i); ri->i_mode = cpu_to_le16(inode->i_mode); ri->i_advise = F2FS_I(inode)->i_advise; ri->i_uid = cpu_to_le32(i_uid_read(inode)); ri->i_gid = cpu_to_le32(i_gid_read(inode)); ri->i_links = cpu_to_le32(inode->i_nlink); ri->i_size = cpu_to_le64(i_size_read(inode)); ri->i_blocks = cpu_to_le64(inode->i_blocks); set_raw_extent(&F2FS_I(inode)->ext, &ri->i_ext); ri->i_atime = cpu_to_le64(inode->i_atime.tv_sec); ri->i_ctime = cpu_to_le64(inode->i_ctime.tv_sec); ri->i_mtime = cpu_to_le64(inode->i_mtime.tv_sec); ri->i_atime_nsec = cpu_to_le32(inode->i_atime.tv_nsec); ri->i_ctime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec); ri->i_mtime_nsec = cpu_to_le32(inode->i_mtime.tv_nsec); ri->i_current_depth = cpu_to_le32(F2FS_I(inode)->i_current_depth); ri->i_xattr_nid = cpu_to_le32(F2FS_I(inode)->i_xattr_nid); ri->i_flags = cpu_to_le32(F2FS_I(inode)->i_flags); ri->i_pino = cpu_to_le32(F2FS_I(inode)->i_pino); ri->i_generation = cpu_to_le32(inode->i_generation); set_cold_node(inode, node_page); set_page_dirty(node_page); } int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc) { struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); struct page *node_page; bool need_lock = false; if (inode->i_ino == F2FS_NODE_INO(sbi) || inode->i_ino == F2FS_META_INO(sbi)) return 0; if (wbc) f2fs_balance_fs(sbi); node_page = get_node_page(sbi, inode->i_ino); if (IS_ERR(node_page)) return PTR_ERR(node_page); if (!PageDirty(node_page)) { need_lock = true; f2fs_put_page(node_page, 1); mutex_lock(&sbi->write_inode); node_page = get_node_page(sbi, inode->i_ino); if (IS_ERR(node_page)) { mutex_unlock(&sbi->write_inode); return PTR_ERR(node_page); } } update_inode(inode, node_page); f2fs_put_page(node_page, 1); if (need_lock) mutex_unlock(&sbi->write_inode); return 0; } /* * Called at the last iput() if i_nlink is zero */ void f2fs_evict_inode(struct inode *inode) { struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); truncate_inode_pages(&inode->i_data, 0); if (inode->i_ino == F2FS_NODE_INO(sbi) || inode->i_ino == F2FS_META_INO(sbi)) goto no_delete; BUG_ON(atomic_read(&F2FS_I(inode)->dirty_dents)); remove_dirty_dir_inode(inode); if (inode->i_nlink || is_bad_inode(inode)) goto no_delete; set_inode_flag(F2FS_I(inode), FI_NO_ALLOC); i_size_write(inode, 0); if (F2FS_HAS_BLOCKS(inode)) f2fs_truncate(inode); remove_inode_page(inode); no_delete: clear_inode(inode); }
int f2fs_setxattr(struct inode *inode, int name_index, const char *name, const void *value, size_t value_len, struct page *ipage) { struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); struct f2fs_inode_info *fi = F2FS_I(inode); struct f2fs_xattr_header *header = NULL; struct f2fs_xattr_entry *here, *last; struct page *page; void *base_addr; int error, found, free, newsize; size_t name_len; char *pval; int ilock; if (name == NULL) return -EINVAL; if (value == NULL) value_len = 0; name_len = strlen(name); if (name_len > F2FS_NAME_LEN || value_len > MAX_VALUE_LEN) return -ERANGE; f2fs_balance_fs(sbi); ilock = mutex_lock_op(sbi); if (!fi->i_xattr_nid) { /* Allocate new attribute block */ struct dnode_of_data dn; if (!alloc_nid(sbi, &fi->i_xattr_nid)) { error = -ENOSPC; goto exit; } set_new_dnode(&dn, inode, NULL, NULL, fi->i_xattr_nid); mark_inode_dirty(inode); page = new_node_page(&dn, XATTR_NODE_OFFSET, ipage); if (IS_ERR(page)) { alloc_nid_failed(sbi, fi->i_xattr_nid); fi->i_xattr_nid = 0; error = PTR_ERR(page); goto exit; } alloc_nid_done(sbi, fi->i_xattr_nid); base_addr = page_address(page); header = XATTR_HDR(base_addr); header->h_magic = cpu_to_le32(F2FS_XATTR_MAGIC); header->h_refcount = cpu_to_le32(1); } else { /* The inode already has an extended attribute block. */ page = get_node_page(sbi, fi->i_xattr_nid); if (IS_ERR(page)) { error = PTR_ERR(page); goto exit; } base_addr = page_address(page); header = XATTR_HDR(base_addr); } if (le32_to_cpu(header->h_magic) != F2FS_XATTR_MAGIC) { error = -EIO; goto cleanup; } /* find entry with wanted name. */ found = 0; list_for_each_xattr(here, base_addr) { if (here->e_name_index != name_index) continue; if (here->e_name_len != name_len) continue; if (!memcmp(here->e_name, name, name_len)) { found = 1; break; } } last = here; while (!IS_XATTR_LAST_ENTRY(last)) last = XATTR_NEXT_ENTRY(last); newsize = XATTR_ALIGN(sizeof(struct f2fs_xattr_entry) + name_len + value_len); /* 1. Check space */ if (value) { /* If value is NULL, it is remove operation. * In case of update operation, we caculate free. */ free = MIN_OFFSET - ((char *)last - (char *)header); if (found) free = free - ENTRY_SIZE(here); if (free < newsize) { error = -ENOSPC; goto cleanup; } } /* 2. Remove old entry */ if (found) { /* If entry is found, remove old entry. * If not found, remove operation is not needed. */ struct f2fs_xattr_entry *next = XATTR_NEXT_ENTRY(here); int oldsize = ENTRY_SIZE(here); memmove(here, next, (char *)last - (char *)next); last = (struct f2fs_xattr_entry *)((char *)last - oldsize); memset(last, 0, oldsize); } /* 3. Write new entry */ if (value) { /* Before we come here, old entry is removed. * We just write new entry. */ memset(last, 0, newsize); last->e_name_index = name_index; last->e_name_len = name_len; memcpy(last->e_name, name, name_len); pval = last->e_name + name_len; memcpy(pval, value, value_len); last->e_value_size = cpu_to_le16(value_len); } set_page_dirty(page); f2fs_put_page(page, 1); if (is_inode_flag_set(fi, FI_ACL_MODE)) { inode->i_mode = fi->i_acl_mode; inode->i_ctime = CURRENT_TIME; clear_inode_flag(fi, FI_ACL_MODE); } if (ipage) update_inode(inode, ipage); else update_inode_page(inode); mutex_unlock_op(sbi, ilock); return 0; cleanup: f2fs_put_page(page, 1); exit: mutex_unlock_op(sbi, ilock); return error; }
uint8_t* ramdisk_init(){ int i; uint8_t* ramdisk; int root_bid; struct rd_inode* root_inode; struct rd_super_block* InitSuperBlock; #ifdef UL_DEBUG if(!(ramdisk=(uint8_t*)malloc(RAMDISK_SIZE*sizeof(uint8_t)))){ fprintf(stderr,"No sufficient mem space for ramdisk!\n"); exit(-1); } #endif #ifndef UL_DEBUG if(!(ramdisk=(uint8_t*)vmalloc(RAMDISK_SIZE*sizeof(uint8_t)))){ printk("<1> No sufficient mem space for ramdisk!\n"); return NULL; } #endif //Nullify all the data in ramdisk memset(ramdisk,0,RAMDISK_SIZE); //Init the bitmap for(i=0;i<=(BITMAP_LIMIT+1)/RD_BLOCK_SIZE;i++){ set_bitmap(ramdisk,i); } //Init the root directory root_bid=find_next_free_block(ramdisk);//BlockNO for root dir #ifdef UL_DEBUG if(!(root_inode=(struct rd_inode*)malloc(sizeof(struct rd_inode)))){ fprintf(stderr, "No sufficient mem space for root dir!\n"); exit(-1); } #endif #ifndef UL_DEBUG if(!(root_inode=(struct rd_inode*)vmalloc(sizeof(struct rd_inode)))){ printk("<1> No sufficient mem space for root dir!\n"); return NULL; } #endif root_inode->type=0; root_inode->size=0; root_inode->BlockPointer[0]=root_bid; update_inode(ramdisk,0,root_inode); //Init the superblock #ifdef UL_DEBUG if(!(InitSuperBlock=(struct rd_super_block*)malloc(sizeof(struct rd_super_block)))){ fprintf(stderr,"No sufficient mem\n"); exit(-1); } #endif #ifndef UL_DEBUG if(!(InitSuperBlock=(struct rd_super_block*)vmalloc(sizeof(struct rd_super_block)))){ printk("<1> No sufficient mem\n"); return NULL; } #endif InitSuperBlock->FreeBlockNum=BLOCK_NUM-(BITMAP_LIMIT+1)/RD_BLOCK_SIZE; InitSuperBlock->FreeInodeNum=INODE_NUM-1;//The root dir takes one inode memset(InitSuperBlock->InodeBitmap,0,INODEBITMAP_SIZE); update_superblock(ramdisk,InitSuperBlock); //Init the inode bitmap in superblock set_inode_bitmap(ramdisk,0); #ifndef UL_DEBUG vfree(root_inode); #endif return ramdisk; }
int main(int argc, char *argv[]) { // check for correct arguments if(argc != 3) { fprintf(stderr, "Usage: %s <port> <file-system-image>\n", argv[0]); exit(1); } int portnum = atoi(argv[1]); char *fs_image = argv[2]; int sd = UDP_Open(portnum); assert(sd > -1); int fd = open(fs_image, O_RDWR|O_CREAT, S_IRWXU); if(fd < 0) { fprintf(stderr, "Cannot open file image"); exit(1); } struct stat file_stat; if(fstat(fd, &file_stat) < 0) { fprintf(stderr, "Cannot open file image"); exit(1); } int i, j, rc; MFS_Header_t *header; int image_size; free_bytes = MFS_BYTE_STEP_SIZE; int entry_offset, inode_offset, new_dir_offset, parent_inode_offset; int tmp_offset, tmp_inode_offset, tmp_imap_offset; int done = 0; MFS_Imap_t *imap_temp; MFS_Inode_t *inode_temp; MFS_Inode_t *new_inode; MFS_DirEnt_t *entry_temp; if(file_stat.st_size >= sizeof(MFS_Header_t)) { image_size = file_stat.st_size + MFS_BYTE_STEP_SIZE; printf("Using old file of size %d\n", (int)file_stat.st_size); header = (MFS_Header_t *)malloc(image_size); // Put text in memory rc = read(fd, header, file_stat.st_size); if(rc < 0){ fprintf(stderr, "Cannot open file"); exit(1); } } else { //Initialize image_size = sizeof(MFS_Header_t) + MFS_BYTE_STEP_SIZE; header = (MFS_Header_t *)malloc(image_size); // root initialization inode_temp = allot_space(&header, sizeof(MFS_Inode_t), &tmp_inode_offset); imap_temp = allot_space(&header, sizeof(MFS_Imap_t), &tmp_imap_offset); imap_temp->inodes[0] = tmp_inode_offset; prepare_inode(inode_temp, MFS_DIRECTORY, NULL); for (i = 0; i < 14; i++) { imap_temp->inodes[i] = -1; } // header initialization for (i = 0; i < 4096/14; i++) { header->map[i] = -1; } imap_temp->inodes[0] = tmp_inode_offset; // add two default entries entry_temp = allot_space(&header, MFS_BLOCK_SIZE, &tmp_offset); entry_temp[0].name[0] = '.'; entry_temp[0].name[1] = '\0'; entry_temp[0].inum = 0; entry_temp[1].name[0] = '.'; entry_temp[1].name[1] = '.'; entry_temp[1].name[2] = '\0'; entry_temp[1].inum = 0; for (i = 2; i < MFS_BLOCK_SIZE/sizeof(MFS_DirEnt_t); i++) { entry_temp[i].inum = -1; } inode_temp->data[0] = tmp_offset; //Write to disk header->map[0] = tmp_imap_offset; flush(fd); write_header(fd, header); printf("Initializing new file\n"); } void* header_ptr = (void*)header; void* block_ptr = header_ptr + sizeof(MFS_Header_t); prot_r = (MFS_Prot_t*)malloc(sizeof(MFS_Prot_t)); printf("Started listening at port %d\n", portnum); while (1) { struct sockaddr_in s; rc = UDP_Read(sd, &s, (char*)prot_r, sizeof(MFS_Prot_t)); if (rc > 0) { //Special case for shutdown if(prot_r->cmd == CMD_INIT){ printf("Server initialized\n"); prot_r->ret = 0; } else if(prot_r->cmd == CMD_LOOKUP){ prot_r->ret = -1; MFS_Inode_t* parent_inode = fix_inode(header, prot_r->pinum); prot_r->ret = lookup(block_ptr, parent_inode, &(prot_r->datapacket[0])); } else if(prot_r->cmd == CMD_SHUTDOWN){ //Close file rc = close(fd); if(rc < 0){ fprintf(stderr, "Cannot open file"); exit(1); } prot_r->ret = 0; if(UDP_Write(sd, &s, (char*)prot_r, sizeof(MFS_Prot_t)) < -1){ fprintf(stderr, "Unable to send result"); exit(1); } exit(0); } else if(prot_r->cmd == CMD_UNLINK){ verify(&header, &block_ptr, 16384); prot_r->ret = -1; MFS_Inode_t* parent_inode = fix_inode(header, prot_r->pinum); if(parent_inode != NULL && parent_inode->type == MFS_DIRECTORY){ int exist = lookup(block_ptr, parent_inode, &(prot_r->datapacket[0])); if(exist != -1){ //Check if empty MFS_Inode_t* this_inode = fix_inode(header, exist); if(!(this_inode->type == MFS_DIRECTORY && this_inode->size != 0)){ //Need to remove MFS_DirEnt_t* new_dir_entry = allot_space(&header, MFS_BLOCK_SIZE, &entry_offset); MFS_Inode_t* new_parent_inode = allot_space(&header, sizeof(MFS_Inode_t), &parent_inode_offset); prepare_inode(new_parent_inode, 0, parent_inode); update_inode(&header, prot_r->pinum, parent_inode_offset); i = 0, done = 0; while(i < 14) { if(parent_inode->data[i] != -1){ j = 0; while(j < MFS_BLOCK_SIZE / sizeof(MFS_DirEnt_t)){ //printf("Parent node %d %d\n", inode->data[i], MFS_BLOCK_SIZE / sizeof(MFS_DirEnt_t) ); MFS_DirEnt_t* entry = (MFS_DirEnt_t*)(block_ptr + parent_inode->data[i] + (j * sizeof(MFS_DirEnt_t))); if(entry->inum != -1 && strcmp(entry->name, prot_r->datapacket) == 0 ){ memcpy(new_dir_entry, block_ptr + parent_inode->data[i] , MFS_BLOCK_SIZE); //We now know which entry new_parent_inode->data[i] = entry_offset; new_dir_entry[j].inum = -1; update_inode(&header, exist, -1); prot_r->ret = 0; new_parent_inode->size--; done = 1; break; } j++; } if(done == 1) break; } i++; } } }else{ prot_r->ret = 0; } } } else if(prot_r->cmd == CMD_READ){ prot_r->ret = -1; MFS_Inode_t* parent_inode = fix_inode(header, prot_r->pinum); if(parent_inode != NULL && parent_inode->type == MFS_REGULAR_FILE && prot_r->block >= 0 && prot_r->block < 14){ //New inode memcpy(prot_r->datapacket, block_ptr + parent_inode->data[prot_r->block], MFS_BLOCK_SIZE); prot_r->ret = 0; } } else if(prot_r->cmd == CMD_STAT){ prot_r->ret = -1; MFS_Inode_t* parent_inode = fix_inode(header, prot_r->pinum); if(parent_inode != NULL && prot_r->block >= 0 && prot_r->block < 14){ //New inode prot_r->block = parent_inode->size; prot_r->datapacket[0] = parent_inode->type; prot_r->ret = 0; } } else if(prot_r->cmd == CMD_WRITE){ verify(&header, &block_ptr, 16384); prot_r->ret = -1; MFS_Inode_t* parent_inode = fix_inode(header, prot_r->pinum); int block_offset; if(parent_inode != NULL && parent_inode->type == MFS_REGULAR_FILE && prot_r->block >= 0 && prot_r->block < 14){ //New inode new_inode = (MFS_Inode_t*)allot_space(&header, sizeof(MFS_Inode_t), &inode_offset); prepare_inode(new_inode, 0, parent_inode); void* new_block = allot_space(&header, MFS_BLOCK_SIZE, &block_offset); memcpy(new_block, prot_r->datapacket, MFS_BLOCK_SIZE); i = prot_r->block; while(new_inode->data[i] == -1 && i >= 0){ new_inode->size += MFS_BLOCK_SIZE; new_inode->data[i] = block_offset; i--; } new_inode->data[prot_r->block] = block_offset; update_inode(&header, prot_r->pinum, inode_offset); prot_r->ret = 0; } } else if(prot_r->cmd == CMD_CREAT){ verify(&header, &block_ptr, 16384); prot_r->ret = -1; MFS_Inode_t* parent_inode = fix_inode(header, prot_r->pinum); int exist = lookup(block_ptr, parent_inode, &(prot_r->datapacket[1])); if(exist == -1){ new_inode = allot_space(&header, sizeof(MFS_Inode_t), &inode_offset); prepare_inode(new_inode, prot_r->datapacket[0], NULL); int new_inode_inum = gen_inum(&header, inode_offset); if(parent_inode != NULL && parent_inode->type == MFS_DIRECTORY && strlen(&(prot_r->datapacket[1])) <= 28 && new_inode_inum != -1){ //Check if the dir is full MFS_DirEnt_t* entry; //Initialize new data block for entries MFS_DirEnt_t* new_entry = allot_space(&header, MFS_BLOCK_SIZE, &entry_offset); MFS_Inode_t* new_parent_inode = allot_space(&header, sizeof(MFS_Inode_t), &parent_inode_offset); prepare_inode(new_parent_inode, 0, parent_inode); update_inode(&header, prot_r->pinum, parent_inode_offset); //Copy new stuff done = 0; i = 0; while(i < 14) { if(parent_inode->data[i] != -1){ j = 0; while(j < MFS_BLOCK_SIZE / sizeof(MFS_DirEnt_t)){ entry = (MFS_DirEnt_t*)(block_ptr + parent_inode->data[i] + (j * sizeof(MFS_DirEnt_t))); if(entry->inum == -1){ //Copy the dir entry memcpy(new_entry, block_ptr + parent_inode->data[i], MFS_BLOCK_SIZE); new_parent_inode->data[i] = entry_offset; new_entry[j].inum = new_inode_inum; strcpy(new_entry[j].name, &(prot_r->datapacket[1])); //printf("Name: %s - %s\n",entry->name, &(prot_r->datapacket[1])); done = 1; break; } j++; } if(done == 1) break; }else{ //Create new node //Initialize for (j = 0; j < MFS_BLOCK_SIZE / sizeof(MFS_DirEnt_t); j++) { new_entry[j].inum = -1; } new_parent_inode->data[i] = entry_offset; new_entry[0].inum = new_inode_inum; strcpy(new_entry[0].name, &(prot_r->datapacket[1])); done = 1; break; } i++; } if(done){ //Actually create the inode //Add .. and . dirs if(new_inode->type == MFS_DIRECTORY){ MFS_DirEnt_t* new_dir_entry = allot_space(&header, MFS_BLOCK_SIZE, &new_dir_offset); for (i = 0; i < MFS_BLOCK_SIZE/sizeof(MFS_DirEnt_t); i++) { new_dir_entry[i].inum = -1; } new_dir_entry[0].name[0] = '.'; new_dir_entry[0].name[1] = '\0'; new_dir_entry[0].inum = new_inode_inum; new_dir_entry[1].name[0] = '.'; new_dir_entry[1].name[1] = '.'; new_dir_entry[1].name[2] = '\0'; new_dir_entry[1].inum = prot_r->pinum; new_inode->data[0] = new_dir_offset; } //Write to block new_parent_inode->size++; header->total_inode++; prot_r->ret = 0; }else{ header->total_byte -= unwritten_bytes; unwritten_bytes = 0; } }else{ header->total_byte -= unwritten_bytes; unwritten_bytes = 0; } }else{ prot_r->ret = 0; } } else { fprintf(stderr, "Unknown command"); exit(1); continue; } flush(fd); write_header(fd, header); if(UDP_Write(sd, &s, (char*)prot_r, sizeof(MFS_Prot_t)) < -1){ fprintf(stderr, "Unable to send result"); exit(1); } } } return 0; }