Commit a632f559 authored by Anton Altaparmakov's avatar Anton Altaparmakov Committed by Al Viro

NTFS: Version 2.1.32 - Update file write from aio_write to write_iter.

Signed-off-by: default avatarAnton Altaparmakov <anton@tuxera.com>
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 171a0203
...@@ -8,7 +8,7 @@ ntfs-y := aops.o attrib.o collate.o compress.o debug.o dir.o file.o \ ...@@ -8,7 +8,7 @@ ntfs-y := aops.o attrib.o collate.o compress.o debug.o dir.o file.o \
ntfs-$(CONFIG_NTFS_RW) += bitmap.o lcnalloc.o logfile.o quota.o usnjrnl.o ntfs-$(CONFIG_NTFS_RW) += bitmap.o lcnalloc.o logfile.o quota.o usnjrnl.o
ccflags-y := -DNTFS_VERSION=\"2.1.31\" ccflags-y := -DNTFS_VERSION=\"2.1.32\"
ccflags-$(CONFIG_NTFS_DEBUG) += -DDEBUG ccflags-$(CONFIG_NTFS_DEBUG) += -DDEBUG
ccflags-$(CONFIG_NTFS_RW) += -DNTFS_RW ccflags-$(CONFIG_NTFS_RW) += -DNTFS_RW
/* /*
* file.c - NTFS kernel file operations. Part of the Linux-NTFS project. * file.c - NTFS kernel file operations. Part of the Linux-NTFS project.
* *
* Copyright (c) 2001-2014 Anton Altaparmakov and Tuxera Inc. * Copyright (c) 2001-2015 Anton Altaparmakov and Tuxera Inc.
* *
* This program/include file is free software; you can redistribute it and/or * This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published * modify it under the terms of the GNU General Public License as published
...@@ -329,62 +329,168 @@ static int ntfs_attr_extend_initialized(ntfs_inode *ni, const s64 new_init_size) ...@@ -329,62 +329,168 @@ static int ntfs_attr_extend_initialized(ntfs_inode *ni, const s64 new_init_size)
return err; return err;
} }
/** static ssize_t ntfs_prepare_file_for_write(struct file *file, loff_t *ppos,
* ntfs_fault_in_pages_readable - size_t *count)
*
* Fault a number of userspace pages into pagetables.
*
* Unlike include/linux/pagemap.h::fault_in_pages_readable(), this one copes
* with more than two userspace pages as well as handling the single page case
* elegantly.
*
* If you find this difficult to understand, then think of the while loop being
* the following code, except that we do without the integer variable ret:
*
* do {
* ret = __get_user(c, uaddr);
* uaddr += PAGE_SIZE;
* } while (!ret && uaddr < end);
*
* Note, the final __get_user() may well run out-of-bounds of the user buffer,
* but _not_ out-of-bounds of the page the user buffer belongs to, and since
* this is only a read and not a write, and since it is still in the same page,
* it should not matter and this makes the code much simpler.
*/
static inline void ntfs_fault_in_pages_readable(const char __user *uaddr,
int bytes)
{ {
const char __user *end; loff_t pos;
volatile char c; s64 end, ll;
ssize_t err;
/* Set @end to the first byte outside the last page we care about. */ unsigned long flags;
end = (const char __user*)PAGE_ALIGN((unsigned long)uaddr + bytes); struct inode *vi = file_inode(file);
ntfs_inode *base_ni, *ni = NTFS_I(vi);
while (!__get_user(c, uaddr) && (uaddr += PAGE_SIZE, uaddr < end)) ntfs_volume *vol = ni->vol;
;
}
/** ntfs_debug("Entering for i_ino 0x%lx, attribute type 0x%x, pos "
* ntfs_fault_in_pages_readable_iovec - "0x%llx, count 0x%lx.", vi->i_ino,
(unsigned)le32_to_cpu(ni->type),
(unsigned long long)*ppos, (unsigned long)*count);
/* We can write back this queue in page reclaim. */
current->backing_dev_info = inode_to_bdi(vi);
err = generic_write_checks(file, ppos, count, S_ISBLK(vi->i_mode));
if (unlikely(err))
goto out;
/*
* All checks have passed. Before we start doing any writing we want
* to abort any totally illegal writes.
*/
BUG_ON(NInoMstProtected(ni));
BUG_ON(ni->type != AT_DATA);
/* If file is encrypted, deny access, just like NT4. */
if (NInoEncrypted(ni)) {
/* Only $DATA attributes can be encrypted. */
/*
* Reminder for later: Encrypted files are _always_
* non-resident so that the content can always be encrypted.
*/
ntfs_debug("Denying write access to encrypted file.");
err = -EACCES;
goto out;
}
if (NInoCompressed(ni)) {
/* Only unnamed $DATA attribute can be compressed. */
BUG_ON(ni->name_len);
/*
* Reminder for later: If resident, the data is not actually
* compressed. Only on the switch to non-resident does
* compression kick in. This is in contrast to encrypted files
* (see above).
*/
ntfs_error(vi->i_sb, "Writing to compressed files is not "
"implemented yet. Sorry.");
err = -EOPNOTSUPP;
goto out;
}
if (*count == 0)
goto out;
base_ni = ni;
if (NInoAttr(ni))
base_ni = ni->ext.base_ntfs_ino;
err = file_remove_suid(file);
if (unlikely(err))
goto out;
/*
* Our ->update_time method always succeeds thus file_update_time()
* cannot fail either so there is no need to check the return code.
*/
file_update_time(file);
pos = *ppos;
/* The first byte after the last cluster being written to. */
end = (pos + *count + vol->cluster_size_mask) &
~(u64)vol->cluster_size_mask;
/*
* If the write goes beyond the allocated size, extend the allocation
* to cover the whole of the write, rounded up to the nearest cluster.
*/
read_lock_irqsave(&ni->size_lock, flags);
ll = ni->allocated_size;
read_unlock_irqrestore(&ni->size_lock, flags);
if (end > ll) {
/*
* Extend the allocation without changing the data size.
* *
* Same as ntfs_fault_in_pages_readable() but operates on an array of iovecs. * Note we ensure the allocation is big enough to at least
* write some data but we do not require the allocation to be
* complete, i.e. it may be partial.
*/ */
static inline void ntfs_fault_in_pages_readable_iovec(const struct iovec *iov, ll = ntfs_attr_extend_allocation(ni, end, -1, pos);
size_t iov_ofs, int bytes) if (likely(ll >= 0)) {
{ BUG_ON(pos >= ll);
do { /* If the extension was partial truncate the write. */
const char __user *buf; if (end > ll) {
unsigned len; ntfs_debug("Truncating write to inode 0x%lx, "
"attribute type 0x%x, because "
buf = iov->iov_base + iov_ofs; "the allocation was only "
len = iov->iov_len - iov_ofs; "partially extended.",
if (len > bytes) vi->i_ino, (unsigned)
len = bytes; le32_to_cpu(ni->type));
ntfs_fault_in_pages_readable(buf, len); *count = ll - pos;
bytes -= len; }
iov++; } else {
iov_ofs = 0; err = ll;
} while (bytes); read_lock_irqsave(&ni->size_lock, flags);
ll = ni->allocated_size;
read_unlock_irqrestore(&ni->size_lock, flags);
/* Perform a partial write if possible or fail. */
if (pos < ll) {
ntfs_debug("Truncating write to inode 0x%lx "
"attribute type 0x%x, because "
"extending the allocation "
"failed (error %d).",
vi->i_ino, (unsigned)
le32_to_cpu(ni->type),
(int)-err);
*count = ll - pos;
} else {
if (err != -ENOSPC)
ntfs_error(vi->i_sb, "Cannot perform "
"write to inode "
"0x%lx, attribute "
"type 0x%x, because "
"extending the "
"allocation failed "
"(error %ld).",
vi->i_ino, (unsigned)
le32_to_cpu(ni->type),
(long)-err);
else
ntfs_debug("Cannot perform write to "
"inode 0x%lx, "
"attribute type 0x%x, "
"because there is not "
"space left.",
vi->i_ino, (unsigned)
le32_to_cpu(ni->type));
goto out;
}
}
}
/*
* If the write starts beyond the initialized size, extend it up to the
* beginning of the write and initialize all non-sparse space between
* the old initialized size and the new one. This automatically also
* increments the vfs inode->i_size to keep it above or equal to the
* initialized_size.
*/
read_lock_irqsave(&ni->size_lock, flags);
ll = ni->initialized_size;
read_unlock_irqrestore(&ni->size_lock, flags);
if (pos > ll) {
/*
* Wait for ongoing direct i/o to complete before proceeding.
* New direct i/o cannot start as we hold i_mutex.
*/
inode_dio_wait(vi);
err = ntfs_attr_extend_initialized(ni, pos);
if (unlikely(err < 0))
ntfs_error(vi->i_sb, "Cannot perform write to inode "
"0x%lx, attribute type 0x%x, because "
"extending the initialized size "
"failed (error %d).", vi->i_ino,
(unsigned)le32_to_cpu(ni->type),
(int)-err);
}
out:
return err;
} }
/** /**
...@@ -421,8 +527,8 @@ static inline int __ntfs_grab_cache_pages(struct address_space *mapping, ...@@ -421,8 +527,8 @@ static inline int __ntfs_grab_cache_pages(struct address_space *mapping,
goto err_out; goto err_out;
} }
} }
err = add_to_page_cache_lru(*cached_page, mapping, index, err = add_to_page_cache_lru(*cached_page, mapping,
GFP_KERNEL); index, GFP_KERNEL);
if (unlikely(err)) { if (unlikely(err)) {
if (err == -EEXIST) if (err == -EEXIST)
continue; continue;
...@@ -1268,180 +1374,6 @@ static int ntfs_prepare_pages_for_non_resident_write(struct page **pages, ...@@ -1268,180 +1374,6 @@ static int ntfs_prepare_pages_for_non_resident_write(struct page **pages,
return err; return err;
} }
/*
* Copy as much as we can into the pages and return the number of bytes which
* were successfully copied. If a fault is encountered then clear the pages
* out to (ofs + bytes) and return the number of bytes which were copied.
*/
static inline size_t ntfs_copy_from_user(struct page **pages,
unsigned nr_pages, unsigned ofs, const char __user *buf,
size_t bytes)
{
struct page **last_page = pages + nr_pages;
char *addr;
size_t total = 0;
unsigned len;
int left;
do {
len = PAGE_CACHE_SIZE - ofs;
if (len > bytes)
len = bytes;
addr = kmap_atomic(*pages);
left = __copy_from_user_inatomic(addr + ofs, buf, len);
kunmap_atomic(addr);
if (unlikely(left)) {
/* Do it the slow way. */
addr = kmap(*pages);
left = __copy_from_user(addr + ofs, buf, len);
kunmap(*pages);
if (unlikely(left))
goto err_out;
}
total += len;
bytes -= len;
if (!bytes)
break;
buf += len;
ofs = 0;
} while (++pages < last_page);
out:
return total;
err_out:
total += len - left;
/* Zero the rest of the target like __copy_from_user(). */
while (++pages < last_page) {
bytes -= len;
if (!bytes)
break;
len = PAGE_CACHE_SIZE;
if (len > bytes)
len = bytes;
zero_user(*pages, 0, len);
}
goto out;
}
static size_t __ntfs_copy_from_user_iovec_inatomic(char *vaddr,
const struct iovec *iov, size_t iov_ofs, size_t bytes)
{
size_t total = 0;
while (1) {
const char __user *buf = iov->iov_base + iov_ofs;
unsigned len;
size_t left;
len = iov->iov_len - iov_ofs;
if (len > bytes)
len = bytes;
left = __copy_from_user_inatomic(vaddr, buf, len);
total += len;
bytes -= len;
vaddr += len;
if (unlikely(left)) {
total -= left;
break;
}
if (!bytes)
break;
iov++;
iov_ofs = 0;
}
return total;
}
static inline void ntfs_set_next_iovec(const struct iovec **iovp,
size_t *iov_ofsp, size_t bytes)
{
const struct iovec *iov = *iovp;
size_t iov_ofs = *iov_ofsp;
while (bytes) {
unsigned len;
len = iov->iov_len - iov_ofs;
if (len > bytes)
len = bytes;
bytes -= len;
iov_ofs += len;
if (iov->iov_len == iov_ofs) {
iov++;
iov_ofs = 0;
}
}
*iovp = iov;
*iov_ofsp = iov_ofs;
}
/*
* This has the same side-effects and return value as ntfs_copy_from_user().
* The difference is that on a fault we need to memset the remainder of the
* pages (out to offset + bytes), to emulate ntfs_copy_from_user()'s
* single-segment behaviour.
*
* We call the same helper (__ntfs_copy_from_user_iovec_inatomic()) both when
* atomic and when not atomic. This is ok because it calls
* __copy_from_user_inatomic() and it is ok to call this when non-atomic. In
* fact, the only difference between __copy_from_user_inatomic() and
* __copy_from_user() is that the latter calls might_sleep() and the former
* should not zero the tail of the buffer on error. And on many architectures
* __copy_from_user_inatomic() is just defined to __copy_from_user() so it
* makes no difference at all on those architectures.
*/
static inline size_t ntfs_copy_from_user_iovec(struct page **pages,
unsigned nr_pages, unsigned ofs, const struct iovec **iov,
size_t *iov_ofs, size_t bytes)
{
struct page **last_page = pages + nr_pages;
char *addr;
size_t copied, len, total = 0;
do {
len = PAGE_CACHE_SIZE - ofs;
if (len > bytes)
len = bytes;
addr = kmap_atomic(*pages);
copied = __ntfs_copy_from_user_iovec_inatomic(addr + ofs,
*iov, *iov_ofs, len);
kunmap_atomic(addr);
if (unlikely(copied != len)) {
/* Do it the slow way. */
addr = kmap(*pages);
copied = __ntfs_copy_from_user_iovec_inatomic(addr +
ofs, *iov, *iov_ofs, len);
if (unlikely(copied != len))
goto err_out;
kunmap(*pages);
}
total += len;
ntfs_set_next_iovec(iov, iov_ofs, len);
bytes -= len;
if (!bytes)
break;
ofs = 0;
} while (++pages < last_page);
out:
return total;
err_out:
BUG_ON(copied > len);
/* Zero the rest of the target like __copy_from_user(). */
memset(addr + ofs + copied, 0, len - copied);
kunmap(*pages);
total += copied;
ntfs_set_next_iovec(iov, iov_ofs, copied);
while (++pages < last_page) {
bytes -= len;
if (!bytes)
break;
len = PAGE_CACHE_SIZE;
if (len > bytes)
len = bytes;
zero_user(*pages, 0, len);
}
goto out;
}
static inline void ntfs_flush_dcache_pages(struct page **pages, static inline void ntfs_flush_dcache_pages(struct page **pages,
unsigned nr_pages) unsigned nr_pages)
{ {
...@@ -1762,86 +1694,83 @@ static int ntfs_commit_pages_after_write(struct page **pages, ...@@ -1762,86 +1694,83 @@ static int ntfs_commit_pages_after_write(struct page **pages,
return err; return err;
} }
static void ntfs_write_failed(struct address_space *mapping, loff_t to) /*
* Copy as much as we can into the pages and return the number of bytes which
* were successfully copied. If a fault is encountered then clear the pages
* out to (ofs + bytes) and return the number of bytes which were copied.
*/
static size_t ntfs_copy_from_user_iter(struct page **pages, unsigned nr_pages,
unsigned ofs, struct iov_iter *i, size_t bytes)
{ {
struct inode *inode = mapping->host; struct page **last_page = pages + nr_pages;
size_t total = 0;
struct iov_iter data = *i;
unsigned len, copied;
if (to > inode->i_size) { do {
truncate_pagecache(inode, inode->i_size); len = PAGE_CACHE_SIZE - ofs;
ntfs_truncate_vfs(inode); if (len > bytes)
} len = bytes;
copied = iov_iter_copy_from_user_atomic(*pages, &data, ofs,
len);
total += copied;
bytes -= copied;
if (!bytes)
break;
iov_iter_advance(&data, copied);
if (copied < len)
goto err;
ofs = 0;
} while (++pages < last_page);
out:
return total;
err:
/* Zero the rest of the target like __copy_from_user(). */
len = PAGE_CACHE_SIZE - copied;
do {
if (len > bytes)
len = bytes;
zero_user(*pages, copied, len);
bytes -= len;
copied = 0;
len = PAGE_CACHE_SIZE;
} while (++pages < last_page);
goto out;
} }
/** /**
* ntfs_file_buffered_write - * ntfs_perform_write - perform buffered write to a file
* * @file: file to write to
* Locking: The vfs is holding ->i_mutex on the inode. * @i: iov_iter with data to write
* @pos: byte offset in file at which to begin writing to
*/ */
static ssize_t ntfs_file_buffered_write(struct kiocb *iocb, static ssize_t ntfs_perform_write(struct file *file, struct iov_iter *i,
const struct iovec *iov, unsigned long nr_segs, loff_t pos)
loff_t pos, loff_t *ppos, size_t count)
{ {
struct file *file = iocb->ki_filp;
struct address_space *mapping = file->f_mapping; struct address_space *mapping = file->f_mapping;
struct inode *vi = mapping->host; struct inode *vi = mapping->host;
ntfs_inode *ni = NTFS_I(vi); ntfs_inode *ni = NTFS_I(vi);
ntfs_volume *vol = ni->vol; ntfs_volume *vol = ni->vol;
struct page *pages[NTFS_MAX_PAGES_PER_CLUSTER]; struct page *pages[NTFS_MAX_PAGES_PER_CLUSTER];
struct page *cached_page = NULL; struct page *cached_page = NULL;
char __user *buf = NULL;
s64 end, ll;
VCN last_vcn; VCN last_vcn;
LCN lcn; LCN lcn;
unsigned long flags; size_t bytes;
size_t bytes, iov_ofs = 0; /* Offset in the current iovec. */ ssize_t status, written = 0;
ssize_t status, written;
unsigned nr_pages; unsigned nr_pages;
int err;
ntfs_debug("Entering for i_ino 0x%lx, attribute type 0x%x, " ntfs_debug("Entering for i_ino 0x%lx, attribute type 0x%x, pos "
"pos 0x%llx, count 0x%lx.", "0x%llx, count 0x%lx.", vi->i_ino,
vi->i_ino, (unsigned)le32_to_cpu(ni->type), (unsigned)le32_to_cpu(ni->type),
(unsigned long long)pos, (unsigned long)count); (unsigned long long)pos,
if (unlikely(!count)) (unsigned long)iov_iter_count(i));
return 0;
BUG_ON(NInoMstProtected(ni));
/*
* If the attribute is not an index root and it is encrypted or
* compressed, we cannot write to it yet. Note we need to check for
* AT_INDEX_ALLOCATION since this is the type of both directory and
* index inodes.
*/
if (ni->type != AT_INDEX_ALLOCATION) {
/* If file is encrypted, deny access, just like NT4. */
if (NInoEncrypted(ni)) {
/*
* Reminder for later: Encrypted files are _always_
* non-resident so that the content can always be
* encrypted.
*/
ntfs_debug("Denying write access to encrypted file.");
return -EACCES;
}
if (NInoCompressed(ni)) {
/* Only unnamed $DATA attribute can be compressed. */
BUG_ON(ni->type != AT_DATA);
BUG_ON(ni->name_len);
/*
* Reminder for later: If resident, the data is not
* actually compressed. Only on the switch to non-
* resident does compression kick in. This is in
* contrast to encrypted files (see above).
*/
ntfs_error(vi->i_sb, "Writing to compressed files is "
"not implemented yet. Sorry.");
return -EOPNOTSUPP;
}
}
/* /*
* If a previous ntfs_truncate() failed, repeat it and abort if it * If a previous ntfs_truncate() failed, repeat it and abort if it
* fails again. * fails again.
*/ */
if (unlikely(NInoTruncateFailed(ni))) { if (unlikely(NInoTruncateFailed(ni))) {
int err;
inode_dio_wait(vi); inode_dio_wait(vi);
err = ntfs_truncate(vi); err = ntfs_truncate(vi);
if (err || NInoTruncateFailed(ni)) { if (err || NInoTruncateFailed(ni)) {
...@@ -1855,81 +1784,6 @@ static ssize_t ntfs_file_buffered_write(struct kiocb *iocb, ...@@ -1855,81 +1784,6 @@ static ssize_t ntfs_file_buffered_write(struct kiocb *iocb,
return err; return err;
} }
} }
/* The first byte after the write. */
end = pos + count;
/*
* If the write goes beyond the allocated size, extend the allocation
* to cover the whole of the write, rounded up to the nearest cluster.
*/
read_lock_irqsave(&ni->size_lock, flags);
ll = ni->allocated_size;
read_unlock_irqrestore(&ni->size_lock, flags);
if (end > ll) {
/* Extend the allocation without changing the data size. */
ll = ntfs_attr_extend_allocation(ni, end, -1, pos);
if (likely(ll >= 0)) {
BUG_ON(pos >= ll);
/* If the extension was partial truncate the write. */
if (end > ll) {
ntfs_debug("Truncating write to inode 0x%lx, "
"attribute type 0x%x, because "
"the allocation was only "
"partially extended.",
vi->i_ino, (unsigned)
le32_to_cpu(ni->type));
end = ll;
count = ll - pos;
}
} else {
err = ll;
read_lock_irqsave(&ni->size_lock, flags);
ll = ni->allocated_size;
read_unlock_irqrestore(&ni->size_lock, flags);
/* Perform a partial write if possible or fail. */
if (pos < ll) {
ntfs_debug("Truncating write to inode 0x%lx, "
"attribute type 0x%x, because "
"extending the allocation "
"failed (error code %i).",
vi->i_ino, (unsigned)
le32_to_cpu(ni->type), err);
end = ll;
count = ll - pos;
} else {
ntfs_error(vol->sb, "Cannot perform write to "
"inode 0x%lx, attribute type "
"0x%x, because extending the "
"allocation failed (error "
"code %i).", vi->i_ino,
(unsigned)
le32_to_cpu(ni->type), err);
return err;
}
}
}
written = 0;
/*
* If the write starts beyond the initialized size, extend it up to the
* beginning of the write and initialize all non-sparse space between
* the old initialized size and the new one. This automatically also
* increments the vfs inode->i_size to keep it above or equal to the
* initialized_size.
*/
read_lock_irqsave(&ni->size_lock, flags);
ll = ni->initialized_size;
read_unlock_irqrestore(&ni->size_lock, flags);
if (pos > ll) {
err = ntfs_attr_extend_initialized(ni, pos);
if (err < 0) {
ntfs_error(vol->sb, "Cannot perform write to inode "
"0x%lx, attribute type 0x%x, because "
"extending the initialized size "
"failed (error code %i).", vi->i_ino,
(unsigned)le32_to_cpu(ni->type), err);
status = err;
goto err_out;
}
}
/* /*
* Determine the number of pages per cluster for non-resident * Determine the number of pages per cluster for non-resident
* attributes. * attributes.
...@@ -1937,10 +1791,7 @@ static ssize_t ntfs_file_buffered_write(struct kiocb *iocb, ...@@ -1937,10 +1791,7 @@ static ssize_t ntfs_file_buffered_write(struct kiocb *iocb,
nr_pages = 1; nr_pages = 1;
if (vol->cluster_size > PAGE_CACHE_SIZE && NInoNonResident(ni)) if (vol->cluster_size > PAGE_CACHE_SIZE && NInoNonResident(ni))
nr_pages = vol->cluster_size >> PAGE_CACHE_SHIFT; nr_pages = vol->cluster_size >> PAGE_CACHE_SHIFT;
/* Finally, perform the actual write. */
last_vcn = -1; last_vcn = -1;
if (likely(nr_segs == 1))
buf = iov->iov_base;
do { do {
VCN vcn; VCN vcn;
pgoff_t idx, start_idx; pgoff_t idx, start_idx;
...@@ -1965,10 +1816,10 @@ static ssize_t ntfs_file_buffered_write(struct kiocb *iocb, ...@@ -1965,10 +1816,10 @@ static ssize_t ntfs_file_buffered_write(struct kiocb *iocb,
vol->cluster_size_bits, false); vol->cluster_size_bits, false);
up_read(&ni->runlist.lock); up_read(&ni->runlist.lock);
if (unlikely(lcn < LCN_HOLE)) { if (unlikely(lcn < LCN_HOLE)) {
status = -EIO;
if (lcn == LCN_ENOMEM) if (lcn == LCN_ENOMEM)
status = -ENOMEM; status = -ENOMEM;
else else {
status = -EIO;
ntfs_error(vol->sb, "Cannot " ntfs_error(vol->sb, "Cannot "
"perform write to " "perform write to "
"inode 0x%lx, " "inode 0x%lx, "
...@@ -1977,6 +1828,7 @@ static ssize_t ntfs_file_buffered_write(struct kiocb *iocb, ...@@ -1977,6 +1828,7 @@ static ssize_t ntfs_file_buffered_write(struct kiocb *iocb,
"is corrupt.", "is corrupt.",
vi->i_ino, (unsigned) vi->i_ino, (unsigned)
le32_to_cpu(ni->type)); le32_to_cpu(ni->type));
}
break; break;
} }
if (lcn == LCN_HOLE) { if (lcn == LCN_HOLE) {
...@@ -1989,8 +1841,9 @@ static ssize_t ntfs_file_buffered_write(struct kiocb *iocb, ...@@ -1989,8 +1841,9 @@ static ssize_t ntfs_file_buffered_write(struct kiocb *iocb,
} }
} }
} }
if (bytes > count) if (bytes > iov_iter_count(i))
bytes = count; bytes = iov_iter_count(i);
again:
/* /*
* Bring in the user page(s) that we will copy from _first_. * Bring in the user page(s) that we will copy from _first_.
* Otherwise there is a nasty deadlock on copying from the same * Otherwise there is a nasty deadlock on copying from the same
...@@ -1999,10 +1852,10 @@ static ssize_t ntfs_file_buffered_write(struct kiocb *iocb, ...@@ -1999,10 +1852,10 @@ static ssize_t ntfs_file_buffered_write(struct kiocb *iocb,
* pages being swapped out between us bringing them into memory * pages being swapped out between us bringing them into memory
* and doing the actual copying. * and doing the actual copying.
*/ */
if (likely(nr_segs == 1)) if (unlikely(iov_iter_fault_in_multipages_readable(i, bytes))) {
ntfs_fault_in_pages_readable(buf, bytes); status = -EFAULT;
else break;
ntfs_fault_in_pages_readable_iovec(iov, iov_ofs, bytes); }
/* Get and lock @do_pages starting at index @start_idx. */ /* Get and lock @do_pages starting at index @start_idx. */
status = __ntfs_grab_cache_pages(mapping, start_idx, do_pages, status = __ntfs_grab_cache_pages(mapping, start_idx, do_pages,
pages, &cached_page); pages, &cached_page);
...@@ -2018,56 +1871,57 @@ static ssize_t ntfs_file_buffered_write(struct kiocb *iocb, ...@@ -2018,56 +1871,57 @@ static ssize_t ntfs_file_buffered_write(struct kiocb *iocb,
status = ntfs_prepare_pages_for_non_resident_write( status = ntfs_prepare_pages_for_non_resident_write(
pages, do_pages, pos, bytes); pages, do_pages, pos, bytes);
if (unlikely(status)) { if (unlikely(status)) {
loff_t i_size;
do { do {
unlock_page(pages[--do_pages]); unlock_page(pages[--do_pages]);
page_cache_release(pages[do_pages]); page_cache_release(pages[do_pages]);
} while (do_pages); } while (do_pages);
/*
* The write preparation may have instantiated
* allocated space outside i_size. Trim this
* off again. We can ignore any errors in this
* case as we will just be waisting a bit of
* allocated space, which is not a disaster.
*/
i_size = i_size_read(vi);
if (pos + bytes > i_size) {
ntfs_write_failed(mapping, pos + bytes);
}
break; break;
} }
} }
u = (pos >> PAGE_CACHE_SHIFT) - pages[0]->index; u = (pos >> PAGE_CACHE_SHIFT) - pages[0]->index;
if (likely(nr_segs == 1)) { copied = ntfs_copy_from_user_iter(pages + u, do_pages - u, ofs,
copied = ntfs_copy_from_user(pages + u, do_pages - u, i, bytes);
ofs, buf, bytes);
buf += copied;
} else
copied = ntfs_copy_from_user_iovec(pages + u,
do_pages - u, ofs, &iov, &iov_ofs,
bytes);
ntfs_flush_dcache_pages(pages + u, do_pages - u); ntfs_flush_dcache_pages(pages + u, do_pages - u);
status = ntfs_commit_pages_after_write(pages, do_pages, pos, status = 0;
bytes); if (likely(copied == bytes)) {
if (likely(!status)) { status = ntfs_commit_pages_after_write(pages, do_pages,
written += copied; pos, bytes);
count -= copied; if (!status)
pos += copied; status = bytes;
if (unlikely(copied != bytes))
status = -EFAULT;
} }
do { do {
unlock_page(pages[--do_pages]); unlock_page(pages[--do_pages]);
page_cache_release(pages[do_pages]); page_cache_release(pages[do_pages]);
} while (do_pages); } while (do_pages);
if (unlikely(status)) if (unlikely(status < 0))
break; break;
balance_dirty_pages_ratelimited(mapping); copied = status;
cond_resched(); cond_resched();
} while (count); if (unlikely(!copied)) {
err_out: size_t sc;
*ppos = pos;
/*
* We failed to copy anything. Fall back to single
* segment length write.
*
* This is needed to avoid possible livelock in the
* case that all segments in the iov cannot be copied
* at once without a pagefault.
*/
sc = iov_iter_single_seg_count(i);
if (bytes > sc)
bytes = sc;
goto again;
}
iov_iter_advance(i, copied);
pos += copied;
written += copied;
balance_dirty_pages_ratelimited(mapping);
if (fatal_signal_pending(current)) {
status = -EINTR;
break;
}
} while (iov_iter_count(i));
if (cached_page) if (cached_page)
page_cache_release(cached_page); page_cache_release(cached_page);
ntfs_debug("Done. Returning %s (written 0x%lx, status %li).", ntfs_debug("Done. Returning %s (written 0x%lx, status %li).",
...@@ -2077,59 +1931,56 @@ static ssize_t ntfs_file_buffered_write(struct kiocb *iocb, ...@@ -2077,59 +1931,56 @@ static ssize_t ntfs_file_buffered_write(struct kiocb *iocb,
} }
/** /**
* ntfs_file_aio_write_nolock - * ntfs_file_write_iter_nolock - write data to a file
* @iocb: IO state structure (file, offset, etc.)
* @from: iov_iter with data to write
*
* Basically the same as __generic_file_write_iter() except that it ends
* up calling ntfs_perform_write() instead of generic_perform_write() and that
* O_DIRECT is not implemented.
*/ */
static ssize_t ntfs_file_aio_write_nolock(struct kiocb *iocb, static ssize_t ntfs_file_write_iter_nolock(struct kiocb *iocb,
const struct iovec *iov, unsigned long nr_segs, loff_t *ppos) struct iov_iter *from)
{ {
struct file *file = iocb->ki_filp; struct file *file = iocb->ki_filp;
struct address_space *mapping = file->f_mapping; loff_t pos = iocb->ki_pos;
struct inode *inode = mapping->host; ssize_t written = 0;
loff_t pos; ssize_t err;
size_t count; /* after file limit checks */ size_t count = iov_iter_count(from);
ssize_t written, err;
count = iov_length(iov, nr_segs); err = ntfs_prepare_file_for_write(file, &pos, &count);
pos = *ppos; if (count && !err) {
/* We can write back this queue in page reclaim. */ iov_iter_truncate(from, count);
current->backing_dev_info = inode_to_bdi(inode); written = ntfs_perform_write(file, from, pos);
written = 0; if (likely(written >= 0))
err = generic_write_checks(file, &pos, &count, S_ISBLK(inode->i_mode)); iocb->ki_pos = pos + written;
if (err) }
goto out;
if (!count)
goto out;
err = file_remove_suid(file);
if (err)
goto out;
err = file_update_time(file);
if (err)
goto out;
written = ntfs_file_buffered_write(iocb, iov, nr_segs, pos, ppos,
count);
out:
current->backing_dev_info = NULL; current->backing_dev_info = NULL;
return written ? written : err; return written ? written : err;
} }
/** /**
* ntfs_file_aio_write - * ntfs_file_write_iter - simple wrapper for ntfs_file_write_iter_nolock()
* @iocb: IO state structure
* @from: iov_iter with data to write
*
* Basically the same as generic_file_write_iter() except that it ends up
* calling ntfs_file_write_iter_nolock() instead of
* __generic_file_write_iter().
*/ */
static ssize_t ntfs_file_aio_write(struct kiocb *iocb, const struct iovec *iov, static ssize_t ntfs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
unsigned long nr_segs, loff_t pos)
{ {
struct file *file = iocb->ki_filp; struct file *file = iocb->ki_filp;
struct address_space *mapping = file->f_mapping; struct inode *vi = file_inode(file);
struct inode *inode = mapping->host;
ssize_t ret; ssize_t ret;
BUG_ON(iocb->ki_pos != pos); mutex_lock(&vi->i_mutex);
ret = ntfs_file_write_iter_nolock(iocb, from);
mutex_lock(&inode->i_mutex); mutex_unlock(&vi->i_mutex);
ret = ntfs_file_aio_write_nolock(iocb, iov, nr_segs, &iocb->ki_pos);
mutex_unlock(&inode->i_mutex);
if (ret > 0) { if (ret > 0) {
int err = generic_write_sync(file, iocb->ki_pos - ret, ret); ssize_t err;
err = generic_write_sync(file, iocb->ki_pos - ret, ret);
if (err < 0) if (err < 0)
ret = err; ret = err;
} }
...@@ -2197,37 +2048,17 @@ static int ntfs_file_fsync(struct file *filp, loff_t start, loff_t end, ...@@ -2197,37 +2048,17 @@ static int ntfs_file_fsync(struct file *filp, loff_t start, loff_t end,
#endif /* NTFS_RW */ #endif /* NTFS_RW */
const struct file_operations ntfs_file_ops = { const struct file_operations ntfs_file_ops = {
.llseek = generic_file_llseek, /* Seek inside file. */ .llseek = generic_file_llseek,
.read = new_sync_read, /* Read from file. */ .read = new_sync_read,
.read_iter = generic_file_read_iter, /* Async read from file. */ .read_iter = generic_file_read_iter,
#ifdef NTFS_RW #ifdef NTFS_RW
.write = do_sync_write, /* Write to file. */ .write = new_sync_write,
.aio_write = ntfs_file_aio_write, /* Async write to file. */ .write_iter = ntfs_file_write_iter,
/*.release = ,*/ /* Last file is closed. See .fsync = ntfs_file_fsync,
fs/ext2/file.c::
ext2_release_file() for
how to use this to discard
preallocated space for
write opened files. */
.fsync = ntfs_file_fsync, /* Sync a file to disk. */
/*.aio_fsync = ,*/ /* Sync all outstanding async
i/o operations on a
kiocb. */
#endif /* NTFS_RW */ #endif /* NTFS_RW */
/*.ioctl = ,*/ /* Perform function on the .mmap = generic_file_mmap,
mounted filesystem. */ .open = ntfs_file_open,
.mmap = generic_file_mmap, /* Mmap file. */ .splice_read = generic_file_splice_read,
.open = ntfs_file_open, /* Open file. */
.splice_read = generic_file_splice_read /* Zero-copy data send with
the data source being on
the ntfs partition. We do
not need to care about the
data destination. */
/*.sendpage = ,*/ /* Zero-copy data send with
the data destination being
on the ntfs partition. We
do not need to care about
the data source. */
}; };
const struct inode_operations ntfs_file_inode_ops = { const struct inode_operations ntfs_file_inode_ops = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment