Skip to content

Commit 6a23b45

Browse files
committed
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull vfs and fs fixes from Al Viro: "Several AIO and OCFS2 fixes" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: ocfs2: _really_ sync the right range ocfs2_file_write_iter: keep return value and current position update in sync [regression] ocfs2: do *not* increment ->ki_pos twice ioctx_alloc(): fix vma (and file) leak on failure fix mremap() vs. ioctx_kill() race
2 parents 54d8ccc + 64b4e25 commit 6a23b45

File tree

4 files changed

+34
-15
lines changed

4 files changed

+34
-15
lines changed

fs/aio.c

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -278,11 +278,11 @@ static int aio_ring_mmap(struct file *file, struct vm_area_struct *vma)
278278
return 0;
279279
}
280280

281-
static void aio_ring_remap(struct file *file, struct vm_area_struct *vma)
281+
static int aio_ring_remap(struct file *file, struct vm_area_struct *vma)
282282
{
283283
struct mm_struct *mm = vma->vm_mm;
284284
struct kioctx_table *table;
285-
int i;
285+
int i, res = -EINVAL;
286286

287287
spin_lock(&mm->ioctx_lock);
288288
rcu_read_lock();
@@ -292,13 +292,17 @@ static void aio_ring_remap(struct file *file, struct vm_area_struct *vma)
292292

293293
ctx = table->table[i];
294294
if (ctx && ctx->aio_ring_file == file) {
295-
ctx->user_id = ctx->mmap_base = vma->vm_start;
295+
if (!atomic_read(&ctx->dead)) {
296+
ctx->user_id = ctx->mmap_base = vma->vm_start;
297+
res = 0;
298+
}
296299
break;
297300
}
298301
}
299302

300303
rcu_read_unlock();
301304
spin_unlock(&mm->ioctx_lock);
305+
return res;
302306
}
303307

304308
static const struct file_operations aio_ring_fops = {
@@ -727,6 +731,9 @@ static struct kioctx *ioctx_alloc(unsigned nr_events)
727731
err_cleanup:
728732
aio_nr_sub(ctx->max_reqs);
729733
err_ctx:
734+
atomic_set(&ctx->dead, 1);
735+
if (ctx->mmap_size)
736+
vm_munmap(ctx->mmap_base, ctx->mmap_size);
730737
aio_free_ring(ctx);
731738
err:
732739
mutex_unlock(&ctx->ring_lock);
@@ -748,11 +755,12 @@ static int kill_ioctx(struct mm_struct *mm, struct kioctx *ctx,
748755
{
749756
struct kioctx_table *table;
750757

751-
if (atomic_xchg(&ctx->dead, 1))
758+
spin_lock(&mm->ioctx_lock);
759+
if (atomic_xchg(&ctx->dead, 1)) {
760+
spin_unlock(&mm->ioctx_lock);
752761
return -EINVAL;
762+
}
753763

754-
755-
spin_lock(&mm->ioctx_lock);
756764
table = rcu_dereference_raw(mm->ioctx_table);
757765
WARN_ON(ctx != table->table[ctx->id]);
758766
table->table[ctx->id] = NULL;

fs/ocfs2/file.c

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2394,7 +2394,6 @@ static ssize_t ocfs2_file_write_iter(struct kiocb *iocb,
23942394
/*
23952395
* for completing the rest of the request.
23962396
*/
2397-
*ppos += written;
23982397
count -= written;
23992398
written_buffered = generic_perform_write(file, from, *ppos);
24002399
/*
@@ -2409,7 +2408,6 @@ static ssize_t ocfs2_file_write_iter(struct kiocb *iocb,
24092408
goto out_dio;
24102409
}
24112410

2412-
iocb->ki_pos = *ppos + written_buffered;
24132411
/* We need to ensure that the page cache pages are written to
24142412
* disk and invalidated to preserve the expected O_DIRECT
24152413
* semantics.
@@ -2418,6 +2416,7 @@ static ssize_t ocfs2_file_write_iter(struct kiocb *iocb,
24182416
ret = filemap_write_and_wait_range(file->f_mapping, *ppos,
24192417
endbyte);
24202418
if (ret == 0) {
2419+
iocb->ki_pos = *ppos + written_buffered;
24212420
written += written_buffered;
24222421
invalidate_mapping_pages(mapping,
24232422
*ppos >> PAGE_CACHE_SHIFT,
@@ -2440,10 +2439,14 @@ static ssize_t ocfs2_file_write_iter(struct kiocb *iocb,
24402439
/* buffered aio wouldn't have proper lock coverage today */
24412440
BUG_ON(ret == -EIOCBQUEUED && !(file->f_flags & O_DIRECT));
24422441

2442+
if (unlikely(written <= 0))
2443+
goto no_sync;
2444+
24432445
if (((file->f_flags & O_DSYNC) && !direct_io) || IS_SYNC(inode) ||
24442446
((file->f_flags & O_DIRECT) && !direct_io)) {
2445-
ret = filemap_fdatawrite_range(file->f_mapping, *ppos,
2446-
*ppos + count - 1);
2447+
ret = filemap_fdatawrite_range(file->f_mapping,
2448+
iocb->ki_pos - written,
2449+
iocb->ki_pos - 1);
24472450
if (ret < 0)
24482451
written = ret;
24492452

@@ -2454,10 +2457,12 @@ static ssize_t ocfs2_file_write_iter(struct kiocb *iocb,
24542457
}
24552458

24562459
if (!ret)
2457-
ret = filemap_fdatawait_range(file->f_mapping, *ppos,
2458-
*ppos + count - 1);
2460+
ret = filemap_fdatawait_range(file->f_mapping,
2461+
iocb->ki_pos - written,
2462+
iocb->ki_pos - 1);
24592463
}
24602464

2465+
no_sync:
24612466
/*
24622467
* deep in g_f_a_w_n()->ocfs2_direct_IO we pass in a ocfs2_dio_end_io
24632468
* function pointer which is called when o_direct io completes so that

include/linux/fs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1549,7 +1549,7 @@ struct file_operations {
15491549
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
15501550
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
15511551
int (*mmap) (struct file *, struct vm_area_struct *);
1552-
void (*mremap)(struct file *, struct vm_area_struct *);
1552+
int (*mremap)(struct file *, struct vm_area_struct *);
15531553
int (*open) (struct inode *, struct file *);
15541554
int (*flush) (struct file *, fl_owner_t id);
15551555
int (*release) (struct inode *, struct file *);

mm/mremap.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -286,8 +286,14 @@ static unsigned long move_vma(struct vm_area_struct *vma,
286286
old_len = new_len;
287287
old_addr = new_addr;
288288
new_addr = -ENOMEM;
289-
} else if (vma->vm_file && vma->vm_file->f_op->mremap)
290-
vma->vm_file->f_op->mremap(vma->vm_file, new_vma);
289+
} else if (vma->vm_file && vma->vm_file->f_op->mremap) {
290+
err = vma->vm_file->f_op->mremap(vma->vm_file, new_vma);
291+
if (err < 0) {
292+
move_page_tables(new_vma, new_addr, vma, old_addr,
293+
moved_len, true);
294+
return err;
295+
}
296+
}
291297

292298
/* Conceal VM_ACCOUNT so old reservation is not undone */
293299
if (vm_flags & VM_ACCOUNT) {

0 commit comments

Comments
 (0)