Merge branch 'for-linus' into for-next
This commit is contained in:
commit
337ccfce23
|
@ -12,7 +12,7 @@ DOCBOOKS := z8530book.xml \
|
|||
kernel-api.xml filesystems.xml lsm.xml kgdb.xml \
|
||||
gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml \
|
||||
genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml \
|
||||
80211.xml sh.xml regulator.xml w1.xml \
|
||||
sh.xml regulator.xml w1.xml \
|
||||
writing_musb_glue_layer.xml iio.xml
|
||||
|
||||
ifeq ($(DOCBOOKS),)
|
||||
|
|
|
@ -151,7 +151,7 @@ bool ether_addr_equal(const u8 *addr1, const u8 *addr2)
|
|||
#else
|
||||
const u16 *a = (const u16 *)addr1;
|
||||
const u16 *b = (const u16 *)addr2;
|
||||
return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2])) != 0;
|
||||
return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2])) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
2
Makefile
2
Makefile
|
@ -1,7 +1,7 @@
|
|||
VERSION = 4
|
||||
PATCHLEVEL = 10
|
||||
SUBLEVEL = 0
|
||||
EXTRAVERSION = -rc1
|
||||
EXTRAVERSION = -rc2
|
||||
NAME = Roaring Lionus
|
||||
|
||||
# *DOCUMENTATION*
|
||||
|
|
|
@ -139,6 +139,19 @@ static __always_inline void __clear_bit(long nr, volatile unsigned long *addr)
|
|||
asm volatile("btr %1,%0" : ADDR : "Ir" (nr));
|
||||
}
|
||||
|
||||
static __always_inline bool clear_bit_unlock_is_negative_byte(long nr, volatile unsigned long *addr)
|
||||
{
|
||||
bool negative;
|
||||
asm volatile(LOCK_PREFIX "andb %2,%1\n\t"
|
||||
CC_SET(s)
|
||||
: CC_OUT(s) (negative), ADDR
|
||||
: "ir" ((char) ~(1 << nr)) : "memory");
|
||||
return negative;
|
||||
}
|
||||
|
||||
// Let everybody know we have it
|
||||
#define clear_bit_unlock_is_negative_byte clear_bit_unlock_is_negative_byte
|
||||
|
||||
/*
|
||||
* __clear_bit_unlock - Clears a bit in memory
|
||||
* @nr: Bit to clear
|
||||
|
|
|
@ -1461,16 +1461,25 @@ static int test_acomp(struct crypto_acomp *tfm, struct comp_testvec *ctemplate,
|
|||
for (i = 0; i < ctcount; i++) {
|
||||
unsigned int dlen = COMP_BUF_SIZE;
|
||||
int ilen = ctemplate[i].inlen;
|
||||
void *input_vec;
|
||||
|
||||
input_vec = kmalloc(ilen, GFP_KERNEL);
|
||||
if (!input_vec) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy(input_vec, ctemplate[i].input, ilen);
|
||||
memset(output, 0, dlen);
|
||||
init_completion(&result.completion);
|
||||
sg_init_one(&src, ctemplate[i].input, ilen);
|
||||
sg_init_one(&src, input_vec, ilen);
|
||||
sg_init_one(&dst, output, dlen);
|
||||
|
||||
req = acomp_request_alloc(tfm);
|
||||
if (!req) {
|
||||
pr_err("alg: acomp: request alloc failed for %s\n",
|
||||
algo);
|
||||
kfree(input_vec);
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
@ -1483,6 +1492,7 @@ static int test_acomp(struct crypto_acomp *tfm, struct comp_testvec *ctemplate,
|
|||
if (ret) {
|
||||
pr_err("alg: acomp: compression failed on test %d for %s: ret=%d\n",
|
||||
i + 1, algo, -ret);
|
||||
kfree(input_vec);
|
||||
acomp_request_free(req);
|
||||
goto out;
|
||||
}
|
||||
|
@ -1491,6 +1501,7 @@ static int test_acomp(struct crypto_acomp *tfm, struct comp_testvec *ctemplate,
|
|||
pr_err("alg: acomp: Compression test %d failed for %s: output len = %d\n",
|
||||
i + 1, algo, req->dlen);
|
||||
ret = -EINVAL;
|
||||
kfree(input_vec);
|
||||
acomp_request_free(req);
|
||||
goto out;
|
||||
}
|
||||
|
@ -1500,26 +1511,37 @@ static int test_acomp(struct crypto_acomp *tfm, struct comp_testvec *ctemplate,
|
|||
i + 1, algo);
|
||||
hexdump(output, req->dlen);
|
||||
ret = -EINVAL;
|
||||
kfree(input_vec);
|
||||
acomp_request_free(req);
|
||||
goto out;
|
||||
}
|
||||
|
||||
kfree(input_vec);
|
||||
acomp_request_free(req);
|
||||
}
|
||||
|
||||
for (i = 0; i < dtcount; i++) {
|
||||
unsigned int dlen = COMP_BUF_SIZE;
|
||||
int ilen = dtemplate[i].inlen;
|
||||
void *input_vec;
|
||||
|
||||
input_vec = kmalloc(ilen, GFP_KERNEL);
|
||||
if (!input_vec) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy(input_vec, dtemplate[i].input, ilen);
|
||||
memset(output, 0, dlen);
|
||||
init_completion(&result.completion);
|
||||
sg_init_one(&src, dtemplate[i].input, ilen);
|
||||
sg_init_one(&src, input_vec, ilen);
|
||||
sg_init_one(&dst, output, dlen);
|
||||
|
||||
req = acomp_request_alloc(tfm);
|
||||
if (!req) {
|
||||
pr_err("alg: acomp: request alloc failed for %s\n",
|
||||
algo);
|
||||
kfree(input_vec);
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
@ -1532,6 +1554,7 @@ static int test_acomp(struct crypto_acomp *tfm, struct comp_testvec *ctemplate,
|
|||
if (ret) {
|
||||
pr_err("alg: acomp: decompression failed on test %d for %s: ret=%d\n",
|
||||
i + 1, algo, -ret);
|
||||
kfree(input_vec);
|
||||
acomp_request_free(req);
|
||||
goto out;
|
||||
}
|
||||
|
@ -1540,6 +1563,7 @@ static int test_acomp(struct crypto_acomp *tfm, struct comp_testvec *ctemplate,
|
|||
pr_err("alg: acomp: Decompression test %d failed for %s: output len = %d\n",
|
||||
i + 1, algo, req->dlen);
|
||||
ret = -EINVAL;
|
||||
kfree(input_vec);
|
||||
acomp_request_free(req);
|
||||
goto out;
|
||||
}
|
||||
|
@ -1549,10 +1573,12 @@ static int test_acomp(struct crypto_acomp *tfm, struct comp_testvec *ctemplate,
|
|||
i + 1, algo);
|
||||
hexdump(output, req->dlen);
|
||||
ret = -EINVAL;
|
||||
kfree(input_vec);
|
||||
acomp_request_free(req);
|
||||
goto out;
|
||||
}
|
||||
|
||||
kfree(input_vec);
|
||||
acomp_request_free(req);
|
||||
}
|
||||
|
||||
|
|
249
fs/dax.c
249
fs/dax.c
|
@ -451,16 +451,37 @@ void dax_wake_mapping_entry_waiter(struct address_space *mapping,
|
|||
__wake_up(wq, TASK_NORMAL, wake_all ? 0 : 1, &key);
|
||||
}
|
||||
|
||||
static int __dax_invalidate_mapping_entry(struct address_space *mapping,
|
||||
pgoff_t index, bool trunc)
|
||||
{
|
||||
int ret = 0;
|
||||
void *entry;
|
||||
struct radix_tree_root *page_tree = &mapping->page_tree;
|
||||
|
||||
spin_lock_irq(&mapping->tree_lock);
|
||||
entry = get_unlocked_mapping_entry(mapping, index, NULL);
|
||||
if (!entry || !radix_tree_exceptional_entry(entry))
|
||||
goto out;
|
||||
if (!trunc &&
|
||||
(radix_tree_tag_get(page_tree, index, PAGECACHE_TAG_DIRTY) ||
|
||||
radix_tree_tag_get(page_tree, index, PAGECACHE_TAG_TOWRITE)))
|
||||
goto out;
|
||||
radix_tree_delete(page_tree, index);
|
||||
mapping->nrexceptional--;
|
||||
ret = 1;
|
||||
out:
|
||||
put_unlocked_mapping_entry(mapping, index, entry);
|
||||
spin_unlock_irq(&mapping->tree_lock);
|
||||
return ret;
|
||||
}
|
||||
/*
|
||||
* Delete exceptional DAX entry at @index from @mapping. Wait for radix tree
|
||||
* entry to get unlocked before deleting it.
|
||||
*/
|
||||
int dax_delete_mapping_entry(struct address_space *mapping, pgoff_t index)
|
||||
{
|
||||
void *entry;
|
||||
int ret = __dax_invalidate_mapping_entry(mapping, index, true);
|
||||
|
||||
spin_lock_irq(&mapping->tree_lock);
|
||||
entry = get_unlocked_mapping_entry(mapping, index, NULL);
|
||||
/*
|
||||
* This gets called from truncate / punch_hole path. As such, the caller
|
||||
* must hold locks protecting against concurrent modifications of the
|
||||
|
@ -468,16 +489,46 @@ int dax_delete_mapping_entry(struct address_space *mapping, pgoff_t index)
|
|||
* caller has seen exceptional entry for this index, we better find it
|
||||
* at that index as well...
|
||||
*/
|
||||
if (WARN_ON_ONCE(!entry || !radix_tree_exceptional_entry(entry))) {
|
||||
spin_unlock_irq(&mapping->tree_lock);
|
||||
return 0;
|
||||
}
|
||||
radix_tree_delete(&mapping->page_tree, index);
|
||||
mapping->nrexceptional--;
|
||||
spin_unlock_irq(&mapping->tree_lock);
|
||||
dax_wake_mapping_entry_waiter(mapping, index, entry, true);
|
||||
WARN_ON_ONCE(!ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 1;
|
||||
/*
|
||||
* Invalidate exceptional DAX entry if easily possible. This handles DAX
|
||||
* entries for invalidate_inode_pages() so we evict the entry only if we can
|
||||
* do so without blocking.
|
||||
*/
|
||||
int dax_invalidate_mapping_entry(struct address_space *mapping, pgoff_t index)
|
||||
{
|
||||
int ret = 0;
|
||||
void *entry, **slot;
|
||||
struct radix_tree_root *page_tree = &mapping->page_tree;
|
||||
|
||||
spin_lock_irq(&mapping->tree_lock);
|
||||
entry = __radix_tree_lookup(page_tree, index, NULL, &slot);
|
||||
if (!entry || !radix_tree_exceptional_entry(entry) ||
|
||||
slot_locked(mapping, slot))
|
||||
goto out;
|
||||
if (radix_tree_tag_get(page_tree, index, PAGECACHE_TAG_DIRTY) ||
|
||||
radix_tree_tag_get(page_tree, index, PAGECACHE_TAG_TOWRITE))
|
||||
goto out;
|
||||
radix_tree_delete(page_tree, index);
|
||||
mapping->nrexceptional--;
|
||||
ret = 1;
|
||||
out:
|
||||
spin_unlock_irq(&mapping->tree_lock);
|
||||
if (ret)
|
||||
dax_wake_mapping_entry_waiter(mapping, index, entry, true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Invalidate exceptional DAX entry if it is clean.
|
||||
*/
|
||||
int dax_invalidate_mapping_entry_sync(struct address_space *mapping,
|
||||
pgoff_t index)
|
||||
{
|
||||
return __dax_invalidate_mapping_entry(mapping, index, false);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -488,15 +539,16 @@ int dax_delete_mapping_entry(struct address_space *mapping, pgoff_t index)
|
|||
* otherwise it will simply fall out of the page cache under memory
|
||||
* pressure without ever having been dirtied.
|
||||
*/
|
||||
static int dax_load_hole(struct address_space *mapping, void *entry,
|
||||
static int dax_load_hole(struct address_space *mapping, void **entry,
|
||||
struct vm_fault *vmf)
|
||||
{
|
||||
struct page *page;
|
||||
int ret;
|
||||
|
||||
/* Hole page already exists? Return it... */
|
||||
if (!radix_tree_exceptional_entry(entry)) {
|
||||
vmf->page = entry;
|
||||
return VM_FAULT_LOCKED;
|
||||
if (!radix_tree_exceptional_entry(*entry)) {
|
||||
page = *entry;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* This will replace locked radix tree entry with a hole page */
|
||||
|
@ -504,8 +556,17 @@ static int dax_load_hole(struct address_space *mapping, void *entry,
|
|||
vmf->gfp_mask | __GFP_ZERO);
|
||||
if (!page)
|
||||
return VM_FAULT_OOM;
|
||||
out:
|
||||
vmf->page = page;
|
||||
return VM_FAULT_LOCKED;
|
||||
ret = finish_fault(vmf);
|
||||
vmf->page = NULL;
|
||||
*entry = page;
|
||||
if (!ret) {
|
||||
/* Grab reference for PTE that is now referencing the page */
|
||||
get_page(page);
|
||||
return VM_FAULT_NOPAGE;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int copy_user_dax(struct block_device *bdev, sector_t sector, size_t size,
|
||||
|
@ -934,6 +995,17 @@ dax_iomap_actor(struct inode *inode, loff_t pos, loff_t length, void *data,
|
|||
if (WARN_ON_ONCE(iomap->type != IOMAP_MAPPED))
|
||||
return -EIO;
|
||||
|
||||
/*
|
||||
* Write can allocate block for an area which has a hole page mapped
|
||||
* into page tables. We have to tear down these mappings so that data
|
||||
* written by write(2) is visible in mmap.
|
||||
*/
|
||||
if ((iomap->flags & IOMAP_F_NEW) && inode->i_mapping->nrpages) {
|
||||
invalidate_inode_pages2_range(inode->i_mapping,
|
||||
pos >> PAGE_SHIFT,
|
||||
(end - 1) >> PAGE_SHIFT);
|
||||
}
|
||||
|
||||
while (pos < end) {
|
||||
unsigned offset = pos & (PAGE_SIZE - 1);
|
||||
struct blk_dax_ctl dax = { 0 };
|
||||
|
@ -992,23 +1064,6 @@ dax_iomap_rw(struct kiocb *iocb, struct iov_iter *iter,
|
|||
if (iov_iter_rw(iter) == WRITE)
|
||||
flags |= IOMAP_WRITE;
|
||||
|
||||
/*
|
||||
* Yes, even DAX files can have page cache attached to them: A zeroed
|
||||
* page is inserted into the pagecache when we have to serve a write
|
||||
* fault on a hole. It should never be dirtied and can simply be
|
||||
* dropped from the pagecache once we get real data for the page.
|
||||
*
|
||||
* XXX: This is racy against mmap, and there's nothing we can do about
|
||||
* it. We'll eventually need to shift this down even further so that
|
||||
* we can check if we allocated blocks over a hole first.
|
||||
*/
|
||||
if (mapping->nrpages) {
|
||||
ret = invalidate_inode_pages2_range(mapping,
|
||||
pos >> PAGE_SHIFT,
|
||||
(pos + iov_iter_count(iter) - 1) >> PAGE_SHIFT);
|
||||
WARN_ON_ONCE(ret);
|
||||
}
|
||||
|
||||
while (iov_iter_count(iter)) {
|
||||
ret = iomap_apply(inode, pos, iov_iter_count(iter), flags, ops,
|
||||
iter, dax_iomap_actor);
|
||||
|
@ -1023,6 +1078,15 @@ dax_iomap_rw(struct kiocb *iocb, struct iov_iter *iter,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(dax_iomap_rw);
|
||||
|
||||
static int dax_fault_return(int error)
|
||||
{
|
||||
if (error == 0)
|
||||
return VM_FAULT_NOPAGE;
|
||||
if (error == -ENOMEM)
|
||||
return VM_FAULT_OOM;
|
||||
return VM_FAULT_SIGBUS;
|
||||
}
|
||||
|
||||
/**
|
||||
* dax_iomap_fault - handle a page fault on a DAX file
|
||||
* @vma: The virtual memory area where the fault occurred
|
||||
|
@ -1055,12 +1119,6 @@ int dax_iomap_fault(struct vm_area_struct *vma, struct vm_fault *vmf,
|
|||
if (pos >= i_size_read(inode))
|
||||
return VM_FAULT_SIGBUS;
|
||||
|
||||
entry = grab_mapping_entry(mapping, vmf->pgoff, 0);
|
||||
if (IS_ERR(entry)) {
|
||||
error = PTR_ERR(entry);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((vmf->flags & FAULT_FLAG_WRITE) && !vmf->cow_page)
|
||||
flags |= IOMAP_WRITE;
|
||||
|
||||
|
@ -1071,9 +1129,15 @@ int dax_iomap_fault(struct vm_area_struct *vma, struct vm_fault *vmf,
|
|||
*/
|
||||
error = ops->iomap_begin(inode, pos, PAGE_SIZE, flags, &iomap);
|
||||
if (error)
|
||||
goto unlock_entry;
|
||||
return dax_fault_return(error);
|
||||
if (WARN_ON_ONCE(iomap.offset + iomap.length < pos + PAGE_SIZE)) {
|
||||
error = -EIO; /* fs corruption? */
|
||||
vmf_ret = dax_fault_return(-EIO); /* fs corruption? */
|
||||
goto finish_iomap;
|
||||
}
|
||||
|
||||
entry = grab_mapping_entry(mapping, vmf->pgoff, 0);
|
||||
if (IS_ERR(entry)) {
|
||||
vmf_ret = dax_fault_return(PTR_ERR(entry));
|
||||
goto finish_iomap;
|
||||
}
|
||||
|
||||
|
@ -1096,13 +1160,13 @@ int dax_iomap_fault(struct vm_area_struct *vma, struct vm_fault *vmf,
|
|||
}
|
||||
|
||||
if (error)
|
||||
goto finish_iomap;
|
||||
goto error_unlock_entry;
|
||||
|
||||
__SetPageUptodate(vmf->cow_page);
|
||||
vmf_ret = finish_fault(vmf);
|
||||
if (!vmf_ret)
|
||||
vmf_ret = VM_FAULT_DONE_COW;
|
||||
goto finish_iomap;
|
||||
goto unlock_entry;
|
||||
}
|
||||
|
||||
switch (iomap.type) {
|
||||
|
@ -1114,12 +1178,15 @@ int dax_iomap_fault(struct vm_area_struct *vma, struct vm_fault *vmf,
|
|||
}
|
||||
error = dax_insert_mapping(mapping, iomap.bdev, sector,
|
||||
PAGE_SIZE, &entry, vma, vmf);
|
||||
/* -EBUSY is fine, somebody else faulted on the same PTE */
|
||||
if (error == -EBUSY)
|
||||
error = 0;
|
||||
break;
|
||||
case IOMAP_UNWRITTEN:
|
||||
case IOMAP_HOLE:
|
||||
if (!(vmf->flags & FAULT_FLAG_WRITE)) {
|
||||
vmf_ret = dax_load_hole(mapping, entry, vmf);
|
||||
break;
|
||||
vmf_ret = dax_load_hole(mapping, &entry, vmf);
|
||||
goto unlock_entry;
|
||||
}
|
||||
/*FALLTHRU*/
|
||||
default:
|
||||
|
@ -1128,31 +1195,25 @@ int dax_iomap_fault(struct vm_area_struct *vma, struct vm_fault *vmf,
|
|||
break;
|
||||
}
|
||||
|
||||
error_unlock_entry:
|
||||
vmf_ret = dax_fault_return(error) | major;
|
||||
unlock_entry:
|
||||
put_locked_mapping_entry(mapping, vmf->pgoff, entry);
|
||||
finish_iomap:
|
||||
if (ops->iomap_end) {
|
||||
if (error || (vmf_ret & VM_FAULT_ERROR)) {
|
||||
/* keep previous error */
|
||||
ops->iomap_end(inode, pos, PAGE_SIZE, 0, flags,
|
||||
&iomap);
|
||||
} else {
|
||||
error = ops->iomap_end(inode, pos, PAGE_SIZE,
|
||||
PAGE_SIZE, flags, &iomap);
|
||||
}
|
||||
int copied = PAGE_SIZE;
|
||||
|
||||
if (vmf_ret & VM_FAULT_ERROR)
|
||||
copied = 0;
|
||||
/*
|
||||
* The fault is done by now and there's no way back (other
|
||||
* thread may be already happily using PTE we have installed).
|
||||
* Just ignore error from ->iomap_end since we cannot do much
|
||||
* with it.
|
||||
*/
|
||||
ops->iomap_end(inode, pos, PAGE_SIZE, copied, flags, &iomap);
|
||||
}
|
||||
unlock_entry:
|
||||
if (vmf_ret != VM_FAULT_LOCKED || error)
|
||||
put_locked_mapping_entry(mapping, vmf->pgoff, entry);
|
||||
out:
|
||||
if (error == -ENOMEM)
|
||||
return VM_FAULT_OOM | major;
|
||||
/* -EBUSY is fine, somebody else faulted on the same PTE */
|
||||
if (error < 0 && error != -EBUSY)
|
||||
return VM_FAULT_SIGBUS | major;
|
||||
if (vmf_ret) {
|
||||
WARN_ON_ONCE(error); /* -EBUSY from ops->iomap_end? */
|
||||
return vmf_ret;
|
||||
}
|
||||
return VM_FAULT_NOPAGE | major;
|
||||
return vmf_ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dax_iomap_fault);
|
||||
|
||||
|
@ -1276,16 +1337,6 @@ int dax_iomap_pmd_fault(struct vm_area_struct *vma, unsigned long address,
|
|||
if ((pgoff | PG_PMD_COLOUR) > max_pgoff)
|
||||
goto fallback;
|
||||
|
||||
/*
|
||||
* grab_mapping_entry() will make sure we get a 2M empty entry, a DAX
|
||||
* PMD or a HZP entry. If it can't (because a 4k page is already in
|
||||
* the tree, for instance), it will return -EEXIST and we just fall
|
||||
* back to 4k entries.
|
||||
*/
|
||||
entry = grab_mapping_entry(mapping, pgoff, RADIX_DAX_PMD);
|
||||
if (IS_ERR(entry))
|
||||
goto fallback;
|
||||
|
||||
/*
|
||||
* Note that we don't use iomap_apply here. We aren't doing I/O, only
|
||||
* setting up a mapping, so really we're using iomap_begin() as a way
|
||||
|
@ -1294,10 +1345,21 @@ int dax_iomap_pmd_fault(struct vm_area_struct *vma, unsigned long address,
|
|||
pos = (loff_t)pgoff << PAGE_SHIFT;
|
||||
error = ops->iomap_begin(inode, pos, PMD_SIZE, iomap_flags, &iomap);
|
||||
if (error)
|
||||
goto unlock_entry;
|
||||
goto fallback;
|
||||
|
||||
if (iomap.offset + iomap.length < pos + PMD_SIZE)
|
||||
goto finish_iomap;
|
||||
|
||||
/*
|
||||
* grab_mapping_entry() will make sure we get a 2M empty entry, a DAX
|
||||
* PMD or a HZP entry. If it can't (because a 4k page is already in
|
||||
* the tree, for instance), it will return -EEXIST and we just fall
|
||||
* back to 4k entries.
|
||||
*/
|
||||
entry = grab_mapping_entry(mapping, pgoff, RADIX_DAX_PMD);
|
||||
if (IS_ERR(entry))
|
||||
goto finish_iomap;
|
||||
|
||||
vmf.pgoff = pgoff;
|
||||
vmf.flags = flags;
|
||||
vmf.gfp_mask = mapping_gfp_mask(mapping) | __GFP_IO;
|
||||
|
@ -1310,7 +1372,7 @@ int dax_iomap_pmd_fault(struct vm_area_struct *vma, unsigned long address,
|
|||
case IOMAP_UNWRITTEN:
|
||||
case IOMAP_HOLE:
|
||||
if (WARN_ON_ONCE(write))
|
||||
goto finish_iomap;
|
||||
goto unlock_entry;
|
||||
result = dax_pmd_load_hole(vma, pmd, &vmf, address, &iomap,
|
||||
&entry);
|
||||
break;
|
||||
|
@ -1319,20 +1381,23 @@ int dax_iomap_pmd_fault(struct vm_area_struct *vma, unsigned long address,
|
|||
break;
|
||||
}
|
||||
|
||||
finish_iomap:
|
||||
if (ops->iomap_end) {
|
||||
if (result == VM_FAULT_FALLBACK) {
|
||||
ops->iomap_end(inode, pos, PMD_SIZE, 0, iomap_flags,
|
||||
&iomap);
|
||||
} else {
|
||||
error = ops->iomap_end(inode, pos, PMD_SIZE, PMD_SIZE,
|
||||
iomap_flags, &iomap);
|
||||
if (error)
|
||||
result = VM_FAULT_FALLBACK;
|
||||
}
|
||||
}
|
||||
unlock_entry:
|
||||
put_locked_mapping_entry(mapping, pgoff, entry);
|
||||
finish_iomap:
|
||||
if (ops->iomap_end) {
|
||||
int copied = PMD_SIZE;
|
||||
|
||||
if (result == VM_FAULT_FALLBACK)
|
||||
copied = 0;
|
||||
/*
|
||||
* The fault is done by now and there's no way back (other
|
||||
* thread may be already happily using PMD we have installed).
|
||||
* Just ignore error from ->iomap_end since we cannot do much
|
||||
* with it.
|
||||
*/
|
||||
ops->iomap_end(inode, pos, PMD_SIZE, copied, iomap_flags,
|
||||
&iomap);
|
||||
}
|
||||
fallback:
|
||||
if (result == VM_FAULT_FALLBACK) {
|
||||
split_huge_pmd(vma, pmd, address);
|
||||
|
|
|
@ -751,9 +751,8 @@ static int ext2_get_blocks(struct inode *inode,
|
|||
mutex_unlock(&ei->truncate_mutex);
|
||||
goto cleanup;
|
||||
}
|
||||
} else {
|
||||
*new = true;
|
||||
}
|
||||
*new = true;
|
||||
|
||||
ext2_splice_branch(inode, iblock, partial, indirect_blks, count);
|
||||
mutex_unlock(&ei->truncate_mutex);
|
||||
|
|
|
@ -258,7 +258,6 @@ out:
|
|||
static int ext4_dax_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
|
||||
{
|
||||
int result;
|
||||
handle_t *handle = NULL;
|
||||
struct inode *inode = file_inode(vma->vm_file);
|
||||
struct super_block *sb = inode->i_sb;
|
||||
bool write = vmf->flags & FAULT_FLAG_WRITE;
|
||||
|
@ -266,24 +265,12 @@ static int ext4_dax_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
|
|||
if (write) {
|
||||
sb_start_pagefault(sb);
|
||||
file_update_time(vma->vm_file);
|
||||
down_read(&EXT4_I(inode)->i_mmap_sem);
|
||||
handle = ext4_journal_start_sb(sb, EXT4_HT_WRITE_PAGE,
|
||||
EXT4_DATA_TRANS_BLOCKS(sb));
|
||||
} else
|
||||
down_read(&EXT4_I(inode)->i_mmap_sem);
|
||||
|
||||
if (IS_ERR(handle))
|
||||
result = VM_FAULT_SIGBUS;
|
||||
else
|
||||
result = dax_iomap_fault(vma, vmf, &ext4_iomap_ops);
|
||||
|
||||
if (write) {
|
||||
if (!IS_ERR(handle))
|
||||
ext4_journal_stop(handle);
|
||||
up_read(&EXT4_I(inode)->i_mmap_sem);
|
||||
}
|
||||
down_read(&EXT4_I(inode)->i_mmap_sem);
|
||||
result = dax_iomap_fault(vma, vmf, &ext4_iomap_ops);
|
||||
up_read(&EXT4_I(inode)->i_mmap_sem);
|
||||
if (write)
|
||||
sb_end_pagefault(sb);
|
||||
} else
|
||||
up_read(&EXT4_I(inode)->i_mmap_sem);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -292,7 +279,6 @@ static int ext4_dax_pmd_fault(struct vm_area_struct *vma, unsigned long addr,
|
|||
pmd_t *pmd, unsigned int flags)
|
||||
{
|
||||
int result;
|
||||
handle_t *handle = NULL;
|
||||
struct inode *inode = file_inode(vma->vm_file);
|
||||
struct super_block *sb = inode->i_sb;
|
||||
bool write = flags & FAULT_FLAG_WRITE;
|
||||
|
@ -300,27 +286,13 @@ static int ext4_dax_pmd_fault(struct vm_area_struct *vma, unsigned long addr,
|
|||
if (write) {
|
||||
sb_start_pagefault(sb);
|
||||
file_update_time(vma->vm_file);
|
||||
down_read(&EXT4_I(inode)->i_mmap_sem);
|
||||
handle = ext4_journal_start_sb(sb, EXT4_HT_WRITE_PAGE,
|
||||
ext4_chunk_trans_blocks(inode,
|
||||
PMD_SIZE / PAGE_SIZE));
|
||||
} else
|
||||
down_read(&EXT4_I(inode)->i_mmap_sem);
|
||||
|
||||
if (IS_ERR(handle))
|
||||
result = VM_FAULT_SIGBUS;
|
||||
else {
|
||||
result = dax_iomap_pmd_fault(vma, addr, pmd, flags,
|
||||
&ext4_iomap_ops);
|
||||
}
|
||||
|
||||
if (write) {
|
||||
if (!IS_ERR(handle))
|
||||
ext4_journal_stop(handle);
|
||||
up_read(&EXT4_I(inode)->i_mmap_sem);
|
||||
down_read(&EXT4_I(inode)->i_mmap_sem);
|
||||
result = dax_iomap_pmd_fault(vma, addr, pmd, flags,
|
||||
&ext4_iomap_ops);
|
||||
up_read(&EXT4_I(inode)->i_mmap_sem);
|
||||
if (write)
|
||||
sb_end_pagefault(sb);
|
||||
} else
|
||||
up_read(&EXT4_I(inode)->i_mmap_sem);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -41,6 +41,9 @@ ssize_t dax_iomap_rw(struct kiocb *iocb, struct iov_iter *iter,
|
|||
int dax_iomap_fault(struct vm_area_struct *vma, struct vm_fault *vmf,
|
||||
struct iomap_ops *ops);
|
||||
int dax_delete_mapping_entry(struct address_space *mapping, pgoff_t index);
|
||||
int dax_invalidate_mapping_entry(struct address_space *mapping, pgoff_t index);
|
||||
int dax_invalidate_mapping_entry_sync(struct address_space *mapping,
|
||||
pgoff_t index);
|
||||
void dax_wake_mapping_entry_waiter(struct address_space *mapping,
|
||||
pgoff_t index, void *entry, bool wake_all);
|
||||
|
||||
|
|
|
@ -73,13 +73,13 @@
|
|||
*/
|
||||
enum pageflags {
|
||||
PG_locked, /* Page is locked. Don't touch. */
|
||||
PG_waiters, /* Page has waiters, check its waitqueue */
|
||||
PG_error,
|
||||
PG_referenced,
|
||||
PG_uptodate,
|
||||
PG_dirty,
|
||||
PG_lru,
|
||||
PG_active,
|
||||
PG_waiters, /* Page has waiters, check its waitqueue. Must be bit #7 and in the same byte as "PG_locked" */
|
||||
PG_slab,
|
||||
PG_owner_priv_1, /* Owner use. If pagecache, fs may use*/
|
||||
PG_arch_1,
|
||||
|
|
36
mm/filemap.c
36
mm/filemap.c
|
@ -912,6 +912,29 @@ void add_page_wait_queue(struct page *page, wait_queue_t *waiter)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(add_page_wait_queue);
|
||||
|
||||
#ifndef clear_bit_unlock_is_negative_byte
|
||||
|
||||
/*
|
||||
* PG_waiters is the high bit in the same byte as PG_lock.
|
||||
*
|
||||
* On x86 (and on many other architectures), we can clear PG_lock and
|
||||
* test the sign bit at the same time. But if the architecture does
|
||||
* not support that special operation, we just do this all by hand
|
||||
* instead.
|
||||
*
|
||||
* The read of PG_waiters has to be after (or concurrently with) PG_locked
|
||||
* being cleared, but a memory barrier should be unneccssary since it is
|
||||
* in the same byte as PG_locked.
|
||||
*/
|
||||
static inline bool clear_bit_unlock_is_negative_byte(long nr, volatile void *mem)
|
||||
{
|
||||
clear_bit_unlock(nr, mem);
|
||||
/* smp_mb__after_atomic(); */
|
||||
return test_bit(PG_waiters, mem);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* unlock_page - unlock a locked page
|
||||
* @page: the page
|
||||
|
@ -921,16 +944,19 @@ EXPORT_SYMBOL_GPL(add_page_wait_queue);
|
|||
* mechanism between PageLocked pages and PageWriteback pages is shared.
|
||||
* But that's OK - sleepers in wait_on_page_writeback() just go back to sleep.
|
||||
*
|
||||
* The mb is necessary to enforce ordering between the clear_bit and the read
|
||||
* of the waitqueue (to avoid SMP races with a parallel wait_on_page_locked()).
|
||||
* Note that this depends on PG_waiters being the sign bit in the byte
|
||||
* that contains PG_locked - thus the BUILD_BUG_ON(). That allows us to
|
||||
* clear the PG_locked bit and test PG_waiters at the same time fairly
|
||||
* portably (architectures that do LL/SC can test any bit, while x86 can
|
||||
* test the sign bit).
|
||||
*/
|
||||
void unlock_page(struct page *page)
|
||||
{
|
||||
BUILD_BUG_ON(PG_waiters != 7);
|
||||
page = compound_head(page);
|
||||
VM_BUG_ON_PAGE(!PageLocked(page), page);
|
||||
clear_bit_unlock(PG_locked, &page->flags);
|
||||
smp_mb__after_atomic();
|
||||
wake_up_page(page, PG_locked);
|
||||
if (clear_bit_unlock_is_negative_byte(PG_locked, &page->flags))
|
||||
wake_up_page_bit(page, PG_locked);
|
||||
}
|
||||
EXPORT_SYMBOL(unlock_page);
|
||||
|
||||
|
|
|
@ -24,20 +24,12 @@
|
|||
#include <linux/rmap.h>
|
||||
#include "internal.h"
|
||||
|
||||
static void clear_exceptional_entry(struct address_space *mapping,
|
||||
pgoff_t index, void *entry)
|
||||
static void clear_shadow_entry(struct address_space *mapping, pgoff_t index,
|
||||
void *entry)
|
||||
{
|
||||
struct radix_tree_node *node;
|
||||
void **slot;
|
||||
|
||||
/* Handled by shmem itself */
|
||||
if (shmem_mapping(mapping))
|
||||
return;
|
||||
|
||||
if (dax_mapping(mapping)) {
|
||||
dax_delete_mapping_entry(mapping, index);
|
||||
return;
|
||||
}
|
||||
spin_lock_irq(&mapping->tree_lock);
|
||||
/*
|
||||
* Regular page slots are stabilized by the page lock even
|
||||
|
@ -55,6 +47,56 @@ unlock:
|
|||
spin_unlock_irq(&mapping->tree_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Unconditionally remove exceptional entry. Usually called from truncate path.
|
||||
*/
|
||||
static void truncate_exceptional_entry(struct address_space *mapping,
|
||||
pgoff_t index, void *entry)
|
||||
{
|
||||
/* Handled by shmem itself */
|
||||
if (shmem_mapping(mapping))
|
||||
return;
|
||||
|
||||
if (dax_mapping(mapping)) {
|
||||
dax_delete_mapping_entry(mapping, index);
|
||||
return;
|
||||
}
|
||||
clear_shadow_entry(mapping, index, entry);
|
||||
}
|
||||
|
||||
/*
|
||||
* Invalidate exceptional entry if easily possible. This handles exceptional
|
||||
* entries for invalidate_inode_pages() so for DAX it evicts only unlocked and
|
||||
* clean entries.
|
||||
*/
|
||||
static int invalidate_exceptional_entry(struct address_space *mapping,
|
||||
pgoff_t index, void *entry)
|
||||
{
|
||||
/* Handled by shmem itself */
|
||||
if (shmem_mapping(mapping))
|
||||
return 1;
|
||||
if (dax_mapping(mapping))
|
||||
return dax_invalidate_mapping_entry(mapping, index);
|
||||
clear_shadow_entry(mapping, index, entry);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Invalidate exceptional entry if clean. This handles exceptional entries for
|
||||
* invalidate_inode_pages2() so for DAX it evicts only clean entries.
|
||||
*/
|
||||
static int invalidate_exceptional_entry2(struct address_space *mapping,
|
||||
pgoff_t index, void *entry)
|
||||
{
|
||||
/* Handled by shmem itself */
|
||||
if (shmem_mapping(mapping))
|
||||
return 1;
|
||||
if (dax_mapping(mapping))
|
||||
return dax_invalidate_mapping_entry_sync(mapping, index);
|
||||
clear_shadow_entry(mapping, index, entry);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* do_invalidatepage - invalidate part or all of a page
|
||||
* @page: the page which is affected
|
||||
|
@ -262,7 +304,8 @@ void truncate_inode_pages_range(struct address_space *mapping,
|
|||
break;
|
||||
|
||||
if (radix_tree_exceptional_entry(page)) {
|
||||
clear_exceptional_entry(mapping, index, page);
|
||||
truncate_exceptional_entry(mapping, index,
|
||||
page);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -351,7 +394,8 @@ void truncate_inode_pages_range(struct address_space *mapping,
|
|||
}
|
||||
|
||||
if (radix_tree_exceptional_entry(page)) {
|
||||
clear_exceptional_entry(mapping, index, page);
|
||||
truncate_exceptional_entry(mapping, index,
|
||||
page);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -470,7 +514,8 @@ unsigned long invalidate_mapping_pages(struct address_space *mapping,
|
|||
break;
|
||||
|
||||
if (radix_tree_exceptional_entry(page)) {
|
||||
clear_exceptional_entry(mapping, index, page);
|
||||
invalidate_exceptional_entry(mapping, index,
|
||||
page);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -592,7 +637,9 @@ int invalidate_inode_pages2_range(struct address_space *mapping,
|
|||
break;
|
||||
|
||||
if (radix_tree_exceptional_entry(page)) {
|
||||
clear_exceptional_entry(mapping, index, page);
|
||||
if (!invalidate_exceptional_entry2(mapping,
|
||||
index, page))
|
||||
ret = -EBUSY;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ static void pcm_period_tasklet(unsigned long data);
|
|||
* @protocol_size: the size to allocate newly for protocol
|
||||
*/
|
||||
int amdtp_stream_init(struct amdtp_stream *s, struct fw_unit *unit,
|
||||
enum amdtp_stream_direction dir, enum cip_flags flags,
|
||||
enum amdtp_stream_direction dir, int flags,
|
||||
unsigned int fmt,
|
||||
amdtp_stream_process_data_blocks_t process_data_blocks,
|
||||
unsigned int protocol_size)
|
||||
|
|
|
@ -93,7 +93,7 @@ typedef unsigned int (*amdtp_stream_process_data_blocks_t)(
|
|||
unsigned int *syt);
|
||||
struct amdtp_stream {
|
||||
struct fw_unit *unit;
|
||||
enum cip_flags flags;
|
||||
int flags;
|
||||
enum amdtp_stream_direction direction;
|
||||
struct mutex mutex;
|
||||
|
||||
|
@ -137,7 +137,7 @@ struct amdtp_stream {
|
|||
};
|
||||
|
||||
int amdtp_stream_init(struct amdtp_stream *s, struct fw_unit *unit,
|
||||
enum amdtp_stream_direction dir, enum cip_flags flags,
|
||||
enum amdtp_stream_direction dir, int flags,
|
||||
unsigned int fmt,
|
||||
amdtp_stream_process_data_blocks_t process_data_blocks,
|
||||
unsigned int protocol_size);
|
||||
|
|
|
@ -117,7 +117,7 @@ destroy_stream(struct snd_efw *efw, struct amdtp_stream *stream)
|
|||
conn = &efw->in_conn;
|
||||
|
||||
amdtp_stream_destroy(stream);
|
||||
cmp_connection_destroy(&efw->out_conn);
|
||||
cmp_connection_destroy(conn);
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
|
@ -343,7 +343,7 @@ int snd_tscm_stream_init_duplex(struct snd_tscm *tscm)
|
|||
if (err < 0)
|
||||
amdtp_stream_destroy(&tscm->rx_stream);
|
||||
|
||||
return 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
/* At bus reset, streaming is stopped and some registers are clear. */
|
||||
|
|
Loading…
Reference in New Issue