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

Commit 5eec54fc authored by Ian Abbott's avatar Ian Abbott Committed by Jan Kara
Browse files

UDF: Add support for O_DIRECT



Add support for the O_DIRECT flag.  There are two cases to deal with:

1. Small files stored in the ICB (inode control block?): just return 0
from the new udf_adinicb_direct_IO() handler to fall back to buffered
I/O.

2. Larger files, not stored in the ICB: nothing special here.  Just call
blockdev_direct_IO() from our new udf_direct_IO() handler and tidy up
any blocks instantiated outside i_size on error.  This is pretty
standard.  Factor error handling code out of udf_write_begin() into new
function udf_write_failed() so it can also be called by udf_direct_IO().

Also change the whitespace in udf_aops to make it a bit neater.

Signed-off-by: default avatarIan Abbott <abbotti@mev.co.uk>
Signed-off-by: default avatarJan Kara <jack@suse.cz>
parent 3f6bba82
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -114,7 +114,7 @@ static void deliver_alarm(void)
	skew += this_tick - last_tick;
	skew += this_tick - last_tick;


	while (skew >= one_tick) {
	while (skew >= one_tick) {
		alarm_handler(SIGVTALRM, NULL);
		alarm_handler(SIGVTALRM, NULL, NULL);
		skew -= one_tick;
		skew -= one_tick;
	}
	}


+9 −0
Original line number Original line Diff line number Diff line
@@ -118,11 +118,20 @@ static int udf_adinicb_write_end(struct file *file,
	return simple_write_end(file, mapping, pos, len, copied, page, fsdata);
	return simple_write_end(file, mapping, pos, len, copied, page, fsdata);
}
}


static ssize_t udf_adinicb_direct_IO(int rw, struct kiocb *iocb,
				     const struct iovec *iov,
				     loff_t offset, unsigned long nr_segs)
{
	/* Fallback to buffered I/O. */
	return 0;
}

const struct address_space_operations udf_adinicb_aops = {
const struct address_space_operations udf_adinicb_aops = {
	.readpage	= udf_adinicb_readpage,
	.readpage	= udf_adinicb_readpage,
	.writepage	= udf_adinicb_writepage,
	.writepage	= udf_adinicb_writepage,
	.write_begin	= udf_adinicb_write_begin,
	.write_begin	= udf_adinicb_write_begin,
	.write_end	= udf_adinicb_write_end,
	.write_end	= udf_adinicb_write_end,
	.direct_IO	= udf_adinicb_direct_IO,
};
};


static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
+36 −16
Original line number Original line Diff line number Diff line
@@ -95,6 +95,22 @@ void udf_evict_inode(struct inode *inode)
	}
	}
}
}


static void udf_write_failed(struct address_space *mapping, loff_t to)
{
	struct inode *inode = mapping->host;
	struct udf_inode_info *iinfo = UDF_I(inode);
	loff_t isize = inode->i_size;

	if (to > isize) {
		truncate_pagecache(inode, to, isize);
		if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
			down_write(&iinfo->i_data_sem);
			udf_truncate_extents(inode);
			up_write(&iinfo->i_data_sem);
		}
	}
}

static int udf_writepage(struct page *page, struct writeback_control *wbc)
static int udf_writepage(struct page *page, struct writeback_control *wbc)
{
{
	return block_write_full_page(page, udf_get_block, wbc);
	return block_write_full_page(page, udf_get_block, wbc);
@@ -124,21 +140,24 @@ static int udf_write_begin(struct file *file, struct address_space *mapping,
	int ret;
	int ret;


	ret = block_write_begin(mapping, pos, len, flags, pagep, udf_get_block);
	ret = block_write_begin(mapping, pos, len, flags, pagep, udf_get_block);
	if (unlikely(ret)) {
	if (unlikely(ret))
		struct inode *inode = mapping->host;
		udf_write_failed(mapping, pos + len);
		struct udf_inode_info *iinfo = UDF_I(inode);
	return ret;
		loff_t isize = inode->i_size;

		if (pos + len > isize) {
			truncate_pagecache(inode, pos + len, isize);
			if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
				down_write(&iinfo->i_data_sem);
				udf_truncate_extents(inode);
				up_write(&iinfo->i_data_sem);
			}
		}
}
}


static ssize_t udf_direct_IO(int rw, struct kiocb *iocb,
			     const struct iovec *iov,
			     loff_t offset, unsigned long nr_segs)
{
	struct file *file = iocb->ki_filp;
	struct address_space *mapping = file->f_mapping;
	struct inode *inode = mapping->host;
	ssize_t ret;

	ret = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs,
				  udf_get_block);
	if (unlikely(ret < 0 && (rw & WRITE)))
		udf_write_failed(mapping, offset + iov_length(iov, nr_segs));
	return ret;
	return ret;
}
}


@@ -154,6 +173,7 @@ const struct address_space_operations udf_aops = {
	.writepages	= udf_writepages,
	.writepages	= udf_writepages,
	.write_begin	= udf_write_begin,
	.write_begin	= udf_write_begin,
	.write_end	= generic_write_end,
	.write_end	= generic_write_end,
	.direct_IO	= udf_direct_IO,
	.bmap		= udf_bmap,
	.bmap		= udf_bmap,
};
};