static unsigned long long iblock_emulate_read_cap_with_block_size(
	struct se_device *dev,
	struct block_device *bd,
	struct request_queue *q)
{
	unsigned long long blocks_long = (div_u64(i_size_read(bd->bd_inode),
					bdev_logical_block_size(bd)) - 1);
	u32 block_size = bdev_logical_block_size(bd);

	if (block_size == dev->dev_attrib.block_size)
		return blocks_long;

	switch (block_size) {
	case 4096:
		switch (dev->dev_attrib.block_size) {
		case 2048:
			blocks_long <<= 1;
			break;
		case 1024:
			blocks_long <<= 2;
			break;
		case 512:
			blocks_long <<= 3;
		default:
			break;
		}
		break;
	case 2048:
		switch (dev->dev_attrib.block_size) {
		case 4096:
			blocks_long >>= 1;
			break;
		case 1024:
			blocks_long <<= 1;
			break;
		case 512:
			blocks_long <<= 2;
			break;
		default:
			break;
		}
		break;
	case 1024:
		switch (dev->dev_attrib.block_size) {
		case 4096:
			blocks_long >>= 2;
			break;
		case 2048:
			blocks_long >>= 1;
			break;
		case 512:
			blocks_long <<= 1;
			break;
		default:
			break;
		}
		break;
	case 512:
		switch (dev->dev_attrib.block_size) {
		case 4096:
			blocks_long >>= 3;
			break;
		case 2048:
			blocks_long >>= 2;
			break;
		case 1024:
			blocks_long >>= 1;
			break;
		default:
			break;
		}
		break;
	default:
		break;
	}

	return blocks_long;
}
/**
 * nilfs_resize_fs - resize the filesystem
 * @sb: super block instance
 * @newsize: new size of the filesystem (in bytes)
 */
int nilfs_resize_fs(struct super_block *sb, __u64 newsize)
{
	struct the_nilfs *nilfs = sb->s_fs_info;
	struct nilfs_super_block **sbp;
	__u64 devsize, newnsegs;
	loff_t sb2off;
	int ret;

	ret = -ERANGE;
	devsize = i_size_read(sb->s_bdev->bd_inode);
	if (newsize > devsize)
		goto out;

	/*
	 * Write lock is required to protect some functions depending
	 * on the number of segments, the number of reserved segments,
	 * and so forth.
	 */
	down_write(&nilfs->ns_segctor_sem);

	sb2off = NILFS_SB2_OFFSET_BYTES(newsize);
	newnsegs = sb2off >> nilfs->ns_blocksize_bits;
	do_div(newnsegs, nilfs->ns_blocks_per_segment);

	ret = nilfs_sufile_resize(nilfs->ns_sufile, newnsegs);
	up_write(&nilfs->ns_segctor_sem);
	if (ret < 0)
		goto out;

	ret = nilfs_construct_segment(sb);
	if (ret < 0)
		goto out;

	down_write(&nilfs->ns_sem);
	nilfs_move_2nd_super(sb, sb2off);
	ret = -EIO;
	sbp = nilfs_prepare_super(sb, 0);
	if (likely(sbp)) {
		nilfs_set_log_cursor(sbp[0], nilfs);
		/*
		 * Drop NILFS_RESIZE_FS flag for compatibility with
		 * mount-time resize which may be implemented in a
		 * future release.
		 */
		sbp[0]->s_state = cpu_to_le16(le16_to_cpu(sbp[0]->s_state) &
					      ~NILFS_RESIZE_FS);
		sbp[0]->s_dev_size = cpu_to_le64(newsize);
		sbp[0]->s_nsegments = cpu_to_le64(nilfs->ns_nsegments);
		if (sbp[1])
			memcpy(sbp[1], sbp[0], nilfs->ns_sbsize);
		ret = nilfs_commit_super(sb, NILFS_SB_COMMIT_ALL);
	}
	up_write(&nilfs->ns_sem);

	/*
	 * Reset the range of allocatable segments last.  This order
	 * is important in the case of expansion because the secondary
	 * superblock must be protected from log write until migration
	 * completes.
	 */
	if (!ret)
		nilfs_sufile_set_alloc_range(nilfs->ns_sufile, 0, newnsegs - 1);
out:
	return ret;
}
static int ocfs2_get_block(struct inode *inode, sector_t iblock,
			   struct buffer_head *bh_result, int create)
{
	int err = 0;
	unsigned int ext_flags;
	u64 max_blocks = bh_result->b_size >> inode->i_blkbits;
	u64 p_blkno, count, past_eof;
	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);

	mlog_entry("(0x%p, %llu, 0x%p, %d)\n", inode,
		   (unsigned long long)iblock, bh_result, create);

	if (OCFS2_I(inode)->ip_flags & OCFS2_INODE_SYSTEM_FILE)
		mlog(ML_NOTICE, "get_block on system inode 0x%p (%lu)\n",
		     inode, inode->i_ino);

	if (S_ISLNK(inode->i_mode)) {
		/* this always does I/O for some reason. */
		err = ocfs2_symlink_get_block(inode, iblock, bh_result, create);
		goto bail;
	}

	err = ocfs2_extent_map_get_blocks(inode, iblock, &p_blkno, &count,
					  &ext_flags);
	if (err) {
		mlog(ML_ERROR, "Error %d from get_blocks(0x%p, %llu, 1, "
		     "%llu, NULL)\n", err, inode, (unsigned long long)iblock,
		     (unsigned long long)p_blkno);
		goto bail;
	}

	if (max_blocks < count)
		count = max_blocks;

	/*
	 * ocfs2 never allocates in this function - the only time we
	 * need to use BH_New is when we're extending i_size on a file
	 * system which doesn't support holes, in which case BH_New
	 * allows block_prepare_write() to zero.
	 *
	 * If we see this on a sparse file system, then a truncate has
	 * raced us and removed the cluster. In this case, we clear
	 * the buffers dirty and uptodate bits and let the buffer code
	 * ignore it as a hole.
	 */
	if (create && p_blkno == 0 && ocfs2_sparse_alloc(osb)) {
		clear_buffer_dirty(bh_result);
		clear_buffer_uptodate(bh_result);
		goto bail;
	}

	/* Treat the unwritten extent as a hole for zeroing purposes. */
	if (p_blkno && !(ext_flags & OCFS2_EXT_UNWRITTEN))
		map_bh(bh_result, inode->i_sb, p_blkno);

	bh_result->b_size = count << inode->i_blkbits;

	if (!ocfs2_sparse_alloc(osb)) {
		if (p_blkno == 0) {
			err = -EIO;
			mlog(ML_ERROR,
			     "iblock = %llu p_blkno = %llu blkno=(%llu)\n",
			     (unsigned long long)iblock,
			     (unsigned long long)p_blkno,
			     (unsigned long long)OCFS2_I(inode)->ip_blkno);
			mlog(ML_ERROR, "Size %llu, clusters %u\n", (unsigned long long)i_size_read(inode), OCFS2_I(inode)->ip_clusters);
			dump_stack();
		}

		past_eof = ocfs2_blocks_for_bytes(inode->i_sb, i_size_read(inode));
		mlog(0, "Inode %lu, past_eof = %llu\n", inode->i_ino,
		     (unsigned long long)past_eof);

		if (create && (iblock >= past_eof))
			set_buffer_new(bh_result);
	}

bail:
	if (err < 0)
		err = -EIO;

	mlog_exit(err);
	return err;
}
Beispiel #4
0
STATIC ssize_t
xfs_file_read_iter(
	struct kiocb		*iocb,
	struct iov_iter		*to)
{
	struct file		*file = iocb->ki_filp;
	struct inode		*inode = file->f_mapping->host;
	struct xfs_inode	*ip = XFS_I(inode);
	struct xfs_mount	*mp = ip->i_mount;
	size_t			size = iov_iter_count(to);
	ssize_t			ret = 0;
	int			ioflags = 0;
	xfs_fsize_t		n;
	loff_t			pos = iocb->ki_pos;

	XFS_STATS_INC(xs_read_calls);

	if (unlikely(file->f_flags & O_DIRECT))
		ioflags |= XFS_IO_ISDIRECT;
	if (file->f_mode & FMODE_NOCMTIME)
		ioflags |= XFS_IO_INVIS;

	if (unlikely(ioflags & XFS_IO_ISDIRECT)) {
		xfs_buftarg_t	*target =
			XFS_IS_REALTIME_INODE(ip) ?
				mp->m_rtdev_targp : mp->m_ddev_targp;
		/* DIO must be aligned to device logical sector size */
		if ((pos | size) & target->bt_logical_sectormask) {
			if (pos == i_size_read(inode))
				return 0;
			return -EINVAL;
		}
	}

	n = mp->m_super->s_maxbytes - pos;
	if (n <= 0 || size == 0)
		return 0;

	if (n < size)
		size = n;

	if (XFS_FORCED_SHUTDOWN(mp))
		return -EIO;

	/*
	 * Locking is a bit tricky here. If we take an exclusive lock
	 * for direct IO, we effectively serialise all new concurrent
	 * read IO to this file and block it behind IO that is currently in
	 * progress because IO in progress holds the IO lock shared. We only
	 * need to hold the lock exclusive to blow away the page cache, so
	 * only take lock exclusively if the page cache needs invalidation.
	 * This allows the normal direct IO case of no page cache pages to
	 * proceeed concurrently without serialisation.
	 */
	xfs_rw_ilock(ip, XFS_IOLOCK_SHARED);
	if ((ioflags & XFS_IO_ISDIRECT) && inode->i_mapping->nrpages) {
		xfs_rw_iunlock(ip, XFS_IOLOCK_SHARED);
		xfs_rw_ilock(ip, XFS_IOLOCK_EXCL);

		if (inode->i_mapping->nrpages) {
			ret = filemap_write_and_wait_range(
							VFS_I(ip)->i_mapping,
							pos, -1);
			if (ret) {
				xfs_rw_iunlock(ip, XFS_IOLOCK_EXCL);
				return ret;
			}
			truncate_pagecache_range(VFS_I(ip), pos, -1);
		}
		xfs_rw_ilock_demote(ip, XFS_IOLOCK_EXCL);
	}

	trace_xfs_file_read(ip, size, pos, ioflags);

	ret = generic_file_read_iter(iocb, to);
	if (ret > 0)
		XFS_STATS_ADD(xs_read_bytes, ret);

	xfs_rw_iunlock(ip, XFS_IOLOCK_SHARED);
	return ret;
}
Beispiel #5
0
/* * bitmap_init_from_disk -- called at bitmap_create time to initialize
 * the in-memory bitmap from the on-disk bitmap -- also, sets up the
 * memory mapping of the bitmap file
 * Special cases:
 *   if there's no bitmap file, or if the bitmap file had been
 *   previously kicked from the array, we mark all the bits as
 *   1's in order to cause a full resync.
 *
 * We ignore all bits for sectors that end earlier than 'start'.
 * This is used when reading an out-of-date bitmap...
 */
static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start)
{
    unsigned long i, chunks, index, oldindex, bit;
    struct page *page = NULL, *oldpage = NULL;
    unsigned long num_pages, bit_cnt = 0;
    struct file *file;
    unsigned long bytes, offset, dummy;
    int outofdate;
    int ret = -ENOSPC;
    void *paddr;

    chunks = bitmap->chunks;
    file = bitmap->file;

    BUG_ON(!file && !bitmap->offset);

#ifdef INJECT_FAULTS_3
    outofdate = 1;
#else
    outofdate = bitmap->flags & BITMAP_STALE;
#endif
    if (outofdate)
        printk(KERN_INFO "%s: bitmap file is out of date, doing full "
               "recovery\n", bmname(bitmap));

    bytes = (chunks + 7) / 8;

    num_pages = (bytes + sizeof(bitmap_super_t) + PAGE_SIZE - 1) / PAGE_SIZE;

    if (file && i_size_read(file->f_mapping->host) < bytes + sizeof(bitmap_super_t)) {
        printk(KERN_INFO "%s: bitmap file too short %lu < %lu\n",
               bmname(bitmap),
               (unsigned long) i_size_read(file->f_mapping->host),
               bytes + sizeof(bitmap_super_t));
        goto out;
    }

    ret = -ENOMEM;

    bitmap->filemap = kmalloc(sizeof(struct page *) * num_pages, GFP_KERNEL);
    if (!bitmap->filemap)
        goto out;

    bitmap->filemap_attr = kzalloc(sizeof(long) * num_pages, GFP_KERNEL);
    if (!bitmap->filemap_attr)
        goto out;

    oldindex = ~0L;

    for (i = 0; i < chunks; i++) {
        int b;
        index = file_page_index(i);
        bit = file_page_offset(i);
        if (index != oldindex) { /* this is a new page, read it in */
            /* unmap the old page, we're done with it */
            if (index == 0) {
                /*
                 * if we're here then the superblock page
                 * contains some bits (PAGE_SIZE != sizeof sb)
                 * we've already read it in, so just use it
                 */
                page = bitmap->sb_page;
                offset = sizeof(bitmap_super_t);
            } else if (file) {
                page = read_page(file, index, &dummy);
                offset = 0;
            } else {
                page = read_sb_page(bitmap->mddev, bitmap->offset, index);
                offset = 0;
            }
            if (IS_ERR(page)) { /* read error */
                ret = PTR_ERR(page);
                goto out;
            }

            oldindex = index;
            oldpage = page;

            if (outofdate) {
                /*
                 * if bitmap is out of date, dirty the
                 * whole page and write it out
                 */
                paddr = kmap_atomic(page, KM_USER0);
                memset(paddr + offset, 0xff,
                       PAGE_SIZE - offset);
                kunmap_atomic(paddr, KM_USER0);
                ret = write_page(bitmap, page, 1);
                if (ret) {
                    /* release, page not in filemap yet */
                    put_page(page);
                    goto out;
                }
            }

            bitmap->filemap[bitmap->file_pages++] = page;
        }
        paddr = kmap_atomic(page, KM_USER0);
        if (bitmap->flags & BITMAP_HOSTENDIAN)
            b = test_bit(bit, paddr);
        else
            b = ext2_test_bit(bit, paddr);
        kunmap_atomic(paddr, KM_USER0);
        if (b) {
            /* if the disk bit is set, set the memory bit */
            bitmap_set_memory_bits(bitmap, i << CHUNK_BLOCK_SHIFT(bitmap),
                                   ((i+1) << (CHUNK_BLOCK_SHIFT(bitmap)) >= start)
                                  );
            bit_cnt++;
            set_page_attr(bitmap, page, BITMAP_PAGE_CLEAN);
        }
    }

    /* everything went OK */
    ret = 0;
    bitmap_mask_state(bitmap, BITMAP_STALE, MASK_UNSET);

    if (bit_cnt) { /* Kick recovery if any bits were set */
        set_bit(MD_RECOVERY_NEEDED, &bitmap->mddev->recovery);
        md_wakeup_thread(bitmap->mddev->thread);
    }

out:
    printk(KERN_INFO "%s: bitmap initialized from disk: "
           "read %lu/%lu pages, set %lu bits, status: %d\n",
           bmname(bitmap), bitmap->file_pages, num_pages, bit_cnt, ret);

    return ret;
}
Beispiel #6
0
int __generic_block_fiemap(struct inode *inode,
                           struct fiemap_extent_info *fieinfo, u64 start,
                           u64 len, get_block_t *get_block)
{
    struct buffer_head tmp;
    unsigned long long start_blk;
    long long length = 0, map_len = 0;
    u64 logical = 0, phys = 0, size = 0;
    u32 flags = FIEMAP_EXTENT_MERGED;
    int ret = 0, past_eof = 0, whole_file = 0;

    if ((ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC)))
        return ret;

    start_blk = logical_to_blk(inode, start);

    length = (long long)min_t(u64, len, i_size_read(inode));
    if (length < len)
        whole_file = 1;

    map_len = length;

    do {
        /*
         * we set b_size to the total size we want so it will map as
         * many contiguous blocks as possible at once
         */
        memset(&tmp, 0, sizeof(struct buffer_head));
        tmp.b_size = map_len;

        ret = get_block(inode, start_blk, &tmp, 0);
        if (ret)
            break;

        /* HOLE */
        if (!buffer_mapped(&tmp)) {
            length -= blk_to_logical(inode, 1);
            start_blk++;

            /*
             * we want to handle the case where there is an
             * allocated block at the front of the file, and then
             * nothing but holes up to the end of the file properly,
             * to make sure that extent at the front gets properly
             * marked with FIEMAP_EXTENT_LAST
             */
            if (!past_eof &&
                    blk_to_logical(inode, start_blk) >=
                    blk_to_logical(inode, 0)+i_size_read(inode))
                past_eof = 1;

            /*
             * first hole after going past the EOF, this is our
             * last extent
             */
            if (past_eof && size) {
                flags = FIEMAP_EXTENT_MERGED|FIEMAP_EXTENT_LAST;
                ret = fiemap_fill_next_extent(fieinfo, logical,
                                              phys, size,
                                              flags);
                break;
            }

            /* if we have holes up to/past EOF then we're done */
            if (length <= 0 || past_eof)
                break;
        } else {
            /*
             * we have gone over the length of what we wanted to
             * map, and it wasn't the entire file, so add the extent
             * we got last time and exit.
             *
             * This is for the case where say we want to map all the
             * way up to the second to the last block in a file, but
             * the last block is a hole, making the second to last
             * block FIEMAP_EXTENT_LAST.  In this case we want to
             * see if there is a hole after the second to last block
             * so we can mark it properly.  If we found data after
             * we exceeded the length we were requesting, then we
             * are good to go, just add the extent to the fieinfo
             * and break
             */
            if (length <= 0 && !whole_file) {
                ret = fiemap_fill_next_extent(fieinfo, logical,
                                              phys, size,
                                              flags);
                break;
            }

            /*
             * if size != 0 then we know we already have an extent
             * to add, so add it.
             */
            if (size) {
                ret = fiemap_fill_next_extent(fieinfo, logical,
                                              phys, size,
                                              flags);
                if (ret)
                    break;
            }

            logical = blk_to_logical(inode, start_blk);
            phys = blk_to_logical(inode, tmp.b_blocknr);
            size = tmp.b_size;
            flags = FIEMAP_EXTENT_MERGED;

            length -= tmp.b_size;
            start_blk += logical_to_blk(inode, size);

            /*
             * If we are past the EOF, then we need to make sure as
             * soon as we find a hole that the last extent we found
             * is marked with FIEMAP_EXTENT_LAST
             */
            if (!past_eof &&
                    logical+size >=
                    blk_to_logical(inode, 0)+i_size_read(inode))
                past_eof = 1;
        }
        cond_resched();
    } while (1);

    /* if ret is 1 then we just hit the end of the extent array */
    if (ret == 1)
        ret = 0;

    return ret;
}
Beispiel #7
0
STATIC loff_t
xfs_seek_data(
	struct file		*file,
	loff_t			start)
{
	struct inode		*inode = file->f_mapping->host;
	struct xfs_inode	*ip = XFS_I(inode);
	struct xfs_mount	*mp = ip->i_mount;
	loff_t			uninitialized_var(offset);
	xfs_fsize_t		isize;
	xfs_fileoff_t		fsbno;
	xfs_filblks_t		end;
	uint			lock;
	int			error;

	lock = xfs_ilock_data_map_shared(ip);

	isize = i_size_read(inode);
	if (start >= isize) {
		error = -ENXIO;
		goto out_unlock;
	}

	/*
	 * Try to read extents from the first block indicated
	 * by fsbno to the end block of the file.
	 */
	fsbno = XFS_B_TO_FSBT(mp, start);
	end = XFS_B_TO_FSB(mp, isize);
	for (;;) {
		struct xfs_bmbt_irec	map[2];
		int			nmap = 2;
		unsigned int		i;

		error = xfs_bmapi_read(ip, fsbno, end - fsbno, map, &nmap,
				       XFS_BMAPI_ENTIRE);
		if (error)
			goto out_unlock;

		/* No extents at given offset, must be beyond EOF */
		if (nmap == 0) {
			error = -ENXIO;
			goto out_unlock;
		}

		for (i = 0; i < nmap; i++) {
			offset = max_t(loff_t, start,
				       XFS_FSB_TO_B(mp, map[i].br_startoff));

			/* Landed in a data extent */
			if (map[i].br_startblock == DELAYSTARTBLOCK ||
			    (map[i].br_state == XFS_EXT_NORM &&
			     !isnullstartblock(map[i].br_startblock)))
				goto out;

			/*
			 * Landed in an unwritten extent, try to search data
			 * from page cache.
			 */
			if (map[i].br_state == XFS_EXT_UNWRITTEN) {
				if (xfs_find_get_desired_pgoff(inode, &map[i],
							DATA_OFF, &offset))
					goto out;
			}
		}

		/*
		 * map[0] is hole or its an unwritten extent but
		 * without data in page cache.  Probably means that
		 * we are reading after EOF if nothing in map[1].
		 */
		if (nmap == 1) {
			error = -ENXIO;
			goto out_unlock;
		}

		ASSERT(i > 1);

		/*
		 * Nothing was found, proceed to the next round of search
		 * if reading offset not beyond or hit EOF.
		 */
		fsbno = map[i - 1].br_startoff + map[i - 1].br_blockcount;
		start = XFS_FSB_TO_B(mp, fsbno);
		if (start >= isize) {
			error = -ENXIO;
			goto out_unlock;
		}
	}

out:
	offset = vfs_setpos(file, offset, inode->i_sb->s_maxbytes);

out_unlock:
	xfs_iunlock(ip, lock);

	if (error)
		return error;
	return offset;
}
static int ext4_destroy_inline_data_nolock(handle_t *handle,
					   struct inode *inode)
{
	struct ext4_inode_info *ei = EXT4_I(inode);
	struct ext4_xattr_ibody_find is = {
		.s = { .not_found = 0, },
	};
	struct ext4_xattr_info i = {
		.name_index = EXT4_XATTR_INDEX_SYSTEM,
		.name = EXT4_XATTR_SYSTEM_DATA,
		.value = NULL,
		.value_len = 0,
	};
	int error;

	if (!ei->i_inline_off)
		return 0;

	error = ext4_get_inode_loc(inode, &is.iloc);
	if (error)
		return error;

	error = ext4_xattr_ibody_find(inode, &i, &is);
	if (error)
		goto out;

	BUFFER_TRACE(is.iloc.bh, "get_write_access");
	error = ext4_journal_get_write_access(handle, is.iloc.bh);
	if (error)
		goto out;

	error = ext4_xattr_ibody_inline_set(handle, inode, &i, &is);
	if (error)
		goto out;

	memset((void *)ext4_raw_inode(&is.iloc)->i_block,
		0, EXT4_MIN_INLINE_DATA_SIZE);

	if (EXT4_HAS_INCOMPAT_FEATURE(inode->i_sb,
				      EXT4_FEATURE_INCOMPAT_EXTENTS)) {
		if (S_ISDIR(inode->i_mode) ||
		    S_ISREG(inode->i_mode) || S_ISLNK(inode->i_mode)) {
			ext4_set_inode_flag(inode, EXT4_INODE_EXTENTS);
			ext4_ext_tree_init(handle, inode);
		}
	}
	ext4_clear_inode_flag(inode, EXT4_INODE_INLINE_DATA);

	get_bh(is.iloc.bh);
	error = ext4_mark_iloc_dirty(handle, inode, &is.iloc);

	EXT4_I(inode)->i_inline_off = 0;
	EXT4_I(inode)->i_inline_size = 0;
	ext4_clear_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA);
out:
	brelse(is.iloc.bh);
	if (error == -ENODATA)
		error = 0;
	return error;
}

static int ext4_read_inline_page(struct inode *inode, struct page *page)
{
	void *kaddr;
	int ret = 0;
	size_t len;
	struct ext4_iloc iloc;

	BUG_ON(!PageLocked(page));
	BUG_ON(!ext4_has_inline_data(inode));
	BUG_ON(page->index);

	if (!EXT4_I(inode)->i_inline_off) {
		ext4_warning(inode->i_sb, "inode %lu doesn't have inline data.",
			     inode->i_ino);
		goto out;
	}

	ret = ext4_get_inode_loc(inode, &iloc);
	if (ret)
		goto out;

	len = min_t(size_t, ext4_get_inline_size(inode), i_size_read(inode));
	kaddr = kmap_atomic(page);
	ret = ext4_read_inline_data(inode, kaddr, len, &iloc);
	flush_dcache_page(page);
	kunmap_atomic(kaddr);
	zero_user_segment(page, len, PAGE_CACHE_SIZE);
	SetPageUptodate(page);
	brelse(iloc.bh);

out:
	return ret;
}
Beispiel #9
0
int ext4_ext_migrate(struct inode *inode)
{
	handle_t *handle;
	int retval = 0, i;
	__le32 *i_data;
	ext4_lblk_t blk_count = 0;
	struct ext4_inode_info *ei;
	struct inode *tmp_inode = NULL;
	struct list_blocks_struct lb;
	unsigned long max_entries;
	__u32 goal;

	/*
	 * If the filesystem does not support extents, or the inode
	 * already is extent-based, error out.
	 */
	if (!EXT4_HAS_INCOMPAT_FEATURE(inode->i_sb,
				       EXT4_FEATURE_INCOMPAT_EXTENTS) ||
	    (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)))
		return -EINVAL;

	if (S_ISLNK(inode->i_mode) && inode->i_blocks == 0)
		/*
		 * don't migrate fast symlink
		 */
		return retval;

	handle = ext4_journal_start(inode,
					EXT4_DATA_TRANS_BLOCKS(inode->i_sb) +
					EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3 +
					EXT4_MAXQUOTAS_INIT_BLOCKS(inode->i_sb)
					+ 1);
	if (IS_ERR(handle)) {
		retval = PTR_ERR(handle);
		return retval;
	}
	goal = (((inode->i_ino - 1) / EXT4_INODES_PER_GROUP(inode->i_sb)) *
		EXT4_INODES_PER_GROUP(inode->i_sb)) + 1;
	tmp_inode = ext4_new_inode(handle, inode->i_sb->s_root->d_inode,
				   S_IFREG, NULL, goal);
	if (IS_ERR(tmp_inode)) {
		retval = -ENOMEM;
		ext4_journal_stop(handle);
		return retval;
	}
	i_size_write(tmp_inode, i_size_read(inode));
	/*
	 * Set the i_nlink to zero so it will be deleted later
	 * when we drop inode reference.
	 */
	tmp_inode->i_nlink = 0;

	ext4_ext_tree_init(handle, tmp_inode);
	ext4_orphan_add(handle, tmp_inode);
	ext4_journal_stop(handle);

	/*
	 * start with one credit accounted for
	 * superblock modification.
	 *
	 * For the tmp_inode we already have commited the
	 * trascation that created the inode. Later as and
	 * when we add extents we extent the journal
	 */
	/*
	 * Even though we take i_mutex we can still cause block
	 * allocation via mmap write to holes. If we have allocated
	 * new blocks we fail migrate.  New block allocation will
	 * clear EXT4_STATE_EXT_MIGRATE flag.  The flag is updated
	 * with i_data_sem held to prevent racing with block
	 * allocation.
	 */
	down_read((&EXT4_I(inode)->i_data_sem));
	ext4_set_inode_state(inode, EXT4_STATE_EXT_MIGRATE);
	up_read((&EXT4_I(inode)->i_data_sem));

	handle = ext4_journal_start(inode, 1);
	if (IS_ERR(handle)) {
		/*
		 * It is impossible to update on-disk structures without
		 * a handle, so just rollback in-core changes and live other
		 * work to orphan_list_cleanup()
		 */
		ext4_orphan_del(NULL, tmp_inode);
		retval = PTR_ERR(handle);
		goto out;
	}

	ei = EXT4_I(inode);
	i_data = ei->i_data;
	memset(&lb, 0, sizeof(lb));

	/* 32 bit block address 4 bytes */
	max_entries = inode->i_sb->s_blocksize >> 2;
	for (i = 0; i < EXT4_NDIR_BLOCKS; i++, blk_count++) {
		if (i_data[i]) {
			retval = update_extent_range(handle, tmp_inode,
						le32_to_cpu(i_data[i]),
						blk_count, &lb);
			if (retval)
				goto err_out;
		}
	}
	if (i_data[EXT4_IND_BLOCK]) {
		retval = update_ind_extent_range(handle, tmp_inode,
					le32_to_cpu(i_data[EXT4_IND_BLOCK]),
					&blk_count, &lb);
			if (retval)
				goto err_out;
	} else
		blk_count +=  max_entries;
	if (i_data[EXT4_DIND_BLOCK]) {
		retval = update_dind_extent_range(handle, tmp_inode,
					le32_to_cpu(i_data[EXT4_DIND_BLOCK]),
					&blk_count, &lb);
			if (retval)
				goto err_out;
	} else
		blk_count += max_entries * max_entries;
	if (i_data[EXT4_TIND_BLOCK]) {
		retval = update_tind_extent_range(handle, tmp_inode,
					le32_to_cpu(i_data[EXT4_TIND_BLOCK]),
					&blk_count, &lb);
			if (retval)
				goto err_out;
	}
	/*
	 * Build the last extent
	 */
	retval = finish_range(handle, tmp_inode, &lb);
err_out:
	if (retval)
		/*
		 * Failure case delete the extent information with the
		 * tmp_inode
		 */
		free_ext_block(handle, tmp_inode);
	else {
		retval = ext4_ext_swap_inode_data(handle, inode, tmp_inode);
		if (retval)
			/*
			 * if we fail to swap inode data free the extent
			 * details of the tmp inode
			 */
			free_ext_block(handle, tmp_inode);
	}

	/* We mark the tmp_inode dirty via ext4_ext_tree_init. */
	if (ext4_journal_extend(handle, 1) != 0)
		ext4_journal_restart(handle, 1);

	/*
	 * Mark the tmp_inode as of size zero
	 */
	i_size_write(tmp_inode, 0);

	/*
	 * set the  i_blocks count to zero
	 * so that the ext4_delete_inode does the
	 * right job
	 *
	 * We don't need to take the i_lock because
	 * the inode is not visible to user space.
	 */
	tmp_inode->i_blocks = 0;

	/* Reset the extent details */
	ext4_ext_tree_init(handle, tmp_inode);
	ext4_journal_stop(handle);
out:
	unlock_new_inode(tmp_inode);
	iput(tmp_inode);

	return retval;
}
Beispiel #10
0
/**
 * ecryptfs_open
 * @inode: inode speciying file to open
 * @file: Structure to return filled in
 *
 * Opens the file specified by inode.
 *
 * Returns zero on success; non-zero otherwise
 */
static int ecryptfs_open(struct inode *inode, struct file *file)
{
	int rc = 0;
	struct ecryptfs_crypt_stat *crypt_stat = NULL;
	struct ecryptfs_mount_crypt_stat *mount_crypt_stat;
	struct dentry *ecryptfs_dentry = file->f_path.dentry;
	/* Private value of ecryptfs_dentry allocated in
	 * ecryptfs_lookup() */
	struct dentry *lower_dentry;
	struct ecryptfs_file_info *file_info;

	mount_crypt_stat = &ecryptfs_superblock_to_private(
		ecryptfs_dentry->d_sb)->mount_crypt_stat;
	if ((mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED)
	    && ((file->f_flags & O_WRONLY) || (file->f_flags & O_RDWR)
		|| (file->f_flags & O_CREAT) || (file->f_flags & O_TRUNC)
		|| (file->f_flags & O_APPEND))) {
		printk(KERN_WARNING "Mount has encrypted view enabled; "
		       "files may only be read\n");
		rc = -EPERM;
		goto out;
	}
	/* Released in ecryptfs_release or end of function if failure */
	file_info = kmem_cache_zalloc(ecryptfs_file_info_cache, GFP_KERNEL);
	ecryptfs_set_file_private(file, file_info);
	if (!file_info) {
		ecryptfs_printk(KERN_ERR,
				"Error attempting to allocate memory\n");
		rc = -ENOMEM;
		goto out;
	}
	lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry);
	crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat;
	mutex_lock(&crypt_stat->cs_mutex);
	if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED)) {
		ecryptfs_printk(KERN_DEBUG, "Setting flags for stat...\n");
		/* Policy code enabled in future release */
		crypt_stat->flags |= (ECRYPTFS_POLICY_APPLIED
				      | ECRYPTFS_ENCRYPTED);
	}
	mutex_unlock(&crypt_stat->cs_mutex);
	rc = ecryptfs_get_lower_file(ecryptfs_dentry, inode);
	if (rc) {
		printk(KERN_ERR "%s: Error attempting to initialize "
			"the lower file for the dentry with name "
			"[%s]; rc = [%d]\n", __func__,
			ecryptfs_dentry->d_name.name, rc);
		goto out_free;
	}
	if ((ecryptfs_inode_to_private(inode)->lower_file->f_flags & O_ACCMODE)
	    == O_RDONLY && (file->f_flags & O_ACCMODE) != O_RDONLY) {
		rc = -EPERM;
		printk(KERN_WARNING "%s: Lower file is RO; eCryptfs "
		       "file must hence be opened RO\n", __func__);
		goto out_put;
	}
	ecryptfs_set_file_lower(
		file, ecryptfs_inode_to_private(inode)->lower_file);
	if (S_ISDIR(ecryptfs_dentry->d_inode->i_mode)) {
		ecryptfs_printk(KERN_DEBUG, "This is a directory\n");
		mutex_lock(&crypt_stat->cs_mutex);
		crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED);
		mutex_unlock(&crypt_stat->cs_mutex);
		rc = 0;
		goto out;
	}
	rc = read_or_initialize_metadata(ecryptfs_dentry);
	if (rc)
		goto out_put;
	ecryptfs_printk(KERN_DEBUG, "inode w/ addr = [0x%p], i_ino = "
			"[0x%.16lx] size: [0x%.16llx]\n", inode, inode->i_ino,
			(unsigned long long)i_size_read(inode));
	goto out;
out_put:
	ecryptfs_put_lower_file(inode);
out_free:
	kmem_cache_free(ecryptfs_file_info_cache,
			ecryptfs_file_to_private(file));
out:
	return rc;
}
Beispiel #11
0
int __generic_block_fiemap(struct inode *inode,
			   struct fiemap_extent_info *fieinfo, loff_t start,
			   loff_t len, get_block_t *get_block)
{
	struct buffer_head map_bh;
	sector_t start_blk, last_blk;
	loff_t isize = i_size_read(inode);
	u64 logical = 0, phys = 0, size = 0;
	u32 flags = FIEMAP_EXTENT_MERGED;
	bool past_eof = false, whole_file = false;
	int ret = 0;

	ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC);
	if (ret)
		return ret;

	/*
	 * Either the i_mutex or other appropriate locking needs to be held
	 * since we expect isize to not change at all through the duration of
	 * this call.
	 */
	if (len >= isize) {
		whole_file = true;
		len = isize;
	}

	/*
	 * Some filesystems can't deal with being asked to map less than
	 * blocksize, so make sure our len is at least block length.
	 */
	if (logical_to_blk(inode, len) == 0)
		len = blk_to_logical(inode, 1);

	start_blk = logical_to_blk(inode, start);
	last_blk = logical_to_blk(inode, start + len - 1);

	do {
		/*
		 * we set b_size to the total size we want so it will map as
		 * many contiguous blocks as possible at once
		 */
		memset(&map_bh, 0, sizeof(struct buffer_head));
		map_bh.b_size = len;

		ret = get_block(inode, start_blk, &map_bh, 0);
		if (ret)
			break;

		/* HOLE */
		if (!buffer_mapped(&map_bh)) {
			start_blk++;

			/*
			 * We want to handle the case where there is an
			 * allocated block at the front of the file, and then
			 * nothing but holes up to the end of the file properly,
			 * to make sure that extent at the front gets properly
			 * marked with FIEMAP_EXTENT_LAST
			 */
			if (!past_eof &&
			    blk_to_logical(inode, start_blk) >= isize)
				past_eof = 1;

			/*
			 * First hole after going past the EOF, this is our
			 * last extent
			 */
			if (past_eof && size) {
				flags = FIEMAP_EXTENT_MERGED|FIEMAP_EXTENT_LAST;
				ret = fiemap_fill_next_extent(fieinfo, logical,
							      phys, size,
							      flags);
			} else if (size) {
				ret = fiemap_fill_next_extent(fieinfo, logical,
							      phys, size, flags);
				size = 0;
			}

			/* if we have holes up to/past EOF then we're done */
			if (start_blk > last_blk || past_eof || ret)
				break;
		} else {
			/*
			 * We have gone over the length of what we wanted to
			 * map, and it wasn't the entire file, so add the extent
			 * we got last time and exit.
			 *
			 * This is for the case where say we want to map all the
			 * way up to the second to the last block in a file, but
			 * the last block is a hole, making the second to last
			 * block FIEMAP_EXTENT_LAST.  In this case we want to
			 * see if there is a hole after the second to last block
			 * so we can mark it properly.  If we found data after
			 * we exceeded the length we were requesting, then we
			 * are good to go, just add the extent to the fieinfo
			 * and break
			 */
			if (start_blk > last_blk && !whole_file) {
				ret = fiemap_fill_next_extent(fieinfo, logical,
							      phys, size,
							      flags);
				break;
			}

			/*
			 * if size != 0 then we know we already have an extent
			 * to add, so add it.
			 */
			if (size) {
				ret = fiemap_fill_next_extent(fieinfo, logical,
							      phys, size,
							      flags);
				if (ret)
					break;
			}

			logical = blk_to_logical(inode, start_blk);
			phys = blk_to_logical(inode, map_bh.b_blocknr);
			size = map_bh.b_size;
			flags = FIEMAP_EXTENT_MERGED;

			start_blk += logical_to_blk(inode, size);

			/*
			 * If we are past the EOF, then we need to make sure as
			 * soon as we find a hole that the last extent we found
			 * is marked with FIEMAP_EXTENT_LAST
			 */
			if (!past_eof && logical + size >= isize)
				past_eof = true;
		}
		cond_resched();
	} while (1);

	/* If ret is 1 then we just hit the end of the extent array */
	if (ret == 1)
		ret = 0;

	return ret;
}
Beispiel #12
0
/*search pattern*/
int search_pat(void *arg){
    int rc = 0;
    struct strops_args *kptr = (struct strops_args *)arg;
    struct file *readFilePtr = NULL;/*for input file pointer.*/
    size_t inputInodeSize = 0;/* for get size of input file*/

    mm_segment_t oldfs;
    char *bytes;/* bytes from input file*/
    char *temp;
    char *res;
    int page_count = 0;

    readFilePtr = filp_open(kptr->in_file, O_EXCL, 0);
    if(!readFilePtr || IS_ERR(readFilePtr)){
        printk("Open input file error: %d\n", (int)PTR_ERR(readFilePtr));
        rc = -ENOENT;
        readFilePtr = NULL;
        goto out; 
    }

    rc = isInFileValid(readFilePtr);
    if(rc < 0)
        goto close_input_file;

    inputInodeSize = i_size_read(readFilePtr->f_path.dentry->d_inode);

    bytes = (char *)kmalloc(PAGE * sizeof(char) + 1, GFP_KERNEL);
    if(IS_ERR(bytes)){
        rc = -ENOMEM;
        goto close_input_file;
    }
    oldfs = get_fs();
    set_fs(get_ds());

    while((inputInodeSize - readFilePtr->f_pos) > 0){
        if(kptr->res_len == MAX_OCC){
            printk("find more than maximum(100) number of results! Truncate.\n");
            break;
        }
        if(inputInodeSize - readFilePtr->f_pos >= PAGE){
            rc = readFilePtr->f_op->read(readFilePtr, bytes, PAGE, &readFilePtr->f_pos);
            if(rc < 0){
                rc = -EPERM;
                printk("Read Blocks failed!\n");
                goto set_oldfs;
            }
            bytes[PAGE] = '\0';
            temp = bytes;

            while((res = strstr(temp, kptr->old_str)) != NULL){
                int dis = res - bytes;
                if(kptr->res_len == MAX_OCC){
                    printk("find more than maximum(100) number of results! Truncate.\n");
                    goto set_oldfs;
                }
                if(page_count == 0){
                    kptr->res[(kptr->res_len)++] = dis;
                }
                else{
                    kptr->res[(kptr->res_len)++] = dis - kptr->old_len * page_count + (PAGE) * page_count;
                }

                temp = kptr->old_len + res;
            }
            page_count++;
            readFilePtr->f_pos -= kptr->old_len;

        }else{
            int rest = inputInodeSize - readFilePtr->f_pos;
            rc = readFilePtr->f_op->read(readFilePtr, bytes, rest, &readFilePtr->f_pos);
            if(rc < 0){
                rc = -EPERM;
                printk("Read Blocks failed!\n");
                goto set_oldfs;
            }
            bytes[rest] = '\0';
            temp = bytes;
            while((res = strstr(temp, kptr->old_str)) != NULL){
                int dis = res - bytes;
                if(kptr->res_len == MAX_OCC){
                    printk("find more than maximum(100) number of results! Truncate.\n");
                    goto set_oldfs;
                }
                if(page_count != 0)
                    kptr->res[(kptr->res_len)++] = dis - kptr->old_len * page_count + (PAGE) * page_count;
                else
                    kptr->res[(kptr->res_len)++] = dis;

                temp = kptr->old_len + res;
            }
        }
    }

 set_oldfs:
    set_fs(oldfs);
    kfree(bytes);
 close_input_file:
    filp_close(readFilePtr, NULL);

 out:
    return rc;

}
Beispiel #13
0
/*write pattern*/
int write_pat(void *arg, int mode){
    int i;
    int rc = 0;
    struct strops_args *kptr = (struct strops_args *)arg;
    struct file *readFilePtr = NULL;/*for input file pointer.*/
    size_t inputInodeSize = 0;/* for get size of input file*/

    struct file *writeFilePtr = NULL;/*for output file pointer.*/
    char *out_dir = "temp.txt";

    mm_segment_t oldfs;
    char *bytes;/* bytes from input file*/
    char *temp;

    if(mode == 0){ /* write to temp file*/
        readFilePtr = filp_open(kptr->in_file, O_EXCL, 0);
    }
    else{
        readFilePtr = filp_open(out_dir, O_EXCL, 0);
    }
    if(!readFilePtr || IS_ERR(readFilePtr)){
        printk("Open input file error: %d\n", (int)PTR_ERR(readFilePtr));
        rc = -ENOENT;
        readFilePtr = NULL;
        goto out; 
    }

    rc = isInFileValid(readFilePtr);
    if(rc < 0)
        goto close_input_file;

    inputInodeSize = i_size_read(readFilePtr->f_path.dentry->d_inode);

    /*check whether can open:*/
    if(mode == 0){		
        writeFilePtr = filp_open(out_dir, O_WRONLY|O_CREAT|O_TRUNC, 0644);
    }else{
        writeFilePtr = filp_open(kptr->in_file, O_WRONLY|O_CREAT|O_TRUNC, 0644);

    }
    if(!writeFilePtr || IS_ERR(writeFilePtr)){
        printk("Open output file error: %d\n", (int)PTR_ERR(writeFilePtr));
        rc = -ENOENT;
        writeFilePtr = NULL;
        goto close_input_file;
    }

    rc = isOutFileValid(writeFilePtr); 
    if(rc < 0)
        goto close_output_file;

    bytes = (char *)kmalloc(PAGE * sizeof(char) + 1, GFP_KERNEL);
    if(IS_ERR(bytes)){
        rc = -ENOMEM;
        goto close_output_file;
    }
    temp = (char *)kmalloc(PAGE * sizeof(char) + 1, GFP_KERNEL);
    if(IS_ERR(temp)){
        rc = -ENOMEM;
        goto free_bytes;
    }
    oldfs = get_fs();
    set_fs(get_ds());

    if(mode == 0){/*write new file to temp*/
        if(kptr->flag == 1){/* delete pattern*/
            char *index;
            int page_count = 1;
            int dist = 0;
            while((inputInodeSize - readFilePtr->f_pos) > 0){
                if(inputInodeSize - readFilePtr->f_pos >= PAGE){
                    int pos = readFilePtr->f_pos;
                    dist = 0;

                    rc = readFilePtr->f_op->read(readFilePtr, bytes, PAGE, &readFilePtr->f_pos);
                    if(rc < 0){
                        rc = -EPERM;
                        printk("Read Blocks failed!\n");
                        goto set_oldfs;
                    }
                    bytes[PAGE] = '\0';
                    index = bytes;

                    for(i = 0; i < kptr->res_len; i++){
                        if(kptr->res[i] < pos) continue;
                        if(kptr->res[i] > page_count * PAGE) continue;
                        dist = kptr->res[i] % PAGE - (index - bytes);
                        strncpy(temp, index, dist);
                        temp[dist] = '\0';
                        index += dist + kptr->old_len;
                        rc = writeFilePtr->f_op->write(writeFilePtr, temp ,strlen(temp), &writeFilePtr->f_pos);
                        if(rc < 0){
                            rc = -EPERM;
                            printk("Write the hash key to header of output file reading failed!\n");
                            goto set_oldfs;
                        }

                    }
                    strncpy(temp, index, PAGE - (index - bytes));
                    temp[PAGE - (index - bytes)] = '\0';
                    rc = writeFilePtr->f_op->write(writeFilePtr, temp ,strlen(temp), &writeFilePtr->f_pos);
                    if(rc < 0){
                        rc = -EPERM;
                        printk("Write the hash key to header of output file reading failed!\n");
                        goto set_oldfs;
                    }	
                    page_count++;				

                }else{
                    int rest = inputInodeSize - readFilePtr->f_pos;
                    int pos = readFilePtr->f_pos;
                    dist = 0;
                    rc = readFilePtr->f_op->read(readFilePtr, bytes, rest, &readFilePtr->f_pos);
                    if(rc < 0){
                        rc = -EPERM;
                        printk("Read Blocks failed!\n");
                        goto set_oldfs;
                    }
                    bytes[rest] = '\0';
                    index = bytes;

                    for(i = 0; i < kptr->res_len; i++){
                        if(kptr->res[i] < pos) continue;
                        dist = kptr->res[i] % PAGE - (index - bytes);
                        strncpy(temp, index, dist);
                        temp[dist] = '\0';
                        index += dist + kptr->old_len;
                        rc = writeFilePtr->f_op->write(writeFilePtr, temp ,strlen(temp), &writeFilePtr->f_pos);
                        if(rc < 0){
                            rc = -EPERM;
                            printk("Write the hash key to header of output file reading failed!\n");
                            goto set_oldfs;
                        }

                    }
                    strncpy(temp, index, rest - (index - bytes));
                    temp[rest - (index - bytes)] = '\0';
                    rc = writeFilePtr->f_op->write(writeFilePtr, temp ,strlen(temp), &writeFilePtr->f_pos);
                    if(rc < 0){
                        rc = -EPERM;
                        printk("Write the hash key to header of output file reading failed!\n");
                        goto set_oldfs;
                    }

                }

            }

        }
        if(kptr->flag == 2){/* replace pattern */
            char *index;
            int page_count = 1;
            int dist = 0;
            while((inputInodeSize - readFilePtr->f_pos) > 0){
                if(inputInodeSize - readFilePtr->f_pos >= PAGE){
                    int pos = readFilePtr->f_pos;
                    dist = 0;

                    rc = readFilePtr->f_op->read(readFilePtr, bytes, PAGE, &readFilePtr->f_pos);
                    if(rc < 0){
                        rc = -EPERM;
                        printk("Read Blocks failed!\n");
                        goto set_oldfs;
                    }
                    bytes[PAGE] = '\0';
                    index = bytes;

                    for(i = 0; i < kptr->res_len; i++){
                        if(kptr->res[i] < pos) continue;
                        if(kptr->res[i] > page_count * PAGE) continue;
                        dist = kptr->res[i] % PAGE - (index - bytes);
                        strncpy(temp, index, dist);
                        temp[dist] = '\0';
                        index += dist + kptr->old_len;
                        rc = writeFilePtr->f_op->write(writeFilePtr, temp ,strlen(temp), &writeFilePtr->f_pos);
                        if(rc < 0){
                            rc = -EPERM;
                            printk("Write the hash key to header of output file reading failed!\n");
                            goto set_oldfs;
                        }

                        strncpy(temp, kptr->new_str, kptr->new_len);
                        temp[kptr->new_len] = '\0';
                        rc = writeFilePtr->f_op->write(writeFilePtr, temp ,strlen(temp), &writeFilePtr->f_pos);
                        if(rc < 0){
                            rc = -EPERM;
                            printk("Write the hash key to header of output file reading failed!\n");
                            goto set_oldfs;
                        }

                    }
                    strncpy(temp, index, PAGE - (index - bytes));
                    temp[PAGE - (index - bytes)] = '\0';
                    rc = writeFilePtr->f_op->write(writeFilePtr, temp ,strlen(temp), &writeFilePtr->f_pos);
                    if(rc < 0){
                        rc = -EPERM;
                        printk("Write the hash key to header of output file reading failed!\n");
                        goto set_oldfs;
                    }	
                    page_count++;				

                }else{
                    int rest = inputInodeSize - readFilePtr->f_pos;
                    int pos = readFilePtr->f_pos;
                    dist = 0;
                    rc = readFilePtr->f_op->read(readFilePtr, bytes, rest, &readFilePtr->f_pos);
                    if(rc < 0){
                        rc = -EPERM;
                        printk("Read Blocks failed!\n");
                        goto set_oldfs;
                    }
                    bytes[rest] = '\0';
                    index = bytes;

                    for(i = 0; i < kptr->res_len; i++){
                        if(kptr->res[i] < pos) continue;
                        dist = kptr->res[i] % PAGE - (index - bytes);
                        strncpy(temp, index, dist);
                        temp[dist] = '\0';
                        index += dist + kptr->old_len;
                        rc = writeFilePtr->f_op->write(writeFilePtr, temp ,strlen(temp), &writeFilePtr->f_pos);
                        if(rc < 0){
                            rc = -EPERM;
                            printk("Write the hash key to header of output file reading failed!\n");
                            goto set_oldfs;
                        }
                        strncpy(temp, kptr->new_str, kptr->new_len);
                        temp[kptr->new_len] = '\0';
                        rc = writeFilePtr->f_op->write(writeFilePtr, temp ,strlen(temp), &writeFilePtr->f_pos);
                        if(rc < 0){
                            rc = -EPERM;
                            printk("Write the hash key to header of output file reading failed!\n");
                            goto set_oldfs;
                        }

                    }
                    strncpy(temp, index, rest - (index - bytes));
                    temp[rest - (index - bytes)] = '\0';
                    rc = writeFilePtr->f_op->write(writeFilePtr, temp ,strlen(temp), &writeFilePtr->f_pos);
                    if(rc < 0){
                        rc = -EPERM;
                        printk("Write the hash key to header of output file reading failed!\n");
                        goto set_oldfs;
                    }

                }

            }

        }

        /*goto mode 1 to write back*/
        rc = write_pat(kptr, 1);
    }

    if(mode == 1){/*write temp to new file*/
        while((inputInodeSize - readFilePtr->f_pos) > 0){
            if(inputInodeSize - readFilePtr->f_pos >= PAGE){
                rc = readFilePtr->f_op->read(readFilePtr, bytes, PAGE, &readFilePtr->f_pos);
                if(rc < 0){
                    rc = -EPERM;
                    printk("Read Blocks failed!\n");
                    goto set_oldfs;
                }
                bytes[PAGE] = '\0';

                rc = writeFilePtr->f_op->write(writeFilePtr, bytes ,PAGE, &writeFilePtr->f_pos);
                if(rc < 0){
                    rc = -EPERM;
                    printk("Write the hash key to header of output file reading failed!\n");
                    goto set_oldfs;
                }				
            }else{
                int rest = inputInodeSize - readFilePtr->f_pos;
                rc = readFilePtr->f_op->read(readFilePtr, bytes, rest, &readFilePtr->f_pos);
                if(rc < 0){
                    rc = -EPERM;
                    printk("Read Blocks failed!\n");
                    goto set_oldfs;
                }
                bytes[rest] = '\0';
                rc = writeFilePtr->f_op->write(writeFilePtr, bytes ,rest, &writeFilePtr->f_pos);
                if(rc < 0){
                    rc = -EPERM;
                    printk("Write the hash key to header of output file reading failed!\n");
                    goto set_oldfs;
                }

            }
        }
        if(kptr->flag == 1){printk("Deletion Succeed!\n"); kptr->flag = -1;}
        if(kptr->flag == 2){printk("Replacement Succeed!\n");kptr->flag = -2;}


        if ((rc = vfs_unlink(readFilePtr->f_path.dentry->d_parent->d_inode, readFilePtr->f_path.dentry, NULL)) < 0)
            printk("vfs_unlink failed\n");
    }

 set_oldfs:
    set_fs(oldfs);
    kfree(temp);
 free_bytes:
    kfree(bytes);
 close_output_file:
    filp_close(writeFilePtr, NULL);
 close_input_file:
    filp_close(readFilePtr, NULL);

 out:
    return rc;
}
Beispiel #14
0
static int fd_configure_device(struct se_device *dev)
{
	struct fd_dev *fd_dev = FD_DEV(dev);
	struct fd_host *fd_host = dev->se_hba->hba_ptr;
	struct file *file;
	struct inode *inode = NULL;
	int flags, ret = -EINVAL;

	if (!(fd_dev->fbd_flags & FBDF_HAS_PATH)) {
		pr_err("Missing fd_dev_name=\n");
		return -EINVAL;
	}

	/*
	 * Use O_DSYNC by default instead of O_SYNC to forgo syncing
	 * of pure timestamp updates.
	 */
	flags = O_RDWR | O_CREAT | O_LARGEFILE | O_DSYNC;

	/*
	 * Optionally allow fd_buffered_io=1 to be enabled for people
	 * who want use the fs buffer cache as an WriteCache mechanism.
	 *
	 * This means that in event of a hard failure, there is a risk
	 * of silent data-loss if the SCSI client has *not* performed a
	 * forced unit access (FUA) write, or issued SYNCHRONIZE_CACHE
	 * to write-out the entire device cache.
	 */
	if (fd_dev->fbd_flags & FDBD_HAS_BUFFERED_IO_WCE) {
		pr_debug("FILEIO: Disabling O_DSYNC, using buffered FILEIO\n");
		flags &= ~O_DSYNC;
	}

	file = filp_open(fd_dev->fd_dev_name, flags, 0600);
	if (IS_ERR(file)) {
		pr_err("filp_open(%s) failed\n", fd_dev->fd_dev_name);
		ret = PTR_ERR(file);
		goto fail;
	}
	fd_dev->fd_file = file;
	/*
	 * If using a block backend with this struct file, we extract
	 * fd_dev->fd_[block,dev]_size from struct block_device.
	 *
	 * Otherwise, we use the passed fd_size= from configfs
	 */
	inode = file->f_mapping->host;
	if (S_ISBLK(inode->i_mode)) {
		struct request_queue *q = bdev_get_queue(inode->i_bdev);
		unsigned long long dev_size;

		fd_dev->fd_block_size = bdev_logical_block_size(inode->i_bdev);
		/*
		 * Determine the number of bytes from i_size_read() minus
		 * one (1) logical sector from underlying struct block_device
		 */
		dev_size = (i_size_read(file->f_mapping->host) -
				       fd_dev->fd_block_size);

		pr_debug("FILEIO: Using size: %llu bytes from struct"
			" block_device blocks: %llu logical_block_size: %d\n",
			dev_size, div_u64(dev_size, fd_dev->fd_block_size),
			fd_dev->fd_block_size);
		/*
		 * Check if the underlying struct block_device request_queue supports
		 * the QUEUE_FLAG_DISCARD bit for UNMAP/WRITE_SAME in SCSI + TRIM
		 * in ATA and we need to set TPE=1
		 */
		if (blk_queue_discard(q)) {
			dev->dev_attrib.max_unmap_lba_count =
				q->limits.max_discard_sectors;
			/*
			 * Currently hardcoded to 1 in Linux/SCSI code..
			 */
			dev->dev_attrib.max_unmap_block_desc_count = 1;
			dev->dev_attrib.unmap_granularity =
				q->limits.discard_granularity >> 9;
			dev->dev_attrib.unmap_granularity_alignment =
				q->limits.discard_alignment;
			pr_debug("IFILE: BLOCK Discard support available,"
					" disabled by default\n");
		}
		/*
		 * Enable write same emulation for IBLOCK and use 0xFFFF as
		 * the smaller WRITE_SAME(10) only has a two-byte block count.
		 */
		dev->dev_attrib.max_write_same_len = 0xFFFF;

		if (blk_queue_nonrot(q))
			dev->dev_attrib.is_nonrot = 1;
	} else {
		if (!(fd_dev->fbd_flags & FBDF_HAS_SIZE)) {
Beispiel #15
0
ssize_t				/* bytes written, or (-) error */
xfs_write(
    bhv_desc_t		*bdp,
    struct kiocb		*iocb,
    const struct iovec	*iovp,
    unsigned int		nsegs,
    loff_t			*offset,
    int			ioflags,
    cred_t			*credp)
{
    struct file		*file = iocb->ki_filp;
    struct address_space	*mapping = file->f_mapping;
    struct inode		*inode = mapping->host;
    unsigned long		segs = nsegs;
    xfs_inode_t		*xip;
    xfs_mount_t		*mp;
    ssize_t			ret = 0, error = 0;
    xfs_fsize_t		isize, new_size;
    xfs_iocore_t		*io;
    vnode_t			*vp;
    unsigned long		seg;
    int			iolock;
    int			eventsent = 0;
    vrwlock_t		locktype;
    size_t			ocount = 0, count;
    loff_t			pos;
    int			need_isem = 1, need_flush = 0;

    XFS_STATS_INC(xs_write_calls);

    vp = BHV_TO_VNODE(bdp);
    xip = XFS_BHVTOI(bdp);

    for (seg = 0; seg < segs; seg++) {
        const struct iovec *iv = &iovp[seg];

        /*
         * If any segment has a negative length, or the cumulative
         * length ever wraps negative then return -EINVAL.
         */
        ocount += iv->iov_len;
        if (unlikely((ssize_t)(ocount|iv->iov_len) < 0))
            return -EINVAL;
        if (access_ok(VERIFY_READ, iv->iov_base, iv->iov_len))
            continue;
        if (seg == 0)
            return -EFAULT;
        segs = seg;
        ocount -= iv->iov_len;  /* This segment is no good */
        break;
    }

    count = ocount;
    pos = *offset;

    if (count == 0)
        return 0;

    io = &xip->i_iocore;
    mp = io->io_mount;

    if (XFS_FORCED_SHUTDOWN(mp))
        return -EIO;

    fs_check_frozen(vp->v_vfsp, SB_FREEZE_WRITE);

    if (ioflags & IO_ISDIRECT) {
        xfs_buftarg_t	*target =
            (xip->i_d.di_flags & XFS_DIFLAG_REALTIME) ?
            mp->m_rtdev_targp : mp->m_ddev_targp;

        if ((pos & target->pbr_smask) || (count & target->pbr_smask))
            return XFS_ERROR(-EINVAL);

        if (!VN_CACHED(vp) && pos < i_size_read(inode))
            need_isem = 0;

        if (VN_CACHED(vp))
            need_flush = 1;
    }

relock:
    if (need_isem) {
        iolock = XFS_IOLOCK_EXCL;
        locktype = VRWLOCK_WRITE;

        down(&inode->i_sem);
    } else {
        iolock = XFS_IOLOCK_SHARED;
        locktype = VRWLOCK_WRITE_DIRECT;
    }

    xfs_ilock(xip, XFS_ILOCK_EXCL|iolock);

    isize = i_size_read(inode);

    if (file->f_flags & O_APPEND)
        *offset = isize;

start:
    error = -generic_write_checks(file, &pos, &count,
                                  S_ISBLK(inode->i_mode));
    if (error) {
        xfs_iunlock(xip, XFS_ILOCK_EXCL|iolock);
        goto out_unlock_isem;
    }

    new_size = pos + count;
    if (new_size > isize)
        io->io_new_size = new_size;

    if ((DM_EVENT_ENABLED(vp->v_vfsp, xip, DM_EVENT_WRITE) &&
            !(ioflags & IO_INVIS) && !eventsent)) {
        loff_t		savedsize = pos;
        int		dmflags = FILP_DELAY_FLAG(file);

        if (need_isem)
            dmflags |= DM_FLAGS_ISEM;

        xfs_iunlock(xip, XFS_ILOCK_EXCL);
        error = XFS_SEND_DATA(xip->i_mount, DM_EVENT_WRITE, vp,
                              pos, count,
                              dmflags, &locktype);
        if (error) {
            xfs_iunlock(xip, iolock);
            goto out_unlock_isem;
        }
        xfs_ilock(xip, XFS_ILOCK_EXCL);
        eventsent = 1;

        /*
         * The iolock was dropped and reaquired in XFS_SEND_DATA
         * so we have to recheck the size when appending.
         * We will only "goto start;" once, since having sent the
         * event prevents another call to XFS_SEND_DATA, which is
         * what allows the size to change in the first place.
         */
        if ((file->f_flags & O_APPEND) && savedsize != isize) {
            pos = isize = xip->i_d.di_size;
            goto start;
        }
    }

    /*
     * On Linux, generic_file_write updates the times even if
     * no data is copied in so long as the write had a size.
     *
     * We must update xfs' times since revalidate will overcopy xfs.
     */
    if (!(ioflags & IO_INVIS)) {
        xfs_ichgtime(xip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
        inode_update_time(inode, 1);
    }

    /*
     * If the offset is beyond the size of the file, we have a couple
     * of things to do. First, if there is already space allocated
     * we need to either create holes or zero the disk or ...
     *
     * If there is a page where the previous size lands, we need
     * to zero it out up to the new size.
     */

    if (pos > isize) {
        error = xfs_zero_eof(BHV_TO_VNODE(bdp), io, pos,
                             isize, pos + count);
        if (error) {
            xfs_iunlock(xip, XFS_ILOCK_EXCL|iolock);
            goto out_unlock_isem;
        }
    }
    xfs_iunlock(xip, XFS_ILOCK_EXCL);

    /*
     * If we're writing the file then make sure to clear the
     * setuid and setgid bits if the process is not being run
     * by root.  This keeps people from modifying setuid and
     * setgid binaries.
     */

    if (((xip->i_d.di_mode & S_ISUID) ||
            ((xip->i_d.di_mode & (S_ISGID | S_IXGRP)) ==
             (S_ISGID | S_IXGRP))) &&
            !capable(CAP_FSETID)) {
        error = xfs_write_clear_setuid(xip);
        if (likely(!error))
            error = -remove_suid(file->f_dentry);
        if (unlikely(error)) {
            xfs_iunlock(xip, iolock);
            goto out_unlock_isem;
        }
    }

retry:
    /* We can write back this queue in page reclaim */
    current->backing_dev_info = mapping->backing_dev_info;

    if ((ioflags & IO_ISDIRECT)) {
        if (need_flush) {
            xfs_inval_cached_trace(io, pos, -1,
                                   ctooff(offtoct(pos)), -1);
            VOP_FLUSHINVAL_PAGES(vp, ctooff(offtoct(pos)),
                                 -1, FI_REMAPF_LOCKED);
        }

        if (need_isem) {
            /* demote the lock now the cached pages are gone */
            XFS_ILOCK_DEMOTE(mp, io, XFS_IOLOCK_EXCL);
            up(&inode->i_sem);

            iolock = XFS_IOLOCK_SHARED;
            locktype = VRWLOCK_WRITE_DIRECT;
            need_isem = 0;
        }

        xfs_rw_enter_trace(XFS_DIOWR_ENTER, io, (void *)iovp, segs,
                           *offset, ioflags);
        ret = generic_file_direct_write(iocb, iovp,
                                        &segs, pos, offset, count, ocount);

        /*
         * direct-io write to a hole: fall through to buffered I/O
         * for completing the rest of the request.
         */
        if (ret >= 0 && ret != count) {
            XFS_STATS_ADD(xs_write_bytes, ret);

            pos += ret;
            count -= ret;

            need_isem = 1;
            ioflags &= ~IO_ISDIRECT;
            xfs_iunlock(xip, iolock);
            goto relock;
        }
    } else {
        xfs_rw_enter_trace(XFS_WRITE_ENTER, io, (void *)iovp, segs,
                           *offset, ioflags);
        ret = generic_file_buffered_write(iocb, iovp, segs,
                                          pos, offset, count, ret);
    }

    current->backing_dev_info = NULL;

    if (ret == -EIOCBQUEUED && !(ioflags & IO_ISAIO))
        ret = wait_on_sync_kiocb(iocb);

    if ((ret == -ENOSPC) &&
            DM_EVENT_ENABLED(vp->v_vfsp, xip, DM_EVENT_NOSPACE) &&
            !(ioflags & IO_INVIS)) {

        xfs_rwunlock(bdp, locktype);
        error = XFS_SEND_NAMESP(xip->i_mount, DM_EVENT_NOSPACE, vp,
                                DM_RIGHT_NULL, vp, DM_RIGHT_NULL, NULL, NULL,
                                0, 0, 0); /* Delay flag intentionally  unused */
        if (error)
            goto out_unlock_isem;
        xfs_rwlock(bdp, locktype);
        pos = xip->i_d.di_size;
        ret = 0;
        goto retry;
    }

    if (*offset > xip->i_d.di_size) {
        xfs_ilock(xip, XFS_ILOCK_EXCL);
        if (*offset > xip->i_d.di_size) {
            xip->i_d.di_size = *offset;
            i_size_write(inode, *offset);
            xip->i_update_core = 1;
            xip->i_update_size = 1;
        }
        xfs_iunlock(xip, XFS_ILOCK_EXCL);
    }

    error = -ret;
    if (ret <= 0)
        goto out_unlock_internal;

    XFS_STATS_ADD(xs_write_bytes, ret);

    /* Handle various SYNC-type writes */
    if ((file->f_flags & O_SYNC) || IS_SYNC(inode)) {
        /*
         * If we're treating this as O_DSYNC and we have not updated the
         * size, force the log.
         */
        if (!(mp->m_flags & XFS_MOUNT_OSYNCISOSYNC) &&
                !(xip->i_update_size)) {
            xfs_inode_log_item_t	*iip = xip->i_itemp;

            /*
             * If an allocation transaction occurred
             * without extending the size, then we have to force
             * the log up the proper point to ensure that the
             * allocation is permanent.  We can't count on
             * the fact that buffered writes lock out direct I/O
             * writes - the direct I/O write could have extended
             * the size nontransactionally, then finished before
             * we started.  xfs_write_file will think that the file
             * didn't grow but the update isn't safe unless the
             * size change is logged.
             *
             * Force the log if we've committed a transaction
             * against the inode or if someone else has and
             * the commit record hasn't gone to disk (e.g.
             * the inode is pinned).  This guarantees that
             * all changes affecting the inode are permanent
             * when we return.
             */
            if (iip && iip->ili_last_lsn) {
                xfs_log_force(mp, iip->ili_last_lsn,
                              XFS_LOG_FORCE | XFS_LOG_SYNC);
            } else if (xfs_ipincount(xip) > 0) {
                xfs_log_force(mp, (xfs_lsn_t)0,
                              XFS_LOG_FORCE | XFS_LOG_SYNC);
            }

        } else {
            xfs_trans_t	*tp;

            /*
             * O_SYNC or O_DSYNC _with_ a size update are handled
             * the same way.
             *
             * If the write was synchronous then we need to make
             * sure that the inode modification time is permanent.
             * We'll have updated the timestamp above, so here
             * we use a synchronous transaction to log the inode.
             * It's not fast, but it's necessary.
             *
             * If this a dsync write and the size got changed
             * non-transactionally, then we need to ensure that
             * the size change gets logged in a synchronous
             * transaction.
             */

            tp = xfs_trans_alloc(mp, XFS_TRANS_WRITE_SYNC);
            if ((error = xfs_trans_reserve(tp, 0,
                                           XFS_SWRITE_LOG_RES(mp),
                                           0, 0, 0))) {
                /* Transaction reserve failed */
                xfs_trans_cancel(tp, 0);
            } else {
                /* Transaction reserve successful */
                xfs_ilock(xip, XFS_ILOCK_EXCL);
                xfs_trans_ijoin(tp, xip, XFS_ILOCK_EXCL);
                xfs_trans_ihold(tp, xip);
                xfs_trans_log_inode(tp, xip, XFS_ILOG_CORE);
                xfs_trans_set_sync(tp);
                error = xfs_trans_commit(tp, 0, NULL);
                xfs_iunlock(xip, XFS_ILOCK_EXCL);
            }
            if (error)
                goto out_unlock_internal;
        }

        xfs_rwunlock(bdp, locktype);
        if (need_isem)
            up(&inode->i_sem);

        error = sync_page_range(inode, mapping, pos, ret);
        if (!error)
            error = ret;
        return error;
    }

out_unlock_internal:
    xfs_rwunlock(bdp, locktype);
out_unlock_isem:
    if (need_isem)
        up(&inode->i_sem);
    return -error;
}
Beispiel #16
0
/**
 * ecryptfs_lookup_and_interpose_lower - Perform a lookup
 */
int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry,
					struct dentry *lower_dentry,
					struct inode *ecryptfs_dir_inode,
					struct nameidata *ecryptfs_nd)
{
	struct dentry *lower_dir_dentry;
	struct vfsmount *lower_mnt;
	struct inode *lower_inode;
	struct ecryptfs_mount_crypt_stat *mount_crypt_stat;
	struct ecryptfs_crypt_stat *crypt_stat;
	char *page_virt = NULL;
	u64 file_size;
	int rc = 0;

	lower_dir_dentry = lower_dentry->d_parent;
	lower_mnt = mntget(ecryptfs_dentry_to_lower_mnt(
				   ecryptfs_dentry->d_parent));
	lower_inode = lower_dentry->d_inode;
	fsstack_copy_attr_atime(ecryptfs_dir_inode, lower_dir_dentry->d_inode);
	BUG_ON(!atomic_read(&lower_dentry->d_count));
	ecryptfs_set_dentry_private(ecryptfs_dentry,
				    kmem_cache_alloc(ecryptfs_dentry_info_cache,
						     GFP_KERNEL));
	if (!ecryptfs_dentry_to_private(ecryptfs_dentry)) {
		rc = -ENOMEM;
		printk(KERN_ERR "%s: Out of memory whilst attempting "
		       "to allocate ecryptfs_dentry_info struct\n",
			__func__);
		goto out_put;
	}
	ecryptfs_set_dentry_lower(ecryptfs_dentry, lower_dentry);
	ecryptfs_set_dentry_lower_mnt(ecryptfs_dentry, lower_mnt);
	if (!lower_dentry->d_inode) {
		/* We want to add because we couldn't find in lower */
		d_add(ecryptfs_dentry, NULL);
		goto out;
	}
	rc = ecryptfs_interpose(lower_dentry, ecryptfs_dentry,
				ecryptfs_dir_inode->i_sb,
				ECRYPTFS_INTERPOSE_FLAG_D_ADD);
	if (rc) {
		printk(KERN_ERR "%s: Error interposing; rc = [%d]\n",
		       __func__, rc);
		goto out;
	}
	if (S_ISDIR(lower_inode->i_mode))
		goto out;
	if (S_ISLNK(lower_inode->i_mode))
		goto out;
	if (special_file(lower_inode->i_mode))
		goto out;
	if (!ecryptfs_nd)
		goto out;
	/* Released in this function */
	page_virt = kmem_cache_zalloc(ecryptfs_header_cache_2, GFP_USER);
	if (!page_virt) {
		printk(KERN_ERR "%s: Cannot kmem_cache_zalloc() a page\n",
		       __func__);
		rc = -ENOMEM;
		goto out;
	}
	if (!ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->lower_file) {
		rc = ecryptfs_init_persistent_file(ecryptfs_dentry);
		if (rc) {
			printk(KERN_ERR "%s: Error attempting to initialize "
			       "the persistent file for the dentry with name "
			       "[%s]; rc = [%d]\n", __func__,
			       ecryptfs_dentry->d_name.name, rc);
			goto out_free_kmem;
		}
	}
	crypt_stat = &ecryptfs_inode_to_private(
					ecryptfs_dentry->d_inode)->crypt_stat;
	/* TODO: lock for crypt_stat comparison */
	if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED))
			ecryptfs_set_default_sizes(crypt_stat);
	rc = ecryptfs_read_and_validate_header_region(page_virt,
						      ecryptfs_dentry->d_inode);
	if (rc) {
		memset(page_virt, 0, PAGE_CACHE_SIZE);
		rc = ecryptfs_read_and_validate_xattr_region(page_virt,
							     ecryptfs_dentry);
		if (rc) {
			rc = 0;
			goto out_free_kmem;
		}
		crypt_stat->flags |= ECRYPTFS_METADATA_IN_XATTR;
	}
	mount_crypt_stat = &ecryptfs_superblock_to_private(
		ecryptfs_dentry->d_sb)->mount_crypt_stat;
	if (mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED) {
		if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR)
			file_size = (crypt_stat->metadata_size
				     + i_size_read(lower_dentry->d_inode));
		else
			file_size = i_size_read(lower_dentry->d_inode);
	} else {
		file_size = get_unaligned_be64(page_virt);
	}
	i_size_write(ecryptfs_dentry->d_inode, (loff_t)file_size);
out_free_kmem:
	kmem_cache_free(ecryptfs_header_cache_2, page_virt);
	goto out;
out_put:
	dput(lower_dentry);
	mntput(lower_mnt);
	d_drop(ecryptfs_dentry);
out:
	return rc;
}
Beispiel #17
0
static struct dentry *squashfs_lookup(struct inode *dir, struct dentry *dentry,
				 struct nameidata *nd)
{
	const unsigned char *name = dentry->d_name.name;
	int len = dentry->d_name.len;
	struct inode *inode = NULL;
	struct squashfs_sb_info *msblk = dir->i_sb->s_fs_info;
	struct squashfs_dir_header dirh;
	struct squashfs_dir_entry *dire;
	u64 block = squashfs_i(dir)->start + msblk->directory_table;
	int offset = squashfs_i(dir)->offset;
	int err, length = 0, dir_count, size;

	TRACE("Entered squashfs_lookup [%llx:%x]\n", block, offset);

	dire = kmalloc(sizeof(*dire) + SQUASHFS_NAME_LEN + 1, GFP_KERNEL);
	if (dire == NULL) {
		ERROR("Failed to allocate squashfs_dir_entry\n");
		return ERR_PTR(-ENOMEM);
	}

	if (len > SQUASHFS_NAME_LEN) {
		err = -ENAMETOOLONG;
		goto failed;
	}

	length = get_dir_index_using_name(dir->i_sb, &block, &offset,
				squashfs_i(dir)->dir_idx_start,
				squashfs_i(dir)->dir_idx_offset,
				squashfs_i(dir)->dir_idx_cnt, name, len);

	while (length < i_size_read(dir)) {
		/*
		 * Read directory header.
		 */
		err = squashfs_read_metadata(dir->i_sb, &dirh, &block,
				&offset, sizeof(dirh));
		if (err < 0)
			goto read_failure;

		length += sizeof(dirh);

		dir_count = le32_to_cpu(dirh.count) + 1;
		while (dir_count--) {
			/*
			 * Read directory entry.
			 */
			err = squashfs_read_metadata(dir->i_sb, dire, &block,
					&offset, sizeof(*dire));
			if (err < 0)
				goto read_failure;

			size = le16_to_cpu(dire->size) + 1;

			err = squashfs_read_metadata(dir->i_sb, dire->name,
					&block, &offset, size);
			if (err < 0)
				goto read_failure;

			length += sizeof(*dire) + size;

			if (name[0] < dire->name[0])
				goto exit_lookup;

			if (len == size && !strncmp(name, dire->name, len)) {
				unsigned int blk, off, ino_num;
				long long ino;
				blk = le32_to_cpu(dirh.start_block);
				off = le16_to_cpu(dire->offset);
				ino_num = le32_to_cpu(dirh.inode_number) +
					(short) le16_to_cpu(dire->inode_number);
				ino = SQUASHFS_MKINODE(blk, off);

				TRACE("calling squashfs_iget for directory "
					"entry %s, inode  %x:%x, %d\n", name,
					blk, off, ino_num);

				inode = squashfs_iget(dir->i_sb, ino, ino_num);
				if (IS_ERR(inode)) {
					err = PTR_ERR(inode);
					goto failed;
				}

				goto exit_lookup;
			}
		}
	}

exit_lookup:
	kfree(dire);
	if (inode)
		return d_splice_alias(inode, dentry);
	d_add(dentry, inode);
	return ERR_PTR(0);

read_failure:
	ERROR("Unable to read directory block [%llx:%x]\n",
		squashfs_i(dir)->start + msblk->directory_table,
		squashfs_i(dir)->offset);
failed:
	kfree(dire);
	return ERR_PTR(err);
}
Beispiel #18
0
static long
kdbus_memfd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
	void __user *argp = (void __user *)arg;
	struct kdbus_memfile *mf = file->private_data;
	long ret = 0;

	mutex_lock(&mf->lock);
	switch (cmd) {
	case KDBUS_CMD_MEMFD_SIZE_GET: {
		u64 size = i_size_read(file_inode(mf->fp));

		if (!KDBUS_IS_ALIGNED8(arg)) {
			ret = -EFAULT;
			goto exit;
		}

		if (copy_to_user(argp, &size, sizeof(__u64))) {
			ret = -EFAULT;
			goto exit;
		}
		break;
	}

	case KDBUS_CMD_MEMFD_SIZE_SET: {
		u64 size;

		if (!KDBUS_IS_ALIGNED8(arg)) {
			ret = -EFAULT;
			goto exit;
		}

		if (copy_from_user(&size, argp, sizeof(__u64))) {
			ret = -EFAULT;
			goto exit;
		}

		/* deny a writable access to a sealed file */
		if (mf->sealed) {
			if (size == i_size_read(file_inode(mf->fp)))
				ret = -EALREADY;
			else
				ret = -EPERM;
			goto exit;
		}

		if (size != i_size_read(file_inode(mf->fp)))
			ret = vfs_truncate(&mf->fp->f_path, size);
		break;
	}

	case KDBUS_CMD_MEMFD_SEAL_GET: {
		int __user *addr = argp;

		if (put_user(mf->sealed, addr)) {
			ret = -EFAULT;
			goto exit;
		}
		break;
	}

	case KDBUS_CMD_MEMFD_SEAL_SET: {
		struct mm_struct *mm = current->mm;

		/*
		 * Make sure we have only one single user of the file
		 * before we seal, we rely on the fact there is no
		 * any other possibly writable references to the file.
		 *
		 * Protect mmap() racing against us, take mm->mmap_sem
		 * when accessing mf->sealed.
		 */
		down_read(&mm->mmap_sem);
		if (file_count(mf->fp) != 1) {
			if (mf->sealed == !!argp)
				ret = -EALREADY;
			else
				ret = -ETXTBSY;
		}

		if (ret == 0)
			mf->sealed = !!argp;
		up_read(&mm->mmap_sem);
		break;
	}
default:
		ret = -ENOTTY;
		break;
	}

exit:
	mutex_unlock(&mf->lock);
	return ret;
}
Beispiel #19
0
/*
 * Called when an inode is about to be open.
 * We use this to disallow opening large files on 32bit systems if
 * the caller didn't specify O_LARGEFILE.  On 64bit systems we force
 * on this flag in sys_open.
 */
int generic_file_open(struct inode * inode, struct file * filp)
{
	if (!(filp->f_flags & O_LARGEFILE) && i_size_read(inode) > MAX_NON_LFS)
		return -EOVERFLOW;
	return 0;
}
Beispiel #20
0
static int __ocfs2_page_mkwrite(struct inode *inode, struct buffer_head *di_bh,
				struct page *page)
{
	int ret;
	struct address_space *mapping = inode->i_mapping;
	loff_t pos = page_offset(page);
	unsigned int len = PAGE_CACHE_SIZE;
	pgoff_t last_index;
	struct page *locked_page = NULL;
	void *fsdata;
	loff_t size = i_size_read(inode);

	/*
	 * Another node might have truncated while we were waiting on
	 * cluster locks.
	 */
	last_index = size >> PAGE_CACHE_SHIFT;
	if (page->index > last_index) {
		ret = -EINVAL;
		goto out;
	}

	/*
	 * The i_size check above doesn't catch the case where nodes
	 * truncated and then re-extended the file. We'll re-check the
	 * page mapping after taking the page lock inside of
	 * ocfs2_write_begin_nolock().
	 */
	if (!PageUptodate(page) || page->mapping != inode->i_mapping) {
		/*
		 * the page has been umapped in ocfs2_data_downconvert_worker.
		 * So return 0 here and let VFS retry.
		 */
		ret = 0;
		goto out;
	}

	/*
	 * Call ocfs2_write_begin() and ocfs2_write_end() to take
	 * advantage of the allocation code there. We pass a write
	 * length of the whole page (chopped to i_size) to make sure
	 * the whole thing is allocated.
	 *
	 * Since we know the page is up to date, we don't have to
	 * worry about ocfs2_write_begin() skipping some buffer reads
	 * because the "write" would invalidate their data.
	 */
	if (page->index == last_index)
		len = size & ~PAGE_CACHE_MASK;

	ret = ocfs2_write_begin_nolock(mapping, pos, len, 0, &locked_page,
				       &fsdata, di_bh, page);
	if (ret) {
		if (ret != -ENOSPC)
			mlog_errno(ret);
		goto out;
	}

	ret = ocfs2_write_end_nolock(mapping, pos, len, len, locked_page,
				     fsdata);
	if (ret < 0) {
		mlog_errno(ret);
		goto out;
	}
	BUG_ON(ret != len);
	ret = 0;
out:
	return ret;
}
Beispiel #21
0
STATIC loff_t
xfs_seek_hole(
	struct file		*file,
	loff_t			start)
{
	struct inode		*inode = file->f_mapping->host;
	struct xfs_inode	*ip = XFS_I(inode);
	struct xfs_mount	*mp = ip->i_mount;
	loff_t			uninitialized_var(offset);
	xfs_fsize_t		isize;
	xfs_fileoff_t		fsbno;
	xfs_filblks_t		end;
	uint			lock;
	int			error;

	if (XFS_FORCED_SHUTDOWN(mp))
		return -EIO;

	lock = xfs_ilock_data_map_shared(ip);

	isize = i_size_read(inode);
	if (start >= isize) {
		error = -ENXIO;
		goto out_unlock;
	}

	fsbno = XFS_B_TO_FSBT(mp, start);
	end = XFS_B_TO_FSB(mp, isize);

	for (;;) {
		struct xfs_bmbt_irec	map[2];
		int			nmap = 2;
		unsigned int		i;

		error = xfs_bmapi_read(ip, fsbno, end - fsbno, map, &nmap,
				       XFS_BMAPI_ENTIRE);
		if (error)
			goto out_unlock;

		/* No extents at given offset, must be beyond EOF */
		if (nmap == 0) {
			error = -ENXIO;
			goto out_unlock;
		}

		for (i = 0; i < nmap; i++) {
			offset = max_t(loff_t, start,
				       XFS_FSB_TO_B(mp, map[i].br_startoff));

			/* Landed in a hole */
			if (map[i].br_startblock == HOLESTARTBLOCK)
				goto out;

			/*
			 * Landed in an unwritten extent, try to search hole
			 * from page cache.
			 */
			if (map[i].br_state == XFS_EXT_UNWRITTEN) {
				if (xfs_find_get_desired_pgoff(inode, &map[i],
							HOLE_OFF, &offset))
					goto out;
			}
		}

		/*
		 * map[0] contains data or its unwritten but contains
		 * data in page cache, probably means that we are
		 * reading after EOF.  We should fix offset to point
		 * to the end of the file(i.e., there is an implicit
		 * hole at the end of any file).
		 */
		if (nmap == 1) {
			offset = isize;
			break;
		}

		ASSERT(i > 1);

		/*
		 * Both mappings contains data, proceed to the next round of
		 * search if the current reading offset not beyond or hit EOF.
		 */
		fsbno = map[i - 1].br_startoff + map[i - 1].br_blockcount;
		start = XFS_FSB_TO_B(mp, fsbno);
		if (start >= isize) {
			offset = isize;
			break;
		}
	}

out:
	/*
	 * At this point, we must have found a hole.  However, the returned
	 * offset may be bigger than the file size as it may be aligned to
	 * page boundary for unwritten extents, we need to deal with this
	 * situation in particular.
	 */
	offset = min_t(loff_t, offset, isize);
	offset = vfs_setpos(file, offset, inode->i_sb->s_maxbytes);

out_unlock:
	xfs_iunlock(ip, lock);

	if (error)
		return error;
	return offset;
}
/*
 * inode->i_mutex: down
 */
int
reiserfs_xattr_set_handle(struct reiserfs_transaction_handle *th,
			  struct inode *inode, const char *name,
			  const void *buffer, size_t buffer_size, int flags)
{
	int err = 0;
	struct dentry *dentry;
	struct page *page;
	char *data;
	size_t file_pos = 0;
	size_t buffer_pos = 0;
	size_t new_size;
	__u32 xahash = 0;

	if (get_inode_sd_version(inode) == STAT_DATA_V1)
		return -EOPNOTSUPP;

	if (!buffer) {
		err = lookup_and_delete_xattr(inode, name);
		return err;
	}

	dentry = xattr_lookup(inode, name, flags);
	if (IS_ERR(dentry))
		return PTR_ERR(dentry);

	down_write(&REISERFS_I(inode)->i_xattr_sem);

	xahash = xattr_hash(buffer, buffer_size);
	while (buffer_pos < buffer_size || buffer_pos == 0) {
		size_t chunk;
		size_t skip = 0;
		size_t page_offset = (file_pos & (PAGE_CACHE_SIZE - 1));
		if (buffer_size - buffer_pos > PAGE_CACHE_SIZE)
			chunk = PAGE_CACHE_SIZE;
		else
			chunk = buffer_size - buffer_pos;

		page = reiserfs_get_page(dentry->d_inode, file_pos);
		if (IS_ERR(page)) {
			err = PTR_ERR(page);
			goto out_unlock;
		}

		lock_page(page);
		data = page_address(page);

		if (file_pos == 0) {
			struct reiserfs_xattr_header *rxh;
			skip = file_pos = sizeof(struct reiserfs_xattr_header);
			if (chunk + skip > PAGE_CACHE_SIZE)
				chunk = PAGE_CACHE_SIZE - skip;
			rxh = (struct reiserfs_xattr_header *)data;
			rxh->h_magic = cpu_to_le32(REISERFS_XATTR_MAGIC);
			rxh->h_hash = cpu_to_le32(xahash);
		}

		reiserfs_write_lock(inode->i_sb);
		err = __reiserfs_write_begin(page, page_offset, chunk + skip);
		if (!err) {
			if (buffer)
				memcpy(data + skip, buffer + buffer_pos, chunk);
			err = reiserfs_commit_write(NULL, page, page_offset,
						    page_offset + chunk +
						    skip);
		}
		reiserfs_write_unlock(inode->i_sb);
		unlock_page(page);
		reiserfs_put_page(page);
		buffer_pos += chunk;
		file_pos += chunk;
		skip = 0;
		if (err || buffer_size == 0 || !buffer)
			break;
	}

	new_size = buffer_size + sizeof(struct reiserfs_xattr_header);
	if (!err && new_size < i_size_read(dentry->d_inode)) {
		struct iattr newattrs = {
			.ia_ctime = current_fs_time(inode->i_sb),
			.ia_size = new_size,
			.ia_valid = ATTR_SIZE | ATTR_CTIME,
		};

		mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_XATTR);
		inode_dio_wait(dentry->d_inode);

		err = reiserfs_setattr(dentry, &newattrs);
		mutex_unlock(&dentry->d_inode->i_mutex);
	} else
		update_ctime(inode);
out_unlock:
	up_write(&REISERFS_I(inode)->i_xattr_sem);
	dput(dentry);
	return err;
}
Beispiel #23
0
STATIC long
xfs_file_fallocate(
	struct file		*file,
	int			mode,
	loff_t			offset,
	loff_t			len)
{
	struct inode		*inode = file_inode(file);
	struct xfs_inode	*ip = XFS_I(inode);
	struct xfs_trans	*tp;
	long			error;
	loff_t			new_size = 0;

	if (!S_ISREG(inode->i_mode))
		return -EINVAL;
	if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE |
		     FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_ZERO_RANGE))
		return -EOPNOTSUPP;

	xfs_ilock(ip, XFS_IOLOCK_EXCL);
	if (mode & FALLOC_FL_PUNCH_HOLE) {
		error = xfs_free_file_space(ip, offset, len);
		if (error)
			goto out_unlock;
	} else if (mode & FALLOC_FL_COLLAPSE_RANGE) {
		unsigned blksize_mask = (1 << inode->i_blkbits) - 1;

		if (offset & blksize_mask || len & blksize_mask) {
			error = -EINVAL;
			goto out_unlock;
		}

		/*
		 * There is no need to overlap collapse range with EOF,
		 * in which case it is effectively a truncate operation
		 */
		if (offset + len >= i_size_read(inode)) {
			error = -EINVAL;
			goto out_unlock;
		}

		new_size = i_size_read(inode) - len;

		error = xfs_collapse_file_space(ip, offset, len);
		if (error)
			goto out_unlock;
	} else {
		if (!(mode & FALLOC_FL_KEEP_SIZE) &&
		    offset + len > i_size_read(inode)) {
			new_size = offset + len;
			error = inode_newsize_ok(inode, new_size);
			if (error)
				goto out_unlock;
		}

		if (mode & FALLOC_FL_ZERO_RANGE)
			error = xfs_zero_file_space(ip, offset, len);
		else
			error = xfs_alloc_file_space(ip, offset, len,
						     XFS_BMAPI_PREALLOC);
		if (error)
			goto out_unlock;
	}

	tp = xfs_trans_alloc(ip->i_mount, XFS_TRANS_WRITEID);
	error = xfs_trans_reserve(tp, &M_RES(ip->i_mount)->tr_writeid, 0, 0);
	if (error) {
		xfs_trans_cancel(tp, 0);
		goto out_unlock;
	}

	xfs_ilock(ip, XFS_ILOCK_EXCL);
	xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
	ip->i_d.di_mode &= ~S_ISUID;
	if (ip->i_d.di_mode & S_IXGRP)
		ip->i_d.di_mode &= ~S_ISGID;

	if (!(mode & (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_COLLAPSE_RANGE)))
		ip->i_d.di_flags |= XFS_DIFLAG_PREALLOC;

	xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);

	if (file->f_flags & O_DSYNC)
		xfs_trans_set_sync(tp);
	error = xfs_trans_commit(tp, 0);
	if (error)
		goto out_unlock;

	/* Change file size if needed */
	if (new_size) {
		struct iattr iattr;

		iattr.ia_valid = ATTR_SIZE;
		iattr.ia_size = new_size;
		error = xfs_setattr_size(ip, &iattr);
	}

out_unlock:
	xfs_iunlock(ip, XFS_IOLOCK_EXCL);
	return error;
}
/*
 * inode->i_mutex: down
 */
int
reiserfs_xattr_get(struct inode *inode, const char *name, void *buffer,
		   size_t buffer_size)
{
	ssize_t err = 0;
	struct dentry *dentry;
	size_t isize;
	size_t file_pos = 0;
	size_t buffer_pos = 0;
	struct page *page;
	__u32 hash = 0;

	if (name == NULL)
		return -EINVAL;

	/* We can't have xattrs attached to v1 items since they don't have
	 * generation numbers */
	if (get_inode_sd_version(inode) == STAT_DATA_V1)
		return -EOPNOTSUPP;

	dentry = xattr_lookup(inode, name, XATTR_REPLACE);
	if (IS_ERR(dentry)) {
		err = PTR_ERR(dentry);
		goto out;
	}

	down_read(&REISERFS_I(inode)->i_xattr_sem);

	isize = i_size_read(dentry->d_inode);

	/* Just return the size needed */
	if (buffer == NULL) {
		err = isize - sizeof(struct reiserfs_xattr_header);
		goto out_unlock;
	}

	if (buffer_size < isize - sizeof(struct reiserfs_xattr_header)) {
		err = -ERANGE;
		goto out_unlock;
	}

	while (file_pos < isize) {
		size_t chunk;
		char *data;
		size_t skip = 0;
		if (isize - file_pos > PAGE_CACHE_SIZE)
			chunk = PAGE_CACHE_SIZE;
		else
			chunk = isize - file_pos;

		page = reiserfs_get_page(dentry->d_inode, file_pos);
		if (IS_ERR(page)) {
			err = PTR_ERR(page);
			goto out_unlock;
		}

		lock_page(page);
		data = page_address(page);
		if (file_pos == 0) {
			struct reiserfs_xattr_header *rxh =
			    (struct reiserfs_xattr_header *)data;
			skip = file_pos = sizeof(struct reiserfs_xattr_header);
			chunk -= skip;
			/* Magic doesn't match up.. */
			if (rxh->h_magic != cpu_to_le32(REISERFS_XATTR_MAGIC)) {
				unlock_page(page);
				reiserfs_put_page(page);
				reiserfs_warning(inode->i_sb, "jdm-20001",
						 "Invalid magic for xattr (%s) "
						 "associated with %k", name,
						 INODE_PKEY(inode));
				err = -EIO;
				goto out_unlock;
			}
			hash = le32_to_cpu(rxh->h_hash);
		}
		memcpy(buffer + buffer_pos, data + skip, chunk);
		unlock_page(page);
		reiserfs_put_page(page);
		file_pos += chunk;
		buffer_pos += chunk;
		skip = 0;
	}
	err = isize - sizeof(struct reiserfs_xattr_header);

	if (xattr_hash(buffer, isize - sizeof(struct reiserfs_xattr_header)) !=
	    hash) {
		reiserfs_warning(inode->i_sb, "jdm-20002",
				 "Invalid hash for xattr (%s) associated "
				 "with %k", name, INODE_PKEY(inode));
		err = -EIO;
	}

out_unlock:
	up_read(&REISERFS_I(inode)->i_xattr_sem);
	dput(dentry);

out:
	return err;
}
Beispiel #25
0
static unsigned long dir_blocks(struct inode *inode)
{
    return ((unsigned long long) (i_size_read(inode) + PAGE_CACHE_SIZE - 1))
           >> PAGE_CACHE_SHIFT;
}
Beispiel #26
0
static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
{
    struct squashfs_sb_info *msblk;
    struct squashfs_super_block *sblk = NULL;
    char b[BDEVNAME_SIZE];
    struct inode *root;
    long long root_inode;
    unsigned short flags;
    unsigned int fragments;
    u64 lookup_table_start, xattr_id_table_start, next_table;
    int err;

    TRACE("Entered squashfs_fill_superblock\n");

    sb->s_fs_info = kzalloc(sizeof(*msblk), GFP_KERNEL);
    if (sb->s_fs_info == NULL) {
        ERROR("Failed to allocate squashfs_sb_info\n");
        return -ENOMEM;
    }
    msblk = sb->s_fs_info;

    msblk->devblksize = sb_min_blocksize(sb, SQUASHFS_DEVBLK_SIZE);
    msblk->devblksize_log2 = ffz(~msblk->devblksize);

    mutex_init(&msblk->read_data_mutex);
    mutex_init(&msblk->meta_index_mutex);

    /*
     * msblk->bytes_used is checked in squashfs_read_table to ensure reads
     * are not beyond filesystem end.  But as we're using
     * squashfs_read_table here to read the superblock (including the value
     * of bytes_used) we need to set it to an initial sensible dummy value
     */
    msblk->bytes_used = sizeof(*sblk);
    sblk = squashfs_read_table(sb, SQUASHFS_START, sizeof(*sblk));

    if (IS_ERR(sblk)) {
        ERROR("unable to read squashfs_super_block\n");
        err = PTR_ERR(sblk);
        sblk = NULL;
        goto failed_mount;
    }

    err = -EINVAL;

    /* Check it is a SQUASHFS superblock */
    sb->s_magic = le32_to_cpu(sblk->s_magic);
    if (sb->s_magic != SQUASHFS_MAGIC) {
        if (!silent)
            ERROR("Can't find a SQUASHFS superblock on %s\n",
                  bdevname(sb->s_bdev, b));
        goto failed_mount;
    }

    /* Check the MAJOR & MINOR versions and lookup compression type */
    msblk->decompressor = supported_squashfs_filesystem(
                              le16_to_cpu(sblk->s_major),
                              le16_to_cpu(sblk->s_minor),
                              le16_to_cpu(sblk->compression));
    if (msblk->decompressor == NULL)
        goto failed_mount;

    /* Check the filesystem does not extend beyond the end of the
       block device */
    msblk->bytes_used = le64_to_cpu(sblk->bytes_used);
    if (msblk->bytes_used < 0 || msblk->bytes_used >
            i_size_read(sb->s_bdev->bd_inode))
        goto failed_mount;

    /* Check block size for sanity */
    msblk->block_size = le32_to_cpu(sblk->block_size);
    if (msblk->block_size > SQUASHFS_FILE_MAX_SIZE)
        goto failed_mount;

    /*
     * Check the system page size is not larger than the filesystem
     * block size (by default 128K).  This is currently not supported.
     */
    if (PAGE_CACHE_SIZE > msblk->block_size) {
        ERROR("Page size > filesystem block size (%d).  This is "
              "currently not supported!\n", msblk->block_size);
        goto failed_mount;
    }

    msblk->block_log = le16_to_cpu(sblk->block_log);
    if (msblk->block_log > SQUASHFS_FILE_MAX_LOG)
        goto failed_mount;

    /* Check the root inode for sanity */
    root_inode = le64_to_cpu(sblk->root_inode);
    if (SQUASHFS_INODE_OFFSET(root_inode) > SQUASHFS_METADATA_SIZE)
        goto failed_mount;

    msblk->inode_table = le64_to_cpu(sblk->inode_table_start);
    msblk->directory_table = le64_to_cpu(sblk->directory_table_start);
    msblk->inodes = le32_to_cpu(sblk->inodes);
    flags = le16_to_cpu(sblk->flags);

    TRACE("Found valid superblock on %s\n", bdevname(sb->s_bdev, b));
    TRACE("Inodes are %scompressed\n", SQUASHFS_UNCOMPRESSED_INODES(flags)
          ? "un" : "");
    TRACE("Data is %scompressed\n", SQUASHFS_UNCOMPRESSED_DATA(flags)
          ? "un" : "");
    TRACE("Filesystem size %lld bytes\n", msblk->bytes_used);
    TRACE("Block size %d\n", msblk->block_size);
    TRACE("Number of inodes %d\n", msblk->inodes);
    TRACE("Number of fragments %d\n", le32_to_cpu(sblk->fragments));
    TRACE("Number of ids %d\n", le16_to_cpu(sblk->no_ids));
    TRACE("sblk->inode_table_start %llx\n", msblk->inode_table);
    TRACE("sblk->directory_table_start %llx\n", msblk->directory_table);
    TRACE("sblk->fragment_table_start %llx\n",
          (u64) le64_to_cpu(sblk->fragment_table_start));
    TRACE("sblk->id_table_start %llx\n",
          (u64) le64_to_cpu(sblk->id_table_start));

    sb->s_maxbytes = MAX_LFS_FILESIZE;
    sb->s_flags |= MS_RDONLY;
    sb->s_op = &squashfs_super_ops;

    err = -ENOMEM;

    msblk->block_cache = squashfs_cache_init("metadata",
                         SQUASHFS_CACHED_BLKS, SQUASHFS_METADATA_SIZE);
    if (msblk->block_cache == NULL)
        goto failed_mount;

    /* Allocate read_page block */
    msblk->read_page = squashfs_cache_init("data", 1, msblk->block_size);
    if (msblk->read_page == NULL) {
        ERROR("Failed to allocate read_page block\n");
        goto failed_mount;
    }

    msblk->stream = squashfs_decompressor_init(sb, flags);
    if (IS_ERR(msblk->stream)) {
        err = PTR_ERR(msblk->stream);
        msblk->stream = NULL;
        goto failed_mount;
    }

    /* Handle xattrs */
    sb->s_xattr = squashfs_xattr_handlers;
    xattr_id_table_start = le64_to_cpu(sblk->xattr_id_table_start);
    if (xattr_id_table_start == SQUASHFS_INVALID_BLK) {
        next_table = msblk->bytes_used;
        goto allocate_id_index_table;
    }

    /* Allocate and read xattr id lookup table */
    msblk->xattr_id_table = squashfs_read_xattr_id_table(sb,
                            xattr_id_table_start, &msblk->xattr_table, &msblk->xattr_ids);
    if (IS_ERR(msblk->xattr_id_table)) {
        ERROR("unable to read xattr id index table\n");
        err = PTR_ERR(msblk->xattr_id_table);
        msblk->xattr_id_table = NULL;
        if (err != -ENOTSUPP)
            goto failed_mount;
    }
    next_table = msblk->xattr_table;

allocate_id_index_table:
    /* Allocate and read id index table */
    msblk->id_table = squashfs_read_id_index_table(sb,
                      le64_to_cpu(sblk->id_table_start), next_table,
                      le16_to_cpu(sblk->no_ids));
    if (IS_ERR(msblk->id_table)) {
        ERROR("unable to read id index table\n");
        err = PTR_ERR(msblk->id_table);
        msblk->id_table = NULL;
        goto failed_mount;
    }
    next_table = le64_to_cpu(msblk->id_table[0]);

    /* Handle inode lookup table */
    lookup_table_start = le64_to_cpu(sblk->lookup_table_start);
    if (lookup_table_start == SQUASHFS_INVALID_BLK)
        goto handle_fragments;

    /* Allocate and read inode lookup table */
    msblk->inode_lookup_table = squashfs_read_inode_lookup_table(sb,
                                lookup_table_start, next_table, msblk->inodes);
    if (IS_ERR(msblk->inode_lookup_table)) {
        ERROR("unable to read inode lookup table\n");
        err = PTR_ERR(msblk->inode_lookup_table);
        msblk->inode_lookup_table = NULL;
        goto failed_mount;
    }
    next_table = le64_to_cpu(msblk->inode_lookup_table[0]);

    sb->s_export_op = &squashfs_export_ops;

handle_fragments:
    fragments = le32_to_cpu(sblk->fragments);
    if (fragments == 0)
        goto check_directory_table;

    msblk->fragment_cache = squashfs_cache_init("fragment",
                            SQUASHFS_CACHED_FRAGMENTS, msblk->block_size);
    if (msblk->fragment_cache == NULL) {
        err = -ENOMEM;
        goto failed_mount;
    }

    /* Allocate and read fragment index table */
    msblk->fragment_index = squashfs_read_fragment_index_table(sb,
                            le64_to_cpu(sblk->fragment_table_start), next_table, fragments);
    if (IS_ERR(msblk->fragment_index)) {
        ERROR("unable to read fragment index table\n");
        err = PTR_ERR(msblk->fragment_index);
        msblk->fragment_index = NULL;
        goto failed_mount;
    }
    next_table = le64_to_cpu(msblk->fragment_index[0]);

check_directory_table:
    /* Sanity check directory_table */
    if (msblk->directory_table >= next_table) {
        err = -EINVAL;
        goto failed_mount;
    }

    /* Sanity check inode_table */
    if (msblk->inode_table >= msblk->directory_table) {
        err = -EINVAL;
        goto failed_mount;
    }

    /* allocate root */
    root = new_inode(sb);
    if (!root) {
        err = -ENOMEM;
        goto failed_mount;
    }

    err = squashfs_read_inode(root, root_inode);
    if (err) {
        make_bad_inode(root);
        iput(root);
        goto failed_mount;
    }
    insert_inode_hash(root);

    sb->s_root = d_alloc_root(root);
    if (sb->s_root == NULL) {
        ERROR("Root inode create failed\n");
        err = -ENOMEM;
        iput(root);
        goto failed_mount;
    }

    TRACE("Leaving squashfs_fill_super\n");
    kfree(sblk);
    return 0;

failed_mount:
    squashfs_cache_delete(msblk->block_cache);
    squashfs_cache_delete(msblk->fragment_cache);
    squashfs_cache_delete(msblk->read_page);
    squashfs_decompressor_free(msblk, msblk->stream);
    kfree(msblk->inode_lookup_table);
    kfree(msblk->fragment_index);
    kfree(msblk->id_table);
    kfree(msblk->xattr_id_table);
    kfree(sb->s_fs_info);
    sb->s_fs_info = NULL;
    kfree(sblk);
    return err;
}
Beispiel #27
0
static int ufs_alloc_lastblock(struct inode *inode)
{
	int err = 0;
	struct super_block *sb = inode->i_sb;
	struct address_space *mapping = inode->i_mapping;
	struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
	unsigned i, end;
	sector_t lastfrag;
	struct page *lastpage;
	struct buffer_head *bh;
	u64 phys64;

	lastfrag = (i_size_read(inode) + uspi->s_fsize - 1) >> uspi->s_fshift;

	if (!lastfrag)
		goto out;

	lastfrag--;

	lastpage = ufs_get_locked_page(mapping, lastfrag >>
				       (PAGE_CACHE_SHIFT - inode->i_blkbits));
       if (IS_ERR(lastpage)) {
               err = -EIO;
               goto out;
       }

       end = lastfrag & ((1 << (PAGE_CACHE_SHIFT - inode->i_blkbits)) - 1);
       bh = page_buffers(lastpage);
       for (i = 0; i < end; ++i)
               bh = bh->b_this_page;


       err = ufs_getfrag_block(inode, lastfrag, bh, 1);

       if (unlikely(err))
	       goto out_unlock;

       if (buffer_new(bh)) {
	       clear_buffer_new(bh);
	       unmap_underlying_metadata(bh->b_bdev,
					 bh->b_blocknr);
	       /*
		* we do not zeroize fragment, because of
		* if it maped to hole, it already contains zeroes
		*/
	       set_buffer_uptodate(bh);
	       mark_buffer_dirty(bh);
	       set_page_dirty(lastpage);
       }

       if (lastfrag >= UFS_IND_FRAGMENT) {
	       end = uspi->s_fpb - ufs_fragnum(lastfrag) - 1;
	       phys64 = bh->b_blocknr + 1;
	       for (i = 0; i < end; ++i) {
		       bh = sb_getblk(sb, i + phys64);
		       lock_buffer(bh);
		       memset(bh->b_data, 0, sb->s_blocksize);
		       set_buffer_uptodate(bh);
		       mark_buffer_dirty(bh);
		       unlock_buffer(bh);
		       sync_dirty_buffer(bh);
		       brelse(bh);
	       }
       }
out_unlock:
       ufs_put_locked_page(lastpage);
out:
       return err;
}
Beispiel #28
0
/*
 * This is the worker routine which does all the work of mapping the disk
 * blocks and constructs largest possible bios, submits them for IO if the
 * blocks are not contiguous on the disk.
 *
 * We pass a buffer_head back and forth and use its buffer_mapped() flag to
 * represent the validity of its disk mapping and to decide when to do the next
 * get_block() call.
 */
static struct bio *
do_mpage_readpage(struct bio *bio, struct page *page, unsigned nr_pages,
		sector_t *last_block_in_bio, struct buffer_head *map_bh,
		unsigned long *first_logical_block, get_block_t get_block)
{
	struct inode *inode = page->mapping->host;
	const unsigned blkbits = inode->i_blkbits;
	const unsigned blocks_per_page = PAGE_CACHE_SIZE >> blkbits;
	const unsigned blocksize = 1 << blkbits;
	sector_t block_in_file;
	sector_t last_block;
	sector_t last_block_in_file;
	sector_t blocks[MAX_BUF_PER_PAGE];
	unsigned page_block;
	unsigned first_hole = blocks_per_page;
	struct block_device *bdev = NULL;
	int length, bio_length;
	int fully_mapped = 1;
	unsigned nblocks;
	unsigned relative_block;


	if (page_has_buffers(page))
		goto confused;

	block_in_file = (sector_t)page->index << (PAGE_CACHE_SHIFT - blkbits);
	last_block = block_in_file + nr_pages * blocks_per_page;
	last_block_in_file = (i_size_read(inode) + blocksize - 1) >> blkbits;
	if (last_block > last_block_in_file)
		last_block = last_block_in_file;
	page_block = 0;

	/*
	 * Map blocks using the result from the previous get_blocks call first.
	 */
	nblocks = map_bh->b_size >> blkbits;
	if (buffer_mapped(map_bh) && block_in_file > *first_logical_block &&
			block_in_file < (*first_logical_block + nblocks)) {
		unsigned map_offset = block_in_file - *first_logical_block;
		unsigned last = nblocks - map_offset;

		for (relative_block = 0; ; relative_block++) {
			if (relative_block == last) {
				clear_buffer_mapped(map_bh);
				break;
			}
			if (page_block == blocks_per_page)
				break;
			blocks[page_block] = map_bh->b_blocknr + map_offset +
						relative_block;
			page_block++;
			block_in_file++;
		}
		bdev = map_bh->b_bdev;
	}

	/*
	 * Then do more get_blocks calls until we are done with this page.
	 */
	map_bh->b_page = page;
	while (page_block < blocks_per_page) {
		map_bh->b_state = 0;
		map_bh->b_size = 0;

		if (block_in_file < last_block) {
			map_bh->b_size = (last_block-block_in_file) << blkbits;
			if (get_block(inode, block_in_file, map_bh, 0))
				goto confused;
			*first_logical_block = block_in_file;
		}

		if (!buffer_mapped(map_bh)) {
			fully_mapped = 0;
			if (first_hole == blocks_per_page)
				first_hole = page_block;
			page_block++;
			block_in_file++;
			continue;
		}

		/* some filesystems will copy data into the page during
		 * the get_block call, in which case we don't want to
		 * read it again.  map_buffer_to_page copies the data
		 * we just collected from get_block into the page's buffers
		 * so readpage doesn't have to repeat the get_block call
		 */
		if (buffer_uptodate(map_bh)) {
			map_buffer_to_page(page, map_bh, page_block);
			goto confused;
		}
	
		if (first_hole != blocks_per_page)
			goto confused;		/* hole -> non-hole */

		/* Contiguous blocks? */
		if (page_block && blocks[page_block-1] != map_bh->b_blocknr-1)
			goto confused;
		nblocks = map_bh->b_size >> blkbits;
		for (relative_block = 0; ; relative_block++) {
			if (relative_block == nblocks) {
				clear_buffer_mapped(map_bh);
				break;
			} else if (page_block == blocks_per_page)
				break;
			blocks[page_block] = map_bh->b_blocknr+relative_block;
			page_block++;
			block_in_file++;
		}
		bdev = map_bh->b_bdev;
	}

	if (first_hole != blocks_per_page) {
		zero_user_segment(page, first_hole << blkbits, PAGE_CACHE_SIZE);
		if (first_hole == 0) {
			SetPageUptodate(page);
			if (PageBaio(page))
				baiocb_put(current->current_baiocb);
			unlock_page(page);
			goto out;
		}
	} else if (fully_mapped) {
		SetPageMappedToDisk(page);
	}

	/*
	 * This page will go to BIO.  Do we need to send this BIO off first?
	 */
	if (bio && (*last_block_in_bio != blocks[0] - 1))
		bio = mpage_bio_submit(READ, bio);

alloc_new:
	if (bio == NULL) {
		bio = mpage_alloc(bdev, blocks[0] << (blkbits - 9),
			  	min_t(int, nr_pages, bio_get_nr_vecs(bdev)),
				GFP_KERNEL);
		if (bio == NULL)
			goto confused;
	}
/*
 * TODO: Make this into a generic get_blocks function.
 *
 * From do_direct_io in direct-io.c:
 *  "So what we do is to permit the ->get_blocks function to populate
 *   bh.b_size with the size of IO which is permitted at this offset and
 *   this i_blkbits."
 *
 * This function is called directly from get_more_blocks in direct-io.c.
 *
 * called like this: dio->get_blocks(dio->inode, fs_startblk,
 * 					fs_count, map_bh, dio->rw == WRITE);
 */
static int ocfs2_direct_IO_get_blocks(struct inode *inode, sector_t iblock,
				     struct buffer_head *bh_result, int create)
{
	int ret;
	u64 p_blkno, inode_blocks, contig_blocks;
	unsigned int ext_flags;
	unsigned char blocksize_bits = inode->i_sb->s_blocksize_bits;
	unsigned long max_blocks = bh_result->b_size >> inode->i_blkbits;

	/* This function won't even be called if the request isn't all
	 * nicely aligned and of the right size, so there's no need
	 * for us to check any of that. */

	inode_blocks = ocfs2_blocks_for_bytes(inode->i_sb, i_size_read(inode));

	/*
	 * Any write past EOF is not allowed because we'd be extending.
	 */
	if (create && (iblock + max_blocks) > inode_blocks) {
		ret = -EIO;
		goto bail;
	}

	/* This figures out the size of the next contiguous block, and
	 * our logical offset */
	ret = ocfs2_extent_map_get_blocks(inode, iblock, &p_blkno,
					  &contig_blocks, &ext_flags);
	if (ret) {
		mlog(ML_ERROR, "get_blocks() failed iblock=%llu\n",
		     (unsigned long long)iblock);
		ret = -EIO;
		goto bail;
	}

	if (!ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb)) && !p_blkno && create) {
		ocfs2_error(inode->i_sb,
			    "Inode %llu has a hole at block %llu\n",
			    (unsigned long long)OCFS2_I(inode)->ip_blkno,
			    (unsigned long long)iblock);
		ret = -EROFS;
		goto bail;
	}

	/*
	 * get_more_blocks() expects us to describe a hole by clearing
	 * the mapped bit on bh_result().
	 *
	 * Consider an unwritten extent as a hole.
	 */
	if (p_blkno && !(ext_flags & OCFS2_EXT_UNWRITTEN))
		map_bh(bh_result, inode->i_sb, p_blkno);
	else {
		/*
		 * ocfs2_prepare_inode_for_write() should have caught
		 * the case where we'd be filling a hole and triggered
		 * a buffered write instead.
		 */
		if (create) {
			ret = -EIO;
			mlog_errno(ret);
			goto bail;
		}

		clear_buffer_mapped(bh_result);
	}

	/* make sure we don't map more than max_blocks blocks here as
	   that's all the kernel will handle at this point. */
	if (max_blocks < contig_blocks)
		contig_blocks = max_blocks;
	bh_result->b_size = contig_blocks << blocksize_bits;
bail:
	return ret;
}
Beispiel #30
0
/*
 * AFS read page from file, directory or symlink
 */
static int afs_readpage(struct file *file, struct page *page)
{
	struct afs_vnode *vnode;
	struct inode *inode;
	struct key *key;
	size_t len;
	off_t offset;
	int ret;

	inode = page->mapping->host;

	ASSERT(file != NULL);
	key = file->private_data;
	ASSERT(key != NULL);

	_enter("{%x},{%lu},{%lu}", key_serial(key), inode->i_ino, page->index);

	vnode = AFS_FS_I(inode);

	BUG_ON(!PageLocked(page));

	ret = -ESTALE;
	if (test_bit(AFS_VNODE_DELETED, &vnode->flags))
		goto error;

#ifdef AFS_CACHING_SUPPORT
	/* is it cached? */
	ret = cachefs_read_or_alloc_page(vnode->cache,
					 page,
					 afs_file_readpage_read_complete,
					 NULL,
					 GFP_KERNEL);
#else
	ret = -ENOBUFS;
#endif

	switch (ret) {
		/* read BIO submitted and wb-journal entry found */
	case 1:
		BUG(); // TODO - handle wb-journal match

		/* read BIO submitted (page in cache) */
	case 0:
		break;

		/* no page available in cache */
	case -ENOBUFS:
	case -ENODATA:
	default:
		offset = page->index << PAGE_CACHE_SHIFT;
		len = min_t(size_t, i_size_read(inode) - offset, PAGE_SIZE);

		/* read the contents of the file from the server into the
		 * page */
		ret = afs_vnode_fetch_data(vnode, key, offset, len, page);
		if (ret < 0) {
			if (ret == -ENOENT) {
				_debug("got NOENT from server"
				       " - marking file deleted and stale");
				set_bit(AFS_VNODE_DELETED, &vnode->flags);
				ret = -ESTALE;
			}
#ifdef AFS_CACHING_SUPPORT
			cachefs_uncache_page(vnode->cache, page);
#endif
			goto error;
		}

		SetPageUptodate(page);

#ifdef AFS_CACHING_SUPPORT
		if (cachefs_write_page(vnode->cache,
				       page,
				       afs_file_readpage_write_complete,
				       NULL,
				       GFP_KERNEL) != 0
		    ) {
			cachefs_uncache_page(vnode->cache, page);
			unlock_page(page);
		}
#else
		unlock_page(page);
#endif
	}

	_leave(" = 0");
	return 0;

error:
	SetPageError(page);
	unlock_page(page);
	_leave(" = %d", ret);
	return ret;
}