Exemplo n.º 1
0
static int make_empty_dir(struct inode *inode,
		struct inode *parent, struct page *page)
{
	struct page *dentry_page;
	struct f2fs_dentry_block *dentry_blk;
	struct f2fs_dentry_ptr d;

	if (f2fs_has_inline_dentry(inode))
		return make_empty_inline_dir(inode, parent, page);

	dentry_page = get_new_data_page(inode, page, 0, true);
	if (IS_ERR(dentry_page))
		return PTR_ERR(dentry_page);

	dentry_blk = kmap_atomic(dentry_page);

	make_dentry_ptr(&d, (void *)dentry_blk, 1);
	do_make_empty_dir(inode, parent, &d);

	kunmap_atomic(dentry_blk);

	set_page_dirty(dentry_page);
	f2fs_put_page(dentry_page, 1);
	return 0;
}
Exemplo n.º 2
0
/*
 * Find an entry in the specified directory with the wanted name.
 * It returns the page where the entry was found (as a parameter - res_page),
 * and the entry itself. Page is returned mapped and unlocked.
 * Entry is guaranteed to be valid.
 */
struct f2fs_dir_entry *f2fs_find_entry(struct inode *dir, struct qstr *child,
		struct page **res_page, unsigned int flags)
{
	unsigned long npages = dir_blocks(dir);
	struct f2fs_dir_entry *de = NULL;
	f2fs_hash_t name_hash;
	unsigned int max_depth;
	unsigned int level;

	if (f2fs_has_inline_dentry(dir))
		return find_in_inline_dir(dir, child, res_page, flags);

	if (npages == 0)
		return NULL;

	*res_page = NULL;

	name_hash = f2fs_dentry_hash(child);
	max_depth = F2FS_I(dir)->i_current_depth;

	for (level = 0; level < max_depth; level++) {
		de = find_in_level(dir, level, child, name_hash,
						res_page, flags);
		if (de)
			break;
	}
	if (!de && F2FS_I(dir)->chash != name_hash) {
		F2FS_I(dir)->chash = name_hash;
		F2FS_I(dir)->clevel = level - 1;
	}
	return de;
}
Exemplo n.º 3
0
void f2fs_set_link(struct inode *dir, struct f2fs_dir_entry *de,
                   struct page *page, struct inode *inode)
{
    enum page_type type = f2fs_has_inline_dentry(dir) ? NODE : DATA;
    lock_page(page);
    f2fs_wait_on_page_writeback(page, type);
    de->ino = cpu_to_le32(inode->i_ino);
    set_de_type(de, inode);
    if (!f2fs_has_inline_dentry(dir))
        kunmap(page);
    set_page_dirty(page);
    dir->i_mtime = dir->i_ctime = CURRENT_TIME;
    mark_inode_dirty(dir);

    f2fs_put_page(page, 1);
}
Exemplo n.º 4
0
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;
}
Exemplo n.º 5
0
ino_t f2fs_inode_by_name(struct inode *dir, struct qstr *qstr)
{
	ino_t res = 0;
	struct f2fs_dir_entry *de;
	struct page *page;

	de = f2fs_find_entry(dir, qstr, &page, 0);
	if (de) {
		res = le32_to_cpu(de->ino);
		if (!f2fs_has_inline_dentry(dir))
			kunmap(page);
		f2fs_put_page(page, 0);
	}

	return res;
}
Exemplo n.º 6
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;

	if (f2fs_has_inline_dentry(dir))
		return f2fs_parent_inline_dir(dir, p);

	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;
}
/*
 * It only removes the dentry from the dentry page, corresponding name
 * entry in name page does not need to be touched during deletion.
 */
void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,
                       struct inode *dir, struct inode *inode)
{
    struct	f2fs_dentry_block *dentry_blk;
    unsigned int bit_pos;
    int slots = GET_DENTRY_SLOTS(le16_to_cpu(dentry->name_len));
    int i;

    if (f2fs_has_inline_dentry(dir))
        return f2fs_delete_inline_entry(dentry, page, dir, inode);

    lock_page(page);
    f2fs_wait_on_page_writeback(page, DATA);

    dentry_blk = page_address(page);
    bit_pos = dentry - dentry_blk->dentry;
    for (i = 0; i < slots; i++)
        test_and_clear_bit_le(bit_pos + i, &dentry_blk->dentry_bitmap);

    /* Let's check and deallocate this dentry page */
    bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap,
                               NR_DENTRY_IN_BLOCK,
                               0);
    kunmap(page); /* kunmap - pair of f2fs_find_entry */
    set_page_dirty(page);

    dir->i_ctime = dir->i_mtime = CURRENT_TIME;

    if (inode)
        f2fs_drop_nlink(dir, inode, NULL);

    if (bit_pos == NR_DENTRY_IN_BLOCK) {
        truncate_hole(dir, page->index, page->index + 1);
        clear_page_dirty_for_io(page);
        ClearPagePrivate(page);
        ClearPageUptodate(page);
        inode_dec_dirty_pages(dir);
    }
    f2fs_put_page(page, 1);
}
Exemplo n.º 8
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);

	if (f2fs_has_inline_dentry(dir))
		return f2fs_empty_inline_dir(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;
}
Exemplo n.º 9
0
/*
 * 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;

	if (f2fs_has_inline_dentry(dir)) {
		err = f2fs_add_inline_entry(dir, name, inode);
		if (!err || err != -EAGAIN)
			return err;
		else
			err = 0;
	}

	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->dentry_bitmap,
						slots, NR_DENTRY_IN_BLOCK);
		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, NULL);
	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;
}
Exemplo n.º 10
0
int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
{
	struct inode *inode = file->f_mapping->host;
	struct f2fs_inode_info *fi = F2FS_I(inode);
	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
	nid_t ino = inode->i_ino;
	int ret = 0;
	bool need_cp = false;
	struct writeback_control wbc = {
		.sync_mode = WB_SYNC_ALL,
		.nr_to_write = LONG_MAX,
		.for_reclaim = 0,
	};

	if (unlikely(f2fs_readonly(inode->i_sb)))
		return 0;

	trace_f2fs_sync_file_enter(inode);

	/* if fdatasync is triggered, let's do in-place-update */
	if (get_dirty_pages(inode) <= SM_I(sbi)->min_fsync_blocks)
		set_inode_flag(fi, FI_NEED_IPU);
	ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
	clear_inode_flag(fi, FI_NEED_IPU);

	if (ret) {
		trace_f2fs_sync_file_exit(inode, need_cp, datasync, ret);
		return ret;
	}

	/* if the inode is dirty, let's recover all the time */
	if (!datasync && is_inode_flag_set(fi, FI_DIRTY_INODE)) {
		update_inode_page(inode);
		goto go_write;
	}

	/*
	 * if there is no written data, don't waste time to write recovery info.
	 */
	if (!is_inode_flag_set(fi, FI_APPEND_WRITE) &&
			!exist_written_data(sbi, ino, APPEND_INO)) {

		/* it may call write_inode just prior to fsync */
		if (need_inode_page_update(sbi, ino))
			goto go_write;

		if (is_inode_flag_set(fi, FI_UPDATE_WRITE) ||
				exist_written_data(sbi, ino, UPDATE_INO))
			goto flush_out;
		goto out;
	}
go_write:
	/* guarantee free sections for fsync */
	f2fs_balance_fs(sbi);

	/*
	 * Both of fdatasync() and fsync() are able to be recovered from
	 * sudden-power-off.
	 */
	down_read(&fi->i_sem);
	need_cp = need_do_checkpoint(inode);
	up_read(&fi->i_sem);

	if (need_cp) {
		/* all the dirty node pages should be flushed for POR */
		ret = f2fs_sync_fs(inode->i_sb, 1);

		/*
		 * We've secured consistency through sync_fs. Following pino
		 * will be used only for fsynced inodes after checkpoint.
		 */
		try_to_fix_pino(inode);
		clear_inode_flag(fi, FI_APPEND_WRITE);
		clear_inode_flag(fi, FI_UPDATE_WRITE);
		goto out;
	}
sync_nodes:
	sync_node_pages(sbi, ino, &wbc);

	/* if cp_error was enabled, we should avoid infinite loop */
	if (unlikely(f2fs_cp_error(sbi)))
		goto out;

	if (need_inode_block_update(sbi, ino)) {
		mark_inode_dirty_sync(inode);
		f2fs_write_inode(inode, NULL);
		goto sync_nodes;
	}

	ret = wait_on_node_pages_writeback(sbi, ino);
	if (ret)
		goto out;

	/* once recovery info is written, don't need to tack this */
	remove_dirty_inode(sbi, ino, APPEND_INO);
	clear_inode_flag(fi, FI_APPEND_WRITE);
flush_out:
	remove_dirty_inode(sbi, ino, UPDATE_INO);
	clear_inode_flag(fi, FI_UPDATE_WRITE);
	ret = f2fs_issue_flush(sbi);
out:
	trace_f2fs_sync_file_exit(inode, need_cp, datasync, ret);
	f2fs_trace_ios(NULL, 1);
	return ret;
}

static pgoff_t __get_first_dirty_index(struct address_space *mapping,
						pgoff_t pgofs, int whence)
{
	struct pagevec pvec;
	int nr_pages;

	if (whence != SEEK_DATA)
		return 0;

	/* find first dirty page index */
	pagevec_init(&pvec, 0);
	nr_pages = pagevec_lookup_tag(&pvec, mapping, &pgofs,
					PAGECACHE_TAG_DIRTY, 1);
	pgofs = nr_pages ? pvec.pages[0]->index : LONG_MAX;
	pagevec_release(&pvec);
	return pgofs;
}

static bool __found_offset(block_t blkaddr, pgoff_t dirty, pgoff_t pgofs,
							int whence)
{
	switch (whence) {
	case SEEK_DATA:
		if ((blkaddr == NEW_ADDR && dirty == pgofs) ||
			(blkaddr != NEW_ADDR && blkaddr != NULL_ADDR))
			return true;
		break;
	case SEEK_HOLE:
		if (blkaddr == NULL_ADDR)
			return true;
		break;
	}
	return false;
}

static inline int unsigned_offsets(struct file *file)
{
	return file->f_mode & FMODE_UNSIGNED_OFFSET;
}

static loff_t vfs_setpos(struct file *file, loff_t offset, loff_t maxsize)
{
	if (offset < 0 && !unsigned_offsets(file))
		return -EINVAL;
	if (offset > maxsize)
		return -EINVAL;

	if (offset != file->f_pos) {
		file->f_pos = offset;
		file->f_version = 0;
	}
	return offset;
}

static loff_t f2fs_seek_block(struct file *file, loff_t offset, int whence)
{
	struct inode *inode = file->f_mapping->host;
	loff_t maxbytes = inode->i_sb->s_maxbytes;
	struct dnode_of_data dn;
	pgoff_t pgofs, end_offset, dirty;
	loff_t data_ofs = offset;
	loff_t isize;
	int err = 0;

	mutex_lock(&inode->i_mutex);

	isize = i_size_read(inode);
	if (offset >= isize)
		goto fail;

	/* handle inline data case */
	if (f2fs_has_inline_data(inode) || f2fs_has_inline_dentry(inode)) {
		if (whence == SEEK_HOLE)
			data_ofs = isize;
		goto found;
	}

	pgofs = (pgoff_t)(offset >> PAGE_CACHE_SHIFT);

	dirty = __get_first_dirty_index(inode->i_mapping, pgofs, whence);

	for (; data_ofs < isize; data_ofs = pgofs << PAGE_CACHE_SHIFT) {
		set_new_dnode(&dn, inode, NULL, NULL, 0);
		err = get_dnode_of_data(&dn, pgofs, LOOKUP_NODE_RA);
		if (err && err != -ENOENT) {
			goto fail;
		} else if (err == -ENOENT) {
			/* direct node does not exists */
			if (whence == SEEK_DATA) {
				pgofs = PGOFS_OF_NEXT_DNODE(pgofs,
							F2FS_I(inode));
				continue;
			} else {
				goto found;
			}
		}

		end_offset = ADDRS_PER_PAGE(dn.node_page, F2FS_I(inode));

		/* find data/hole in dnode block */
		for (; dn.ofs_in_node < end_offset;
				dn.ofs_in_node++, pgofs++,
				data_ofs = (loff_t)pgofs << PAGE_CACHE_SHIFT) {
			block_t blkaddr;
			blkaddr = datablock_addr(dn.node_page, dn.ofs_in_node);

			if (__found_offset(blkaddr, dirty, pgofs, whence)) {
				f2fs_put_dnode(&dn);
				goto found;
			}
		}
		f2fs_put_dnode(&dn);
	}

	if (whence == SEEK_DATA)
		goto fail;
found:
	if (whence == SEEK_HOLE && data_ofs > isize)
		data_ofs = isize;
	mutex_unlock(&inode->i_mutex);
	return vfs_setpos(file, data_ofs, maxbytes);
fail:
	mutex_unlock(&inode->i_mutex);
	return -ENXIO;
}

static loff_t f2fs_llseek(struct file *file, loff_t offset, int whence)
{
	struct inode *inode = file->f_mapping->host;
	loff_t maxbytes = inode->i_sb->s_maxbytes;

	switch (whence) {
	case SEEK_SET:
	case SEEK_CUR:
	case SEEK_END:
		return generic_file_llseek_size(file, offset, whence,
						maxbytes);
	case SEEK_DATA:
	case SEEK_HOLE:
		if (offset < 0)
			return -ENXIO;
		return f2fs_seek_block(file, offset, whence);
	}

	return -EINVAL;
}

static int f2fs_file_mmap(struct file *file, struct vm_area_struct *vma)
{
	struct inode *inode = file_inode(file);

	if (f2fs_encrypted_inode(inode)) {
		int err = f2fs_get_encryption_info(inode);
		if (err)
			return 0;
	}

	/* we don't need to use inline_data strictly */
	if (f2fs_has_inline_data(inode)) {
		int err = f2fs_convert_inline_inode(inode);
		if (err)
			return err;
	}

	file_accessed(file);
	vma->vm_ops = &f2fs_file_vm_ops;
	return 0;
}

static int f2fs_file_open(struct inode *inode, struct file *filp)
{
	int ret = generic_file_open(inode, filp);

	if (!ret && f2fs_encrypted_inode(inode)) {
		ret = f2fs_get_encryption_info(inode);
		if (ret)
			ret = -EACCES;
	}
	return ret;
}
Exemplo n.º 11
0
struct dentry *f2fs_get_parent(struct dentry *child)
{
    struct qstr dotdot = {.len = 2, .name = ".."};
    unsigned long ino = f2fs_inode_by_name(child->d_inode, &dotdot);
    if (!ino)
        return ERR_PTR(-ENOENT);
    return d_obtain_alias(f2fs_iget(child->d_inode->i_sb, ino));
}

static int __recover_dot_dentries(struct inode *dir, nid_t pino)
{
    struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
    struct qstr dot = {.len = 1, .name = "."};
    struct qstr dotdot = {.len = 2, .name = ".."};
    struct f2fs_dir_entry *de;
    struct page *page;
    int err = 0;

    if (f2fs_readonly(sbi->sb)) {
        f2fs_msg(sbi->sb, KERN_INFO,
                 "skip recovering inline_dots inode (ino:%lu, pino:%u) "
                 "in readonly mountpoint", dir->i_ino, pino);
        return 0;
    }

    f2fs_balance_fs(sbi, true);

    f2fs_lock_op(sbi);

    de = f2fs_find_entry(dir, &dot, &page);
    if (de) {
        f2fs_dentry_kunmap(dir, page);
        f2fs_put_page(page, 0);
    } else {
        err = __f2fs_add_link(dir, &dot, NULL, dir->i_ino, S_IFDIR);
        if (err)
            goto out;
    }

    de = f2fs_find_entry(dir, &dotdot, &page);
    if (de) {
        f2fs_dentry_kunmap(dir, page);
        f2fs_put_page(page, 0);
    } else {
        err = __f2fs_add_link(dir, &dotdot, NULL, pino, S_IFDIR);
    }
out:
    if (!err) {
        clear_inode_flag(F2FS_I(dir), FI_INLINE_DOTS);
        mark_inode_dirty(dir);
    }

    f2fs_unlock_op(sbi);
    return err;
}

static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry,
                                  struct nameidata *nd)
{
    struct inode *inode = NULL;
    struct f2fs_dir_entry *de;
    struct page *page;
    nid_t ino;
    int err = 0;

    if (dentry->d_name.len > F2FS_NAME_LEN)
        return ERR_PTR(-ENAMETOOLONG);

    de = f2fs_find_entry(dir, &dentry->d_name, &page);
    if (!de)
        return d_splice_alias(inode, dentry);

    ino = le32_to_cpu(de->ino);
    f2fs_dentry_kunmap(dir, page);
    f2fs_put_page(page, 0);

    inode = f2fs_iget(dir->i_sb, ino);
    if (IS_ERR(inode))
        return ERR_CAST(inode);

    if (f2fs_has_inline_dots(inode)) {
        err = __recover_dot_dentries(inode, dir->i_ino);
        if (err)
            goto err_out;
    }
    return d_splice_alias(inode, dentry);

err_out:
    iget_failed(inode);
    return ERR_PTR(err);
}

static int f2fs_unlink(struct inode *dir, struct dentry *dentry)
{
    struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
    struct inode *inode = dentry->d_inode;
    struct f2fs_dir_entry *de;
    struct page *page;
    int err = -ENOENT;

    trace_f2fs_unlink_enter(dir, dentry);

    de = f2fs_find_entry(dir, &dentry->d_name, &page);
    if (!de)
        goto fail;

    f2fs_balance_fs(sbi, true);

    f2fs_lock_op(sbi);
    err = acquire_orphan_inode(sbi);
    if (err) {
        f2fs_unlock_op(sbi);
        f2fs_dentry_kunmap(dir, page);
        f2fs_put_page(page, 0);
        goto fail;
    }
    f2fs_delete_entry(de, page, dir, inode);
    f2fs_unlock_op(sbi);

    /* In order to evict this inode, we set it dirty */
    mark_inode_dirty(inode);

    if (IS_DIRSYNC(dir))
        f2fs_sync_fs(sbi->sb, 1);
fail:
    trace_f2fs_unlink_exit(inode, err);
    return err;
}

static void *f2fs_follow_link(struct dentry *dentry, struct nameidata *nd)
{
    struct page *page;
    char *link;

    page = page_follow_link_light(dentry, nd);
    if (IS_ERR(page))
        return page;

    link = nd_get_link(nd);
    if (IS_ERR(link))
        return link;

    /* this is broken symlink case */
    if (*link == 0) {
        kunmap(page);
        page_cache_release(page);
        return ERR_PTR(-ENOENT);
    }
    return page;
}

static int f2fs_symlink(struct inode *dir, struct dentry *dentry,
                        const char *symname)
{
    struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
    struct inode *inode;
    size_t len = strlen(symname);
    struct f2fs_str disk_link = FSTR_INIT((char *)symname, len + 1);
    struct f2fs_encrypted_symlink_data *sd = NULL;
    int err;

    if (f2fs_encrypted_inode(dir)) {
        err = f2fs_get_encryption_info(dir);
        if (err)
            return err;

        if (!f2fs_encrypted_inode(dir))
            return -EPERM;

        disk_link.len = (f2fs_fname_encrypted_size(dir, len) +
                         sizeof(struct f2fs_encrypted_symlink_data));
    }

    if (disk_link.len > dir->i_sb->s_blocksize)
        return -ENAMETOOLONG;

    inode = f2fs_new_inode(dir, S_IFLNK | S_IRWXUGO);
    if (IS_ERR(inode))
        return PTR_ERR(inode);

    if (f2fs_encrypted_inode(inode))
        inode->i_op = &f2fs_encrypted_symlink_inode_operations;
    else
        inode->i_op = &f2fs_symlink_inode_operations;
    inode->i_mapping->a_ops = &f2fs_dblock_aops;

    f2fs_balance_fs(sbi, true);

    f2fs_lock_op(sbi);
    err = f2fs_add_link(dentry, inode);
    if (err)
        goto out;
    f2fs_unlock_op(sbi);
    alloc_nid_done(sbi, inode->i_ino);

    if (f2fs_encrypted_inode(inode)) {
        struct qstr istr = QSTR_INIT(symname, len);
        struct f2fs_str ostr;

        sd = kzalloc(disk_link.len, GFP_NOFS);
        if (!sd) {
            err = -ENOMEM;
            goto err_out;
        }

        err = f2fs_get_encryption_info(inode);
        if (err)
            goto err_out;

        if (!f2fs_encrypted_inode(inode)) {
            err = -EPERM;
            goto err_out;
        }

        ostr.name = sd->encrypted_path;
        ostr.len = disk_link.len;
        err = f2fs_fname_usr_to_disk(inode, &istr, &ostr);
        if (err < 0)
            goto err_out;

        sd->len = cpu_to_le16(ostr.len);
        disk_link.name = (char *)sd;
    }

    err = page_symlink(inode, disk_link.name, disk_link.len);

err_out:
    d_instantiate(dentry, inode);
    unlock_new_inode(inode);

    /*
     * Let's flush symlink data in order to avoid broken symlink as much as
     * possible. Nevertheless, fsyncing is the best way, but there is no
     * way to get a file descriptor in order to flush that.
     *
     * Note that, it needs to do dir->fsync to make this recoverable.
     * If the symlink path is stored into inline_data, there is no
     * performance regression.
     */
    if (!err) {
        filemap_write_and_wait_range(inode->i_mapping, 0,
                                     disk_link.len - 1);

        if (IS_DIRSYNC(dir))
            f2fs_sync_fs(sbi->sb, 1);
    } else {
        f2fs_unlink(dir, dentry);
    }

    kfree(sd);
    return err;
out:
    handle_failed_inode(inode);
    return err;
}

static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
{
    struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
    struct inode *inode;
    int err;

    inode = f2fs_new_inode(dir, S_IFDIR | mode);
    if (IS_ERR(inode))
        return PTR_ERR(inode);

    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_F2FS_HIGH_ZERO);

    f2fs_balance_fs(sbi, true);

    set_inode_flag(F2FS_I(inode), FI_INC_LINK);
    f2fs_lock_op(sbi);
    err = f2fs_add_link(dentry, inode);
    if (err)
        goto out_fail;
    f2fs_unlock_op(sbi);

    alloc_nid_done(sbi, inode->i_ino);

    d_instantiate(dentry, inode);
    unlock_new_inode(inode);

    if (IS_DIRSYNC(dir))
        f2fs_sync_fs(sbi->sb, 1);
    return 0;

out_fail:
    clear_inode_flag(F2FS_I(inode), FI_INC_LINK);
    handle_failed_inode(inode);
    return err;
}

static int f2fs_rmdir(struct inode *dir, struct dentry *dentry)
{
    struct inode *inode = dentry->d_inode;
    if (f2fs_empty_dir(inode))
        return f2fs_unlink(dir, dentry);
    return -ENOTEMPTY;
}

static int f2fs_mknod(struct inode *dir, struct dentry *dentry,
                      umode_t mode, dev_t rdev)
{
    struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
    struct inode *inode;
    int err = 0;

    if (!new_valid_dev(rdev))
        return -EINVAL;

    inode = f2fs_new_inode(dir, mode);
    if (IS_ERR(inode))
        return PTR_ERR(inode);

    init_special_inode(inode, inode->i_mode, rdev);
    inode->i_op = &f2fs_special_inode_operations;

    f2fs_balance_fs(sbi, true);

    f2fs_lock_op(sbi);
    err = f2fs_add_link(dentry, inode);
    if (err)
        goto out;
    f2fs_unlock_op(sbi);

    alloc_nid_done(sbi, inode->i_ino);

    d_instantiate(dentry, inode);
    unlock_new_inode(inode);

    if (IS_DIRSYNC(dir))
        f2fs_sync_fs(sbi->sb, 1);
    return 0;
out:
    handle_failed_inode(inode);
    return err;
}

static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
                       struct inode *new_dir, struct dentry *new_dentry)
{
    struct f2fs_sb_info *sbi = F2FS_I_SB(old_dir);
    struct inode *old_inode = old_dentry->d_inode;
    struct inode *new_inode = new_dentry->d_inode;
    struct page *old_dir_page;
    struct page *old_page, *new_page;
    struct f2fs_dir_entry *old_dir_entry = NULL;
    struct f2fs_dir_entry *old_entry;
    struct f2fs_dir_entry *new_entry;
    bool is_old_inline = f2fs_has_inline_dentry(old_dir);
    int err = -ENOENT;

    if ((old_dir != new_dir) && f2fs_encrypted_inode(new_dir) &&
            !f2fs_is_child_context_consistent_with_parent(new_dir,
                    old_inode)) {
        err = -EPERM;
        goto out;
    }

    old_entry = f2fs_find_entry(old_dir, &old_dentry->d_name, &old_page);
    if (!old_entry)
        goto out;

    if (S_ISDIR(old_inode->i_mode)) {
        err = -EIO;
        old_dir_entry = f2fs_parent_dir(old_inode, &old_dir_page);
        if (!old_dir_entry)
            goto out_old;
    }

    if (new_inode) {

        err = -ENOTEMPTY;
        if (old_dir_entry && !f2fs_empty_dir(new_inode))
            goto out_dir;

        err = -ENOENT;
        new_entry = f2fs_find_entry(new_dir, &new_dentry->d_name,
                                    &new_page);
        if (!new_entry)
            goto out_dir;

        f2fs_balance_fs(sbi, true);

        f2fs_lock_op(sbi);

        err = acquire_orphan_inode(sbi);
        if (err)
            goto put_out_dir;

        err = update_dent_inode(old_inode, new_inode,
                                &new_dentry->d_name);
        if (err) {
            release_orphan_inode(sbi);
            goto put_out_dir;
        }

        f2fs_set_link(new_dir, new_entry, new_page, old_inode);

        new_inode->i_ctime = CURRENT_TIME;
        down_write(&F2FS_I(new_inode)->i_sem);
        if (old_dir_entry)
            drop_nlink(new_inode);
        drop_nlink(new_inode);
        up_write(&F2FS_I(new_inode)->i_sem);

        mark_inode_dirty(new_inode);

        if (!new_inode->i_nlink)
            add_orphan_inode(sbi, new_inode->i_ino);
        else
            release_orphan_inode(sbi);

        update_inode_page(old_inode);
        update_inode_page(new_inode);
    } else {
        f2fs_balance_fs(sbi, true);

        f2fs_lock_op(sbi);

        err = f2fs_add_link(new_dentry, old_inode);
        if (err) {
            f2fs_unlock_op(sbi);
            goto out_dir;
        }

        if (old_dir_entry) {
            inc_nlink(new_dir);
            update_inode_page(new_dir);
        }

        /*
         * old entry and new entry can locate in the same inline
         * dentry in inode, when attaching new entry in inline dentry,
         * it could force inline dentry conversion, after that,
         * old_entry and old_page will point to wrong address, in
         * order to avoid this, let's do the check and update here.
         */
        if (is_old_inline && !f2fs_has_inline_dentry(old_dir)) {
            f2fs_put_page(old_page, 0);
            old_page = NULL;

            old_entry = f2fs_find_entry(old_dir,
                                        &old_dentry->d_name, &old_page);
            if (!old_entry) {
                err = -EIO;
                f2fs_unlock_op(sbi);
                goto out_dir;
            }
        }
    }

    down_write(&F2FS_I(old_inode)->i_sem);
    file_lost_pino(old_inode);
    if (new_inode && file_enc_name(new_inode))
        file_set_enc_name(old_inode);
    up_write(&F2FS_I(old_inode)->i_sem);

    old_inode->i_ctime = CURRENT_TIME;
    mark_inode_dirty(old_inode);

    f2fs_delete_entry(old_entry, old_page, old_dir, NULL);

    if (old_dir_entry) {
        if (old_dir != new_dir) {
            f2fs_set_link(old_inode, old_dir_entry,
                          old_dir_page, new_dir);
            update_inode_page(old_inode);
        } else {
            f2fs_dentry_kunmap(old_inode, old_dir_page);
            f2fs_put_page(old_dir_page, 0);
        }
        drop_nlink(old_dir);
        mark_inode_dirty(old_dir);
        update_inode_page(old_dir);
    }

    f2fs_unlock_op(sbi);

    if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir))
        f2fs_sync_fs(sbi->sb, 1);
    return 0;

put_out_dir:
    f2fs_unlock_op(sbi);
    f2fs_dentry_kunmap(new_dir, new_page);
    f2fs_put_page(new_page, 0);
out_dir:
    if (old_dir_entry) {
        f2fs_dentry_kunmap(old_inode, old_dir_page);
        f2fs_put_page(old_dir_page, 0);
    }
out_old:
    f2fs_dentry_kunmap(old_dir, old_page);
    f2fs_put_page(old_page, 0);
out:
    return err;
}

#ifdef CONFIG_F2FS_FS_ENCRYPTION
static void *f2fs_encrypted_follow_link(struct dentry *dentry,
                                        struct nameidata *nd)
{
    struct page *cpage = NULL;
    char *caddr, *paddr = NULL;
    struct f2fs_str cstr = FSTR_INIT(NULL, 0);
    struct f2fs_str pstr = FSTR_INIT(NULL, 0);
    struct inode *inode = dentry->d_inode;
    struct f2fs_encrypted_symlink_data *sd;
    loff_t size = min_t(loff_t, i_size_read(inode), PAGE_SIZE - 1);
    u32 max_size = inode->i_sb->s_blocksize;
    int res;

    res = f2fs_get_encryption_info(inode);
    if (res)
        return ERR_PTR(res);

    cpage = read_mapping_page(inode->i_mapping, 0, NULL);
    if (IS_ERR(cpage))
        return cpage;
    caddr = kmap(cpage);
    caddr[size] = 0;

    /* Symlink is encrypted */
    sd = (struct f2fs_encrypted_symlink_data *)caddr;
    cstr.name = sd->encrypted_path;
    cstr.len = le16_to_cpu(sd->len);

    /* this is broken symlink case */
    if (unlikely(cstr.len == 0)) {
        res = -ENOENT;
        goto errout;
    }

    /* this is broken symlink case */
    if (unlikely(cstr.name[0] == 0)) {
        res = -ENOENT;
        goto errout;
    }

    if ((cstr.len + sizeof(struct f2fs_encrypted_symlink_data) - 1) >
            max_size) {
        /* Symlink data on the disk is corrupted */
        res = -EIO;
        goto errout;
    }
    res = f2fs_fname_crypto_alloc_buffer(inode, cstr.len, &pstr);
    if (res)
        goto errout;

    res = f2fs_fname_disk_to_usr(inode, NULL, &cstr, &pstr);
    if (res < 0)
        goto errout;

    paddr = pstr.name;

    /* Null-terminate the name */
    paddr[res] = '\0';
    nd_set_link(nd, paddr);

    kunmap(cpage);
    page_cache_release(cpage);
    return NULL;
errout:
    f2fs_fname_crypto_free_buffer(&pstr);
    kunmap(cpage);
    page_cache_release(cpage);
    return ERR_PTR(res);
}

void kfree_put_link(struct dentry *dentry, struct nameidata *nd,
                    void *cookie)
{
    char *s = nd_get_link(nd);
    if (!IS_ERR(s))
        kfree(s);
}

const struct inode_operations f2fs_encrypted_symlink_inode_operations = {
    .readlink       = generic_readlink,
    .follow_link    = f2fs_encrypted_follow_link,
    .put_link       = kfree_put_link,
    .getattr	= f2fs_getattr,
    .setattr	= f2fs_setattr,
#ifdef CONFIG_F2FS_FS_XATTR
    .setxattr	= generic_setxattr,
    .getxattr	= generic_getxattr,
    .listxattr	= f2fs_listxattr,
    .removexattr	= generic_removexattr,
#endif
};
#endif

const struct inode_operations f2fs_dir_inode_operations = {
    .create		= f2fs_create,
    .lookup		= f2fs_lookup,
    .link		= f2fs_link,
    .unlink		= f2fs_unlink,
    .symlink	= f2fs_symlink,
    .mkdir		= f2fs_mkdir,
    .rmdir		= f2fs_rmdir,
    .mknod		= f2fs_mknod,
    .rename		= f2fs_rename,
    .getattr	= f2fs_getattr,
    .setattr	= f2fs_setattr,
    .get_acl	= f2fs_get_acl,
#ifdef CONFIG_F2FS_FS_XATTR
    .setxattr	= generic_setxattr,
    .getxattr	= generic_getxattr,
    .listxattr	= f2fs_listxattr,
    .removexattr	= generic_removexattr,
#endif
};

const struct inode_operations f2fs_symlink_inode_operations = {
    .readlink       = generic_readlink,
    .follow_link    = f2fs_follow_link,
    .put_link       = page_put_link,
    .getattr	= f2fs_getattr,
    .setattr	= f2fs_setattr,
#ifdef CONFIG_F2FS_FS_XATTR
    .setxattr	= generic_setxattr,
    .getxattr	= generic_getxattr,
    .listxattr	= f2fs_listxattr,
    .removexattr	= generic_removexattr,
#endif
};

const struct inode_operations f2fs_special_inode_operations = {
    .getattr	= f2fs_getattr,
    .setattr        = f2fs_setattr,
    .get_acl	= f2fs_get_acl,
#ifdef CONFIG_F2FS_FS_XATTR
    .setxattr       = generic_setxattr,
    .getxattr       = generic_getxattr,
    .listxattr	= f2fs_listxattr,
    .removexattr    = generic_removexattr,
#endif
};
Exemplo n.º 12
0
struct dentry *f2fs_get_parent(struct dentry *child)
{
	struct qstr dotdot = {.len = 2, .name = ".."};
	unsigned long ino = f2fs_inode_by_name(child->d_inode, &dotdot);
	if (!ino)
		return ERR_PTR(-ENOENT);
	return d_obtain_alias(f2fs_iget(child->d_inode->i_sb, ino));
}

static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry,
					struct nameidata *nd)
{
	struct inode *inode = NULL;
	struct f2fs_dir_entry *de;
	struct page *page;

	if (dentry->d_name.len > F2FS_NAME_LEN)
		return ERR_PTR(-ENAMETOOLONG);

	de = f2fs_find_entry(dir, &dentry->d_name, &page, nd ? nd->flags : 0);
	if (de) {
		nid_t ino = le32_to_cpu(de->ino);
		if (!f2fs_has_inline_dentry(dir))
			kunmap(page);
		f2fs_put_page(page, 0);

		inode = f2fs_iget(dir->i_sb, ino);
		if (IS_ERR(inode))
			return ERR_CAST(inode);
	}

	return d_splice_alias(inode, dentry);
}

static int f2fs_unlink(struct inode *dir, struct dentry *dentry)
{
	struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
	struct inode *inode = dentry->d_inode;
	struct f2fs_dir_entry *de;
	struct page *page;
	int err = -ENOENT;

	trace_f2fs_unlink_enter(dir, dentry);
	f2fs_balance_fs(sbi);

	de = f2fs_find_entry(dir, &dentry->d_name, &page, 0);
	if (!de)
		goto fail;

	f2fs_lock_op(sbi);
	err = acquire_orphan_inode(sbi);
	if (err) {
		f2fs_unlock_op(sbi);
		if (!f2fs_has_inline_dentry(dir))
			kunmap(page);
		f2fs_put_page(page, 0);
		goto fail;
	}
	f2fs_delete_entry(de, page, dir, inode);
	f2fs_unlock_op(sbi);

	/* In order to evict this inode, we set it dirty */
	mark_inode_dirty(inode);
fail:
	trace_f2fs_unlink_exit(inode, err);
	return err;
}

static int f2fs_symlink(struct inode *dir, struct dentry *dentry,
					const char *symname)
{
	struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
	struct inode *inode;
	size_t symlen = strlen(symname) + 1;
	int err;

	f2fs_balance_fs(sbi);

	inode = f2fs_new_inode(dir, S_IFLNK | S_IRWXUGO);
	if (IS_ERR(inode))
		return PTR_ERR(inode);

	inode->i_op = &f2fs_symlink_inode_operations;
	inode->i_mapping->a_ops = &f2fs_dblock_aops;

	f2fs_lock_op(sbi);
	err = f2fs_add_link(dentry, inode);
	if (err)
		goto out;
	f2fs_unlock_op(sbi);

	err = page_symlink(inode, symname, symlen);
	alloc_nid_done(sbi, inode->i_ino);

	d_instantiate(dentry, inode);
	unlock_new_inode(inode);
	return err;
out:
	handle_failed_inode(inode);
	return err;
}

static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
{
	struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
	struct inode *inode;
	int err;

	f2fs_balance_fs(sbi);

	inode = f2fs_new_inode(dir, S_IFDIR | mode);
	if (IS_ERR(inode))
		return PTR_ERR(inode);

	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_F2FS_ZERO);

	set_inode_flag(F2FS_I(inode), FI_INC_LINK);
	f2fs_lock_op(sbi);
	err = f2fs_add_link(dentry, inode);
	if (err)
		goto out_fail;
	f2fs_unlock_op(sbi);

	stat_inc_inline_dir(inode);
	alloc_nid_done(sbi, inode->i_ino);

	d_instantiate(dentry, inode);
	unlock_new_inode(inode);

	return 0;

out_fail:
	clear_inode_flag(F2FS_I(inode), FI_INC_LINK);
	handle_failed_inode(inode);
	return err;
}

static int f2fs_rmdir(struct inode *dir, struct dentry *dentry)
{
	struct inode *inode = dentry->d_inode;
	if (f2fs_empty_dir(inode))
		return f2fs_unlink(dir, dentry);
	return -ENOTEMPTY;
}

static int f2fs_mknod(struct inode *dir, struct dentry *dentry,
				umode_t mode, dev_t rdev)
{
	struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
	struct inode *inode;
	int err = 0;

	if (!new_valid_dev(rdev))
		return -EINVAL;

	f2fs_balance_fs(sbi);

	inode = f2fs_new_inode(dir, mode);
	if (IS_ERR(inode))
		return PTR_ERR(inode);

	init_special_inode(inode, inode->i_mode, rdev);
	inode->i_op = &f2fs_special_inode_operations;

	f2fs_lock_op(sbi);
	err = f2fs_add_link(dentry, inode);
	if (err)
		goto out;
	f2fs_unlock_op(sbi);

	alloc_nid_done(sbi, inode->i_ino);
	d_instantiate(dentry, inode);
	unlock_new_inode(inode);
	return 0;
out:
	handle_failed_inode(inode);
	return err;
}

static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
			struct inode *new_dir, struct dentry *new_dentry)
{
	struct f2fs_sb_info *sbi = F2FS_I_SB(old_dir);
	struct inode *old_inode = old_dentry->d_inode;
	struct inode *new_inode = new_dentry->d_inode;
	struct page *old_dir_page;
	struct page *old_page, *new_page;
	struct f2fs_dir_entry *old_dir_entry = NULL;
	struct f2fs_dir_entry *old_entry;
	struct f2fs_dir_entry *new_entry;
	int err = -ENOENT;

	f2fs_balance_fs(sbi);

	old_entry = f2fs_find_entry(old_dir, &old_dentry->d_name, &old_page, 0);
	if (!old_entry)
		goto out;

	if (S_ISDIR(old_inode->i_mode)) {
		err = -EIO;
		old_dir_entry = f2fs_parent_dir(old_inode, &old_dir_page);
		if (!old_dir_entry)
			goto out_old;
	}

	if (new_inode) {

		err = -ENOTEMPTY;
		if (old_dir_entry && !f2fs_empty_dir(new_inode))
			goto out_dir;

		err = -ENOENT;
		new_entry = f2fs_find_entry(new_dir, &new_dentry->d_name,
						&new_page, 0);
		if (!new_entry)
			goto out_dir;

		f2fs_lock_op(sbi);

		err = acquire_orphan_inode(sbi);
		if (err)
			goto put_out_dir;

		if (update_dent_inode(old_inode, &new_dentry->d_name)) {
			release_orphan_inode(sbi);
			goto put_out_dir;
		}

		f2fs_set_link(new_dir, new_entry, new_page, old_inode);

		new_inode->i_ctime = CURRENT_TIME;
		down_write(&F2FS_I(new_inode)->i_sem);
		if (old_dir_entry)
			drop_nlink(new_inode);
		drop_nlink(new_inode);
		up_write(&F2FS_I(new_inode)->i_sem);

		mark_inode_dirty(new_inode);

		if (!new_inode->i_nlink)
			add_orphan_inode(sbi, new_inode->i_ino);
		else
			release_orphan_inode(sbi);

		update_inode_page(old_inode);
		update_inode_page(new_inode);
	} else {
		f2fs_lock_op(sbi);

		err = f2fs_add_link(new_dentry, old_inode);
		if (err) {
			f2fs_unlock_op(sbi);
			goto out_dir;
		}

		if (old_dir_entry) {
			inc_nlink(new_dir);
			update_inode_page(new_dir);
		}
	}

	down_write(&F2FS_I(old_inode)->i_sem);
	file_lost_pino(old_inode);
	up_write(&F2FS_I(old_inode)->i_sem);

	old_inode->i_ctime = CURRENT_TIME;
	mark_inode_dirty(old_inode);

	f2fs_delete_entry(old_entry, old_page, old_dir, NULL);

	if (old_dir_entry) {
		if (old_dir != new_dir) {
			f2fs_set_link(old_inode, old_dir_entry,
						old_dir_page, new_dir);
			update_inode_page(old_inode);
		} else {
			if (!f2fs_has_inline_dentry(old_inode))
				kunmap(old_dir_page);
			f2fs_put_page(old_dir_page, 0);
		}
		drop_nlink(old_dir);
		mark_inode_dirty(old_dir);
		update_inode_page(old_dir);
	}

	f2fs_unlock_op(sbi);
	return 0;

put_out_dir:
	f2fs_unlock_op(sbi);
	if (!f2fs_has_inline_dentry(new_dir))
		kunmap(new_page);
	f2fs_put_page(new_page, 0);
out_dir:
	if (old_dir_entry) {
		if (!f2fs_has_inline_dentry(old_inode))
			kunmap(old_dir_page);
		f2fs_put_page(old_dir_page, 0);
	}
out_old:
	if (!f2fs_has_inline_dentry(old_dir))
		kunmap(old_page);
	f2fs_put_page(old_page, 0);
out:
	return err;
}

const struct inode_operations f2fs_dir_inode_operations = {
	.create		= f2fs_create,
	.lookup		= f2fs_lookup,
	.link		= f2fs_link,
	.unlink		= f2fs_unlink,
	.symlink	= f2fs_symlink,
	.mkdir		= f2fs_mkdir,
	.rmdir		= f2fs_rmdir,
	.mknod		= f2fs_mknod,
	.rename		= f2fs_rename,
	.getattr	= f2fs_getattr,
	.setattr	= f2fs_setattr,
	.get_acl	= f2fs_get_acl,
#ifdef CONFIG_F2FS_FS_XATTR
	.setxattr	= generic_setxattr,
	.getxattr	= generic_getxattr,
	.listxattr	= f2fs_listxattr,
	.removexattr	= generic_removexattr,
#endif
};

const struct inode_operations f2fs_symlink_inode_operations = {
	.readlink       = generic_readlink,
	.follow_link    = page_follow_link_light,
	.put_link       = page_put_link,
	.getattr	= f2fs_getattr,
	.setattr	= f2fs_setattr,
#ifdef CONFIG_F2FS_FS_XATTR
	.setxattr	= generic_setxattr,
	.getxattr	= generic_getxattr,
	.listxattr	= f2fs_listxattr,
	.removexattr	= generic_removexattr,
#endif
};

const struct inode_operations f2fs_special_inode_operations = {
	.getattr	= f2fs_getattr,
	.setattr        = f2fs_setattr,
	.get_acl	= f2fs_get_acl,
#ifdef CONFIG_F2FS_FS_XATTR
	.setxattr       = generic_setxattr,
	.getxattr       = generic_getxattr,
	.listxattr	= f2fs_listxattr,
	.removexattr    = generic_removexattr,
#endif
};
Exemplo n.º 13
0
Arquivo: inode.c Projeto: Lyude/linux
static int do_read_inode(struct inode *inode)
{
	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
	struct f2fs_inode_info *fi = F2FS_I(inode);
	struct page *node_page;
	struct f2fs_inode *ri;
	projid_t i_projid;
	int err;

	/* Check if ino is within scope */
	if (f2fs_check_nid_range(sbi, inode->i_ino))
		return -EINVAL;

	node_page = f2fs_get_node_page(sbi, inode->i_ino);
	if (IS_ERR(node_page))
		return PTR_ERR(node_page);

	ri = F2FS_INODE(node_page);

	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 = SECTOR_FROM_BLOCK(le64_to_cpu(ri->i_blocks) - 1);

	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);
	if (S_ISDIR(inode->i_mode))
		fi->i_current_depth = le32_to_cpu(ri->i_current_depth);
	else if (S_ISREG(inode->i_mode))
		fi->i_gc_failures[GC_FAILURE_PIN] =
					le16_to_cpu(ri->i_gc_failures);
	fi->i_xattr_nid = le32_to_cpu(ri->i_xattr_nid);
	fi->i_flags = le32_to_cpu(ri->i_flags);
	fi->flags = 0;
	fi->i_advise = ri->i_advise;
	fi->i_pino = le32_to_cpu(ri->i_pino);
	fi->i_dir_level = ri->i_dir_level;

	if (f2fs_init_extent_tree(inode, &ri->i_ext))
		set_page_dirty(node_page);

	get_inline_info(inode, ri);

	fi->i_extra_isize = f2fs_has_extra_attr(inode) ?
					le16_to_cpu(ri->i_extra_isize) : 0;

	if (f2fs_sb_has_flexible_inline_xattr(sbi->sb)) {
		fi->i_inline_xattr_size = le16_to_cpu(ri->i_inline_xattr_size);
	} else if (f2fs_has_inline_xattr(inode) ||
				f2fs_has_inline_dentry(inode)) {
		fi->i_inline_xattr_size = DEFAULT_INLINE_XATTR_ADDRS;
	} else {

		/*
		 * Previous inline data or directory always reserved 200 bytes
		 * in inode layout, even if inline_xattr is disabled. In order
		 * to keep inline_dentry's structure for backward compatibility,
		 * we get the space back only from inline_data.
		 */
		fi->i_inline_xattr_size = 0;
	}

	if (!sanity_check_inode(inode, node_page)) {
		f2fs_put_page(node_page, 1);
		return -EINVAL;
	}

	/* check data exist */
	if (f2fs_has_inline_data(inode) && !f2fs_exist_data(inode))
		__recover_inline_status(inode, node_page);

	/* get rdev by using inline_info */
	__get_inode_rdev(inode, ri);

	if (S_ISREG(inode->i_mode)) {
		err = __written_first_block(sbi, ri);
		if (err < 0) {
			f2fs_put_page(node_page, 1);
			return err;
		}
		if (!err)
			set_inode_flag(inode, FI_FIRST_BLOCK_WRITTEN);
	}

	if (!f2fs_need_inode_block_update(sbi, inode->i_ino))
		fi->last_disk_size = inode->i_size;

	if (fi->i_flags & F2FS_PROJINHERIT_FL)
		set_inode_flag(inode, FI_PROJ_INHERIT);

	if (f2fs_has_extra_attr(inode) && f2fs_sb_has_project_quota(sbi->sb) &&
			F2FS_FITS_IN_INODE(ri, fi->i_extra_isize, i_projid))
		i_projid = (projid_t)le32_to_cpu(ri->i_projid);
	else
		i_projid = F2FS_DEF_PROJID;
	fi->i_projid = make_kprojid(&init_user_ns, i_projid);

	if (f2fs_has_extra_attr(inode) && f2fs_sb_has_inode_crtime(sbi->sb) &&
			F2FS_FITS_IN_INODE(ri, fi->i_extra_isize, i_crtime)) {
		fi->i_crtime.tv_sec = le64_to_cpu(ri->i_crtime);
		fi->i_crtime.tv_nsec = le32_to_cpu(ri->i_crtime_nsec);
	}

	F2FS_I(inode)->i_disk_time[0] = inode->i_atime;
	F2FS_I(inode)->i_disk_time[1] = inode->i_ctime;
	F2FS_I(inode)->i_disk_time[2] = inode->i_mtime;
	F2FS_I(inode)->i_disk_time[3] = F2FS_I(inode)->i_crtime;
	f2fs_put_page(node_page, 1);

	stat_inc_inline_xattr(inode);
	stat_inc_inline_inode(inode);
	stat_inc_inline_dir(inode);

	return 0;
}
Exemplo n.º 14
0
Arquivo: inode.c Projeto: Lyude/linux
static bool sanity_check_inode(struct inode *inode, struct page *node_page)
{
	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
	struct f2fs_inode_info *fi = F2FS_I(inode);
	unsigned long long iblocks;

	iblocks = le64_to_cpu(F2FS_INODE(node_page)->i_blocks);
	if (!iblocks) {
		set_sbi_flag(sbi, SBI_NEED_FSCK);
		f2fs_msg(sbi->sb, KERN_WARNING,
			"%s: corrupted inode i_blocks i_ino=%lx iblocks=%llu, "
			"run fsck to fix.",
			__func__, inode->i_ino, iblocks);
		return false;
	}

	if (ino_of_node(node_page) != nid_of_node(node_page)) {
		set_sbi_flag(sbi, SBI_NEED_FSCK);
		f2fs_msg(sbi->sb, KERN_WARNING,
			"%s: corrupted inode footer i_ino=%lx, ino,nid: "
			"[%u, %u] run fsck to fix.",
			__func__, inode->i_ino,
			ino_of_node(node_page), nid_of_node(node_page));
		return false;
	}

	if (f2fs_sb_has_flexible_inline_xattr(sbi->sb)
			&& !f2fs_has_extra_attr(inode)) {
		set_sbi_flag(sbi, SBI_NEED_FSCK);
		f2fs_msg(sbi->sb, KERN_WARNING,
			"%s: corrupted inode ino=%lx, run fsck to fix.",
			__func__, inode->i_ino);
		return false;
	}

	if (f2fs_has_extra_attr(inode) &&
			!f2fs_sb_has_extra_attr(sbi->sb)) {
		set_sbi_flag(sbi, SBI_NEED_FSCK);
		f2fs_msg(sbi->sb, KERN_WARNING,
			"%s: inode (ino=%lx) is with extra_attr, "
			"but extra_attr feature is off",
			__func__, inode->i_ino);
		return false;
	}

	if (fi->i_extra_isize > F2FS_TOTAL_EXTRA_ATTR_SIZE ||
			fi->i_extra_isize % sizeof(__le32)) {
		set_sbi_flag(sbi, SBI_NEED_FSCK);
		f2fs_msg(sbi->sb, KERN_WARNING,
			"%s: inode (ino=%lx) has corrupted i_extra_isize: %d, "
			"max: %zu",
			__func__, inode->i_ino, fi->i_extra_isize,
			F2FS_TOTAL_EXTRA_ATTR_SIZE);
		return false;
	}

	if (F2FS_I(inode)->extent_tree) {
		struct extent_info *ei = &F2FS_I(inode)->extent_tree->largest;

		if (ei->len &&
			(!f2fs_is_valid_blkaddr(sbi, ei->blk, DATA_GENERIC) ||
			!f2fs_is_valid_blkaddr(sbi, ei->blk + ei->len - 1,
							DATA_GENERIC))) {
			set_sbi_flag(sbi, SBI_NEED_FSCK);
			f2fs_msg(sbi->sb, KERN_WARNING,
				"%s: inode (ino=%lx) extent info [%u, %u, %u] "
				"is incorrect, run fsck to fix",
				__func__, inode->i_ino,
				ei->blk, ei->fofs, ei->len);
			return false;
		}
	}

	if (f2fs_has_inline_data(inode) &&
			(!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode))) {
		set_sbi_flag(sbi, SBI_NEED_FSCK);
		f2fs_msg(sbi->sb, KERN_WARNING,
			"%s: inode (ino=%lx, mode=%u) should not have "
			"inline_data, run fsck to fix",
			__func__, inode->i_ino, inode->i_mode);
		return false;
	}

	if (f2fs_has_inline_dentry(inode) && !S_ISDIR(inode->i_mode)) {
		set_sbi_flag(sbi, SBI_NEED_FSCK);
		f2fs_msg(sbi->sb, KERN_WARNING,
			"%s: inode (ino=%lx, mode=%u) should not have "
			"inline_dentry, run fsck to fix",
			__func__, inode->i_ino, inode->i_mode);
		return false;
	}

	return true;
}
Exemplo n.º 15
0
Arquivo: namei.c Projeto: mdamt/linux
static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
			struct inode *new_dir, struct dentry *new_dentry,
			unsigned int flags)
{
	struct f2fs_sb_info *sbi = F2FS_I_SB(old_dir);
	struct inode *old_inode = d_inode(old_dentry);
	struct inode *new_inode = d_inode(new_dentry);
	struct inode *whiteout = NULL;
	struct page *old_dir_page;
	struct page *old_page, *new_page = NULL;
	struct f2fs_dir_entry *old_dir_entry = NULL;
	struct f2fs_dir_entry *old_entry;
	struct f2fs_dir_entry *new_entry;
	bool is_old_inline = f2fs_has_inline_dentry(old_dir);
	int err = -ENOENT;

	if ((f2fs_encrypted_inode(old_dir) &&
			!fscrypt_has_encryption_key(old_dir)) ||
			(f2fs_encrypted_inode(new_dir) &&
			!fscrypt_has_encryption_key(new_dir)))
		return -ENOKEY;

	if ((old_dir != new_dir) && f2fs_encrypted_inode(new_dir) &&
			!fscrypt_has_permitted_context(new_dir, old_inode)) {
		err = -EPERM;
		goto out;
	}

	err = dquot_initialize(old_dir);
	if (err)
		goto out;

	err = dquot_initialize(new_dir);
	if (err)
		goto out;

	old_entry = f2fs_find_entry(old_dir, &old_dentry->d_name, &old_page);
	if (!old_entry) {
		if (IS_ERR(old_page))
			err = PTR_ERR(old_page);
		goto out;
	}

	if (S_ISDIR(old_inode->i_mode)) {
		old_dir_entry = f2fs_parent_dir(old_inode, &old_dir_page);
		if (!old_dir_entry) {
			if (IS_ERR(old_dir_page))
				err = PTR_ERR(old_dir_page);
			goto out_old;
		}
	}

	if (flags & RENAME_WHITEOUT) {
		err = f2fs_create_whiteout(old_dir, &whiteout);
		if (err)
			goto out_dir;
	}

	if (new_inode) {

		err = -ENOTEMPTY;
		if (old_dir_entry && !f2fs_empty_dir(new_inode))
			goto out_whiteout;

		err = -ENOENT;
		new_entry = f2fs_find_entry(new_dir, &new_dentry->d_name,
						&new_page);
		if (!new_entry) {
			if (IS_ERR(new_page))
				err = PTR_ERR(new_page);
			goto out_whiteout;
		}

		f2fs_balance_fs(sbi, true);

		f2fs_lock_op(sbi);

		err = acquire_orphan_inode(sbi);
		if (err)
			goto put_out_dir;

		f2fs_set_link(new_dir, new_entry, new_page, old_inode);

		new_inode->i_ctime = current_time(new_inode);
		down_write(&F2FS_I(new_inode)->i_sem);
		if (old_dir_entry)
			f2fs_i_links_write(new_inode, false);
		f2fs_i_links_write(new_inode, false);
		up_write(&F2FS_I(new_inode)->i_sem);

		if (!new_inode->i_nlink)
			add_orphan_inode(new_inode);
		else
			release_orphan_inode(sbi);
	} else {
		f2fs_balance_fs(sbi, true);

		f2fs_lock_op(sbi);

		err = f2fs_add_link(new_dentry, old_inode);
		if (err) {
			f2fs_unlock_op(sbi);
			goto out_whiteout;
		}

		if (old_dir_entry)
			f2fs_i_links_write(new_dir, true);

		/*
		 * old entry and new entry can locate in the same inline
		 * dentry in inode, when attaching new entry in inline dentry,
		 * it could force inline dentry conversion, after that,
		 * old_entry and old_page will point to wrong address, in
		 * order to avoid this, let's do the check and update here.
		 */
		if (is_old_inline && !f2fs_has_inline_dentry(old_dir)) {
			f2fs_put_page(old_page, 0);
			old_page = NULL;

			old_entry = f2fs_find_entry(old_dir,
						&old_dentry->d_name, &old_page);
			if (!old_entry) {
				err = -ENOENT;
				if (IS_ERR(old_page))
					err = PTR_ERR(old_page);
				f2fs_unlock_op(sbi);
				goto out_whiteout;
			}
		}
	}

	down_write(&F2FS_I(old_inode)->i_sem);
	if (!old_dir_entry || whiteout)
		file_lost_pino(old_inode);
	else
		F2FS_I(old_inode)->i_pino = new_dir->i_ino;
	up_write(&F2FS_I(old_inode)->i_sem);

	old_inode->i_ctime = current_time(old_inode);
	f2fs_mark_inode_dirty_sync(old_inode, false);

	f2fs_delete_entry(old_entry, old_page, old_dir, NULL);

	if (whiteout) {
		whiteout->i_state |= I_LINKABLE;
		set_inode_flag(whiteout, FI_INC_LINK);
		err = f2fs_add_link(old_dentry, whiteout);
		if (err)
			goto put_out_dir;
		whiteout->i_state &= ~I_LINKABLE;
		iput(whiteout);
	}

	if (old_dir_entry) {
		if (old_dir != new_dir && !whiteout) {
			f2fs_set_link(old_inode, old_dir_entry,
						old_dir_page, new_dir);
		} else {
			f2fs_dentry_kunmap(old_inode, old_dir_page);
			f2fs_put_page(old_dir_page, 0);
		}
		f2fs_i_links_write(old_dir, false);
	}

	f2fs_unlock_op(sbi);

	if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir))
		f2fs_sync_fs(sbi->sb, 1);
	return 0;

put_out_dir:
	f2fs_unlock_op(sbi);
	if (new_page) {
		f2fs_dentry_kunmap(new_dir, new_page);
		f2fs_put_page(new_page, 0);
	}
out_whiteout:
	if (whiteout)
		iput(whiteout);
out_dir:
	if (old_dir_entry) {
		f2fs_dentry_kunmap(old_inode, old_dir_page);
		f2fs_put_page(old_dir_page, 0);
	}
out_old:
	f2fs_dentry_kunmap(old_dir, old_page);
	f2fs_put_page(old_page, 0);
out:
	return err;
}