Exemplo n.º 1
0
int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
	struct file *filp)
{
	int ret;
	struct iattr newattrs;

	
	if (length < 0)
		return -EINVAL;

	newattrs.ia_size = length;
	newattrs.ia_valid = ATTR_SIZE | time_attrs;
	if (filp) {
		newattrs.ia_file = filp;
		newattrs.ia_valid |= ATTR_FILE;
	}

	
	ret = should_remove_suid(dentry);
	if (ret)
		newattrs.ia_valid |= ret | ATTR_FORCE;

	mutex_lock(&dentry->d_inode->i_mutex);
	ret = notify_change(dentry, &newattrs);
	mutex_unlock(&dentry->d_inode->i_mutex);
	return ret;
}
Exemplo n.º 2
0
int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
	struct file *filp)
{
	int ret;
	struct iattr newattrs;

	/* Not pretty: "inode->i_size" shouldn't really be signed. But it is. */
	if (length < 0)
		return -EINVAL;

	newattrs.ia_size = length;
	newattrs.ia_valid = ATTR_SIZE | time_attrs;
	if (filp) {
		newattrs.ia_file = filp;
		newattrs.ia_valid |= ATTR_FILE;
	}

	/* Remove suid/sgid on truncate too */
	ret = should_remove_suid(dentry);
	if (ret)
		newattrs.ia_valid |= ret | ATTR_FORCE;

	mutex_lock(&dentry->d_inode->i_mutex);
	ret = notify_change(dentry, &newattrs);
	mutex_unlock(&dentry->d_inode->i_mutex);
	return ret;
}
Exemplo n.º 3
0
int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
	struct file *filp)
{
	int ret;
	struct iattr newattrs;
#if IO_LOGGER_ENABLE
	
		unsigned long long time1 = 0,timeoffset = 0;
		bool add_trace_e = false;
#endif
	/* Not pretty: "inode->i_size" shouldn't really be signed. But it is. */
	if (length < 0)
		return -EINVAL;
#if IO_LOGGER_ENABLE
	if(unlikely(en_IOLogger())){
		add_trace_e=true;
		time1 = sched_clock();
		AddIOTrace(IO_LOGGER_MSG_VFS_INTFS,do_truncate,dentry->d_name.name,(u32)length);
	}
#endif

	newattrs.ia_size = length;
	newattrs.ia_valid = ATTR_SIZE | time_attrs;
	if (filp) {
		newattrs.ia_file = filp;
		newattrs.ia_valid |= ATTR_FILE;
	}

	/* Remove suid/sgid on truncate too */
	ret = should_remove_suid(dentry);
	if (ret)
		newattrs.ia_valid |= ret | ATTR_FORCE;

	mutex_lock(&dentry->d_inode->i_mutex);
	ret = notify_change(dentry, &newattrs);
	mutex_unlock(&dentry->d_inode->i_mutex);
#if IO_LOGGER_ENABLE
			if(unlikely(en_IOLogger()) && add_trace_e){
				timeoffset = sched_clock() - time1;
				add_trace_e = false;
				if(BEYOND_TRACE_LOG_TIME(timeoffset))
				{
					 AddIOTrace(IO_LOGGER_MSG_VFS_INTFS_END,do_truncate,dentry->d_name.name,ret,timeoffset);	
					 if(BEYOND_DUMP_LOG_TIME(timeoffset))
						DumpIOTrace(timeoffset);
					
				}
			}
#endif
	return ret;
}
Exemplo n.º 4
0
static int fuse_setattr(struct dentry *entry, struct iattr *attr)
{
	struct inode *inode = d_inode(entry);
	struct file *file = (attr->ia_valid & ATTR_FILE) ? attr->ia_file : NULL;
	int ret;

	if (!fuse_allow_current_process(get_fuse_conn(inode)))
		return -EACCES;

	if (attr->ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID)) {
		int kill;

		attr->ia_valid &= ~(ATTR_KILL_SUID | ATTR_KILL_SGID |
				    ATTR_MODE);
		/*
		 * ia_mode calculation may have used stale i_mode.  Refresh and
		 * recalculate.
		 */
		ret = fuse_do_getattr(inode, NULL, file);
		if (ret)
			return ret;

		attr->ia_mode = inode->i_mode;
		kill = should_remove_suid(entry);
		if (kill & ATTR_KILL_SUID) {
			attr->ia_valid |= ATTR_MODE;
			attr->ia_mode &= ~S_ISUID;
		}
		if (kill & ATTR_KILL_SGID) {
			attr->ia_valid |= ATTR_MODE;
			attr->ia_mode &= ~S_ISGID;
		}
	}
	if (!attr->ia_valid)
		return 0;

	ret = fuse_do_setattr(inode, attr, file);
	if (!ret) {
		/* Directory mode changed, may need to revalidate access */
		if (d_is_dir(entry) && (attr->ia_valid & ATTR_MODE))
			fuse_invalidate_entry_cache(entry);
	}
	return ret;
}
Exemplo n.º 5
0
int handle_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs)
{
    int err;
    struct iattr newattrs;

    /* Not pretty: "inode->i_size" shouldn't really be signed. But it is. */
    if(length < 0)
        return -EINVAL;

    newattrs.ia_size = length;
    newattrs.ia_valid = ATTR_SIZE | time_attrs;

    /* Remove suid/sgid on truncate too */
    newattrs.ia_valid |= should_remove_suid(dentry);

    mutex_lock(&dentry->d_inode->i_mutex);
    err = notify_change(dentry, &newattrs);
    mutex_unlock(&dentry->d_inode->i_mutex);
    return err;
}
Exemplo n.º 6
0
/**
 * generic_file_splice_write - splice data from a pipe to a file
 * @pipe:	pipe info
 * @out:	file to write to
 * @len:	number of bytes to splice
 * @flags:	splice modifier flags
 *
 * Will either move or copy pages (determined by @flags options) from
 * the given pipe inode to the given file.
 *
 */
ssize_t
generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out,
			  loff_t *ppos, size_t len, unsigned int flags)
{
	struct address_space *mapping = out->f_mapping;
	struct inode *inode = mapping->host;
	ssize_t ret;
	int err;

	err = should_remove_suid(out->f_dentry);
	if (unlikely(err)) {
		mutex_lock(&inode->i_mutex);
		err = __remove_suid(out->f_dentry, err);
		mutex_unlock(&inode->i_mutex);
		if (err)
			return err;
	}

	ret = splice_from_pipe(pipe, out, ppos, len, flags, pipe_to_file);
	if (ret > 0) {
		*ppos += ret;

		/*
		 * If file or inode is SYNC and we actually wrote some data,
		 * sync it.
		 */
		if (unlikely((out->f_flags & O_SYNC) || IS_SYNC(inode))) {
			mutex_lock(&inode->i_mutex);
			err = generic_osync_inode(inode, mapping,
						  OSYNC_METADATA|OSYNC_DATA);
			mutex_unlock(&inode->i_mutex);

			if (err)
				ret = err;
		}
	}

	return ret;
}
Exemplo n.º 7
0
static int ocfs2_prepare_inode_for_write(struct dentry *dentry,
					 loff_t *ppos,
					 size_t count,
					 int appending,
					 int *direct_io)
{
	int ret = 0, meta_level = appending;
	struct inode *inode = dentry->d_inode;
	u32 clusters;
	loff_t newsize, saved_pos;

	/* 
	 * We sample i_size under a read level meta lock to see if our write
	 * is extending the file, if it is we back off and get a write level
	 * meta lock.
	 */
	for(;;) {
		ret = ocfs2_meta_lock(inode, NULL, meta_level);
		if (ret < 0) {
			meta_level = -1;
			mlog_errno(ret);
			goto out;
		}

		/* Clear suid / sgid if necessary. We do this here
		 * instead of later in the write path because
		 * remove_suid() calls ->setattr without any hint that
		 * we may have already done our cluster locking. Since
		 * ocfs2_setattr() *must* take cluster locks to
		 * proceeed, this will lead us to recursively lock the
		 * inode. There's also the dinode i_size state which
		 * can be lost via setattr during extending writes (we
		 * set inode->i_size at the end of a write. */
		if (should_remove_suid(dentry)) {
			if (meta_level == 0) {
				ocfs2_meta_unlock(inode, meta_level);
				meta_level = 1;
				continue;
			}

			ret = ocfs2_write_remove_suid(inode);
			if (ret < 0) {
				mlog_errno(ret);
				goto out_unlock;
			}
		}

		/* work on a copy of ppos until we're sure that we won't have
		 * to recalculate it due to relocking. */
		if (appending) {
			saved_pos = i_size_read(inode);
			mlog(0, "O_APPEND: inode->i_size=%llu\n", saved_pos);
		} else {
			saved_pos = *ppos;
		}

		if (ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb))) {
			loff_t end = saved_pos + count;

			/*
			 * Skip the O_DIRECT checks if we don't need
			 * them.
			 */
			if (!direct_io || !(*direct_io))
				break;

			/*
			 * Allowing concurrent direct writes means
			 * i_size changes wouldn't be synchronized, so
			 * one node could wind up truncating another
			 * nodes writes.
			 */
			if (end > i_size_read(inode)) {
				*direct_io = 0;
				break;
			}

			/*
			 * We don't fill holes during direct io, so
			 * check for them here. If any are found, the
			 * caller will have to retake some cluster
			 * locks and initiate the io as buffered.
			 */
			ret = ocfs2_check_range_for_holes(inode, saved_pos,
							  count);
			if (ret == 1) {
				*direct_io = 0;
				ret = 0;
			} else if (ret < 0)
				mlog_errno(ret);
			break;
		}

		/*
		 * The rest of this loop is concerned with legacy file
		 * systems which don't support sparse files.
		 */

		newsize = count + saved_pos;

		mlog(0, "pos=%lld newsize=%lld cursize=%lld\n",
		     (long long) saved_pos, (long long) newsize,
		     (long long) i_size_read(inode));

		/* No need for a higher level metadata lock if we're
		 * never going past i_size. */
		if (newsize <= i_size_read(inode))
			break;

		if (meta_level == 0) {
			ocfs2_meta_unlock(inode, meta_level);
			meta_level = 1;
			continue;
		}

		spin_lock(&OCFS2_I(inode)->ip_lock);
		clusters = ocfs2_clusters_for_bytes(inode->i_sb, newsize) -
			OCFS2_I(inode)->ip_clusters;
		spin_unlock(&OCFS2_I(inode)->ip_lock);

		mlog(0, "Writing at EOF, may need more allocation: "
		     "i_size = %lld, newsize = %lld, need %u clusters\n",
		     (long long) i_size_read(inode), (long long) newsize,
		     clusters);

		/* We only want to continue the rest of this loop if
		 * our extend will actually require more
		 * allocation. */
		if (!clusters)
			break;

		ret = ocfs2_extend_file(inode, NULL, newsize, count);
		if (ret < 0) {
			if (ret != -ENOSPC)
				mlog_errno(ret);
			goto out_unlock;
		}
		break;
	}

	if (appending)
		*ppos = saved_pos;

out_unlock:
	ocfs2_meta_unlock(inode, meta_level);

out:
	return ret;
}