Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 06222e49 authored by Josef Bacik's avatar Josef Bacik Committed by Al Viro
Browse files

fs: handle SEEK_HOLE/SEEK_DATA properly in all fs's that define their own llseek



This converts everybody to handle SEEK_HOLE/SEEK_DATA properly.  In some cases
we just return -EINVAL, in others we do the normal generic thing, and in others
we're simply making sure that the properly due-dilligence is done.  For example
in NFS/CIFS we need to make sure the file size is update properly for the
SEEK_HOLE and SEEK_DATA case, but since it calls the generic llseek stuff itself
that is all we have to do.  Thanks,

Signed-off-by: default avatarJosef Bacik <josef@redhat.com>
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent c334b113
Loading
Loading
Loading
Loading
+8 −3
Original line number Original line Diff line number Diff line
@@ -355,20 +355,25 @@ static loff_t block_llseek(struct file *file, loff_t offset, int origin)
	mutex_lock(&bd_inode->i_mutex);
	mutex_lock(&bd_inode->i_mutex);
	size = i_size_read(bd_inode);
	size = i_size_read(bd_inode);


	retval = -EINVAL;
	switch (origin) {
	switch (origin) {
		case 2:
		case SEEK_END:
			offset += size;
			offset += size;
			break;
			break;
		case 1:
		case SEEK_CUR:
			offset += file->f_pos;
			offset += file->f_pos;
		case SEEK_SET:
			break;
		default:
			goto out;
	}
	}
	retval = -EINVAL;
	if (offset >= 0 && offset <= size) {
	if (offset >= 0 && offset <= size) {
		if (offset != file->f_pos) {
		if (offset != file->f_pos) {
			file->f_pos = offset;
			file->f_pos = offset;
		}
		}
		retval = offset;
		retval = offset;
	}
	}
out:
	mutex_unlock(&bd_inode->i_mutex);
	mutex_unlock(&bd_inode->i_mutex);
	return retval;
	return retval;
}
}
+7 −1
Original line number Original line Diff line number Diff line
@@ -446,14 +446,19 @@ static loff_t ceph_dir_llseek(struct file *file, loff_t offset, int origin)
	loff_t retval;
	loff_t retval;


	mutex_lock(&inode->i_mutex);
	mutex_lock(&inode->i_mutex);
	retval = -EINVAL;
	switch (origin) {
	switch (origin) {
	case SEEK_END:
	case SEEK_END:
		offset += inode->i_size + 2;   /* FIXME */
		offset += inode->i_size + 2;   /* FIXME */
		break;
		break;
	case SEEK_CUR:
	case SEEK_CUR:
		offset += file->f_pos;
		offset += file->f_pos;
	case SEEK_SET:
		break;
	default:
		goto out;
	}
	}
	retval = -EINVAL;

	if (offset >= 0 && offset <= inode->i_sb->s_maxbytes) {
	if (offset >= 0 && offset <= inode->i_sb->s_maxbytes) {
		if (offset != file->f_pos) {
		if (offset != file->f_pos) {
			file->f_pos = offset;
			file->f_pos = offset;
@@ -477,6 +482,7 @@ static loff_t ceph_dir_llseek(struct file *file, loff_t offset, int origin)
		if (offset > old_offset)
		if (offset > old_offset)
			fi->dir_release_count--;
			fi->dir_release_count--;
	}
	}
out:
	mutex_unlock(&inode->i_mutex);
	mutex_unlock(&inode->i_mutex);
	return retval;
	return retval;
}
}
+18 −2
Original line number Original line Diff line number Diff line
@@ -768,13 +768,16 @@ static loff_t ceph_llseek(struct file *file, loff_t offset, int origin)


	mutex_lock(&inode->i_mutex);
	mutex_lock(&inode->i_mutex);
	__ceph_do_pending_vmtruncate(inode);
	__ceph_do_pending_vmtruncate(inode);
	switch (origin) {
	if (origin != SEEK_CUR || origin != SEEK_SET) {
	case SEEK_END:
		ret = ceph_do_getattr(inode, CEPH_STAT_CAP_SIZE);
		ret = ceph_do_getattr(inode, CEPH_STAT_CAP_SIZE);
		if (ret < 0) {
		if (ret < 0) {
			offset = ret;
			offset = ret;
			goto out;
			goto out;
		}
		}
	}

	switch (origin) {
	case SEEK_END:
		offset += inode->i_size;
		offset += inode->i_size;
		break;
		break;
	case SEEK_CUR:
	case SEEK_CUR:
@@ -790,6 +793,19 @@ static loff_t ceph_llseek(struct file *file, loff_t offset, int origin)
		}
		}
		offset += file->f_pos;
		offset += file->f_pos;
		break;
		break;
	case SEEK_DATA:
		if (offset >= inode->i_size) {
			ret = -ENXIO;
			goto out;
		}
		break;
	case SEEK_HOLE:
		if (offset >= inode->i_size) {
			ret = -ENXIO;
			goto out;
		}
		offset = inode->i_size;
		break;
	}
	}


	if (offset < 0 || offset > inode->i_sb->s_maxbytes) {
	if (offset < 0 || offset > inode->i_sb->s_maxbytes) {
+5 −2
Original line number Original line Diff line number Diff line
@@ -704,8 +704,11 @@ static ssize_t cifs_file_aio_write(struct kiocb *iocb, const struct iovec *iov,


static loff_t cifs_llseek(struct file *file, loff_t offset, int origin)
static loff_t cifs_llseek(struct file *file, loff_t offset, int origin)
{
{
	/* origin == SEEK_END => we must revalidate the cached file length */
	/*
	if (origin == SEEK_END) {
	 * origin == SEEK_END || SEEK_DATA || SEEK_HOLE => we must revalidate
	 * the cached file length
	 */
	if (origin != SEEK_SET || origin != SEEK_CUR) {
		int rc;
		int rc;
		struct inode *inode = file->f_path.dentry->d_inode;
		struct inode *inode = file->f_path.dentry->d_inode;


+19 −2
Original line number Original line Diff line number Diff line
@@ -1600,15 +1600,32 @@ static loff_t fuse_file_llseek(struct file *file, loff_t offset, int origin)
	struct inode *inode = file->f_path.dentry->d_inode;
	struct inode *inode = file->f_path.dentry->d_inode;


	mutex_lock(&inode->i_mutex);
	mutex_lock(&inode->i_mutex);
	switch (origin) {
	if (origin != SEEK_CUR || origin != SEEK_SET) {
	case SEEK_END:
		retval = fuse_update_attributes(inode, NULL, file, NULL);
		retval = fuse_update_attributes(inode, NULL, file, NULL);
		if (retval)
		if (retval)
			goto exit;
			goto exit;
	}

	switch (origin) {
	case SEEK_END:
		offset += i_size_read(inode);
		offset += i_size_read(inode);
		break;
		break;
	case SEEK_CUR:
	case SEEK_CUR:
		offset += file->f_pos;
		offset += file->f_pos;
		break;
	case SEEK_DATA:
		if (offset >= i_size_read(inode)) {
			retval = -ENXIO;
			goto exit;
		}
		break;
	case SEEK_HOLE:
		if (offset >= i_size_read(inode)) {
			retval = -ENXIO;
			goto exit;
		}
		offset = i_size_read(inode);
		break;
	}
	}
	retval = -EINVAL;
	retval = -EINVAL;
	if (offset >= 0 && offset <= inode->i_sb->s_maxbytes) {
	if (offset >= 0 && offset <= inode->i_sb->s_maxbytes) {
Loading