static int f2fs_readdir(struct file *file, struct dir_context *ctx) { struct inode *inode = file_inode(file); unsigned long npages = dir_blocks(inode); unsigned int bit_pos = 0; struct f2fs_dentry_block *dentry_blk = NULL; struct f2fs_dir_entry *de = NULL; struct page *dentry_page = NULL; struct file_ra_state *ra = &file->f_ra; unsigned int n = ((unsigned long)ctx->pos / NR_DENTRY_IN_BLOCK); unsigned char d_type = DT_UNKNOWN; bit_pos = ((unsigned long)ctx->pos % NR_DENTRY_IN_BLOCK); /* readahead for multi pages of dir */ if (npages - n > 1 && !ra_has_index(ra, n)) page_cache_sync_readahead(inode->i_mapping, ra, file, n, min(npages - n, (pgoff_t)MAX_DIR_RA_PAGES)); for (; n < npages; n++) { dentry_page = get_lock_data_page(inode, n); if (IS_ERR(dentry_page)) continue; dentry_blk = kmap(dentry_page); while (bit_pos < NR_DENTRY_IN_BLOCK) { bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap, NR_DENTRY_IN_BLOCK, bit_pos); if (bit_pos >= NR_DENTRY_IN_BLOCK) break; de = &dentry_blk->dentry[bit_pos]; if (de->file_type < F2FS_FT_MAX) d_type = f2fs_filetype_table[de->file_type]; else d_type = DT_UNKNOWN; if (!dir_emit(ctx, dentry_blk->filename[bit_pos], le16_to_cpu(de->name_len), le32_to_cpu(de->ino), d_type)) goto stop; bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len)); ctx->pos = n * NR_DENTRY_IN_BLOCK + bit_pos; } bit_pos = 0; ctx->pos = (n + 1) * NR_DENTRY_IN_BLOCK; kunmap(dentry_page); f2fs_put_page(dentry_page, 1); dentry_page = NULL; } stop: if (dentry_page && !IS_ERR(dentry_page)) { kunmap(dentry_page); f2fs_put_page(dentry_page, 1); } return 0; }
static int truncate_partial_data_page(struct inode *inode, u64 from, bool cache_only) { unsigned offset = from & (PAGE_CACHE_SIZE - 1); pgoff_t index = from >> PAGE_CACHE_SHIFT; struct address_space *mapping = inode->i_mapping; struct page *page; if (!offset && !cache_only) return 0; if (cache_only) { page = grab_cache_page(mapping, index); if (page && PageUptodate(page)) goto truncate_out; f2fs_put_page(page, 1); return 0; } page = get_lock_data_page(inode, index); if (IS_ERR(page)) return 0; truncate_out: f2fs_wait_on_page_writeback(page, DATA); zero_user(page, offset, PAGE_CACHE_SIZE - offset); if (!cache_only || !f2fs_encrypted_inode(inode) || !S_ISREG(inode->i_mode)) set_page_dirty(page); f2fs_put_page(page, 1); return 0; }
bool f2fs_empty_dir(struct inode *dir) { unsigned long bidx; struct page *dentry_page; unsigned int bit_pos; struct f2fs_dentry_block *dentry_blk; unsigned long nblock = dir_blocks(dir); for (bidx = 0; bidx < nblock; bidx++) { dentry_page = get_lock_data_page(dir, bidx); if (IS_ERR(dentry_page)) { if (PTR_ERR(dentry_page) == -ENOENT) continue; else return false; } dentry_blk = kmap_atomic(dentry_page); if (bidx == 0) bit_pos = 2; else bit_pos = 0; bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap, NR_DENTRY_IN_BLOCK, bit_pos); kunmap_atomic(dentry_blk); f2fs_put_page(dentry_page, 1); if (bit_pos < NR_DENTRY_IN_BLOCK) return false; } return true; }
static int f2fs_readdir(struct file *file, void *dirent, filldir_t filldir) { unsigned long pos = file->f_pos; unsigned int bit_pos = 0; struct inode *inode = file_inode(file); unsigned long npages = dir_blocks(inode); struct f2fs_dentry_block *dentry_blk = NULL; struct page *dentry_page = NULL; struct file_ra_state *ra = &file->f_ra; struct f2fs_dentry_ptr d; unsigned int n = 0; if (f2fs_has_inline_dentry(inode)) return f2fs_read_inline_dir(file, dirent, filldir); bit_pos = (pos % NR_DENTRY_IN_BLOCK); n = (pos / NR_DENTRY_IN_BLOCK); /* readahead for multi pages of dir */ if (npages - n > 1 && !ra_has_index(ra, n)) page_cache_sync_readahead(inode->i_mapping, ra, file, n, min(npages - n, (pgoff_t)MAX_DIR_RA_PAGES)); for (; n < npages; n++) { dentry_page = get_lock_data_page(inode, n); if (IS_ERR(dentry_page)) continue; dentry_blk = kmap(dentry_page); make_dentry_ptr(&d, (void *)dentry_blk, 1); if (f2fs_fill_dentries(file, dirent, filldir, &d, n, bit_pos)) goto stop; bit_pos = 0; file->f_pos = (n + 1) * NR_DENTRY_IN_BLOCK; kunmap(dentry_page); f2fs_put_page(dentry_page, 1); dentry_page = NULL; } stop: if (dentry_page && !IS_ERR(dentry_page)) { kunmap(dentry_page); f2fs_put_page(dentry_page, 1); } return 0; }
struct f2fs_dir_entry *f2fs_parent_dir(struct inode *dir, struct page **p) { struct page *page; struct f2fs_dir_entry *de; struct f2fs_dentry_block *dentry_blk; page = get_lock_data_page(dir, 0); if (IS_ERR(page)) return NULL; dentry_blk = kmap(page); de = &dentry_blk->dentry[1]; *p = page; unlock_page(page); return de; }
static int f2fs_readdir(struct file *file, void *dirent, filldir_t filldir) { unsigned long pos = file->f_pos; unsigned char *types = NULL; unsigned int bit_pos = 0, start_bit_pos = 0; int over = 0; struct inode *inode = file_inode(file); unsigned long npages = dir_blocks(inode); struct f2fs_dentry_block *dentry_blk = NULL; struct f2fs_dir_entry *de = NULL; struct page *dentry_page = NULL; unsigned int n = 0; unsigned char d_type = DT_UNKNOWN; int slots; types = f2fs_filetype_table; bit_pos = (pos % NR_DENTRY_IN_BLOCK); n = (pos / NR_DENTRY_IN_BLOCK); for ( ; n < npages; n++) { dentry_page = get_lock_data_page(inode, n); if (IS_ERR(dentry_page)) continue; start_bit_pos = bit_pos; dentry_blk = kmap(dentry_page); while (bit_pos < NR_DENTRY_IN_BLOCK) { d_type = DT_UNKNOWN; bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap, NR_DENTRY_IN_BLOCK, bit_pos); if (bit_pos >= NR_DENTRY_IN_BLOCK) break; de = &dentry_blk->dentry[bit_pos]; if (types && de->file_type < F2FS_FT_MAX) d_type = types[de->file_type]; over = filldir(dirent, dentry_blk->filename[bit_pos], le16_to_cpu(de->name_len), (n * NR_DENTRY_IN_BLOCK) + bit_pos, le32_to_cpu(de->ino), d_type); if (over) { file->f_pos += bit_pos - start_bit_pos; goto stop; } slots = GET_DENTRY_SLOTS(le16_to_cpu(de->name_len)); bit_pos += slots; } bit_pos = 0; file->f_pos = (n + 1) * NR_DENTRY_IN_BLOCK; kunmap(dentry_page); f2fs_put_page(dentry_page, 1); dentry_page = NULL; } stop: if (dentry_page && !IS_ERR(dentry_page)) { kunmap(dentry_page); f2fs_put_page(dentry_page, 1); } return 0; }
static int __exchange_data_block(struct inode *inode, pgoff_t src, pgoff_t dst, bool full) { struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct dnode_of_data dn; block_t new_addr; bool do_replace = false; int ret; set_new_dnode(&dn, inode, NULL, NULL, 0); ret = get_dnode_of_data(&dn, src, LOOKUP_NODE_RA); if (ret && ret != -ENOENT) { return ret; } else if (ret == -ENOENT) { new_addr = NULL_ADDR; } else { new_addr = dn.data_blkaddr; if (!is_checkpointed_data(sbi, new_addr)) { dn.data_blkaddr = NULL_ADDR; /* do not invalidate this block address */ set_data_blkaddr(&dn); f2fs_update_extent_cache(&dn); do_replace = true; } f2fs_put_dnode(&dn); } if (new_addr == NULL_ADDR) return full ? truncate_hole(inode, dst, dst + 1) : 0; if (do_replace) { struct page *ipage = get_node_page(sbi, inode->i_ino); struct node_info ni; if (IS_ERR(ipage)) { ret = PTR_ERR(ipage); goto err_out; } set_new_dnode(&dn, inode, ipage, NULL, 0); ret = f2fs_reserve_block(&dn, dst); if (ret) goto err_out; truncate_data_blocks_range(&dn, 1); get_node_info(sbi, dn.nid, &ni); f2fs_replace_block(sbi, &dn, dn.data_blkaddr, new_addr, ni.version, true); f2fs_put_dnode(&dn); } else { struct page *psrc, *pdst; psrc = get_lock_data_page(inode, src, true); if (IS_ERR(psrc)) return PTR_ERR(psrc); pdst = get_new_data_page(inode, NULL, dst, false); if (IS_ERR(pdst)) { f2fs_put_page(psrc, 1); return PTR_ERR(pdst); } f2fs_copy_page(psrc, pdst); set_page_dirty(pdst); f2fs_put_page(pdst, 1); f2fs_put_page(psrc, 1); return truncate_hole(inode, src, src + 1); } return 0; err_out: if (!get_dnode_of_data(&dn, src, LOOKUP_NODE)) { dn.data_blkaddr = new_addr; set_data_blkaddr(&dn); f2fs_update_extent_cache(&dn); f2fs_put_dnode(&dn); } return ret; }
static int f2fs_defragment_range(struct f2fs_sb_info *sbi, struct file *filp, struct f2fs_defragment *range) { struct inode *inode = file_inode(filp); struct f2fs_map_blocks map = { .m_next_pgofs = NULL }; struct extent_info ei; pgoff_t pg_start, pg_end; unsigned int blk_per_seg = sbi->blocks_per_seg; unsigned int total = 0, sec_num; unsigned int pages_per_sec = sbi->segs_per_sec * blk_per_seg; block_t blk_end = 0; bool fragmented = false; int err; /* if in-place-update policy is enabled, don't waste time here */ if (need_inplace_update(inode)) return -EINVAL; pg_start = range->start >> PAGE_CACHE_SHIFT; pg_end = (range->start + range->len) >> PAGE_CACHE_SHIFT; f2fs_balance_fs(sbi, true); inode_lock(inode); /* writeback all dirty pages in the range */ err = filemap_write_and_wait_range(inode->i_mapping, range->start, range->start + range->len - 1); if (err) goto out; /* * lookup mapping info in extent cache, skip defragmenting if physical * block addresses are continuous. */ if (f2fs_lookup_extent_cache(inode, pg_start, &ei)) { if (ei.fofs + ei.len >= pg_end) goto out; } map.m_lblk = pg_start; /* * lookup mapping info in dnode page cache, skip defragmenting if all * physical block addresses are continuous even if there are hole(s) * in logical blocks. */ while (map.m_lblk < pg_end) { map.m_len = pg_end - map.m_lblk; err = f2fs_map_blocks(inode, &map, 0, F2FS_GET_BLOCK_READ); if (err) goto out; if (!(map.m_flags & F2FS_MAP_FLAGS)) { map.m_lblk++; continue; } if (blk_end && blk_end != map.m_pblk) { fragmented = true; break; } blk_end = map.m_pblk + map.m_len; map.m_lblk += map.m_len; } if (!fragmented) goto out; map.m_lblk = pg_start; map.m_len = pg_end - pg_start; sec_num = (map.m_len + pages_per_sec - 1) / pages_per_sec; /* * make sure there are enough free section for LFS allocation, this can * avoid defragment running in SSR mode when free section are allocated * intensively */ if (has_not_enough_free_secs(sbi, sec_num)) { err = -EAGAIN; goto out; } while (map.m_lblk < pg_end) { pgoff_t idx; int cnt = 0; do_map: map.m_len = pg_end - map.m_lblk; err = f2fs_map_blocks(inode, &map, 0, F2FS_GET_BLOCK_READ); if (err) goto clear_out; if (!(map.m_flags & F2FS_MAP_FLAGS)) { map.m_lblk++; continue; } set_inode_flag(F2FS_I(inode), FI_DO_DEFRAG); idx = map.m_lblk; while (idx < map.m_lblk + map.m_len && cnt < blk_per_seg) { struct page *page; page = get_lock_data_page(inode, idx, true); if (IS_ERR(page)) { err = PTR_ERR(page); goto clear_out; } set_page_dirty(page); f2fs_put_page(page, 1); idx++; cnt++; total++; } map.m_lblk = idx; if (idx < pg_end && cnt < blk_per_seg) goto do_map; clear_inode_flag(F2FS_I(inode), FI_DO_DEFRAG); err = filemap_fdatawrite(inode->i_mapping); if (err) goto out; } clear_out: clear_inode_flag(F2FS_I(inode), FI_DO_DEFRAG); out: inode_unlock(inode); if (!err) range->len = (u64)total << PAGE_CACHE_SHIFT; return err; }