Skip to content

Commit

Permalink
aufs: bugfix, AIO keeps h_file in kiocb
Browse files Browse the repository at this point in the history
AIO implementation in aufs has never been correct I'm afraid.
The code was written in aufs2.6 era and the local test has ever
passed, but it might be just a luck.
- AIO splits an I/O into two parts, 'submit' and 'complete'. Often
  they are called 'top-half' and 'bottom-half'. They run
  independently.
- aufs modifies a kernel internal data temporary in top-half.
- and aufs restores the modified data, also in top-half phase. This is
  the bug. Such restoration should be done AFTER bottom-half
  completed.

The bug is a race condition I'm afraid.
If bottom-half routine accesses the "temporary modifed but already
restored" internal data, it would get crazy (and Bang!). But if
bottom-half starts and completes so quicky that BEFORE the
restoration, no problem would happen.
The problem is uncovered due to direct-io. Generally direct-io is
slow. And its slowness is the key here.

Probaly it is formal/polite/well-mannered for aufs to register a new
hidden I/O requests for the branch fs in top-half. But it is a little
bit too gorgeous approach. I'd try another way which is simply stops
the restoration. This is rather violent since kernel doesn't expect
its data to be modified silently.

See-also: sfjro/aufs-standalone#39
Signed-off-by: J. R. Okajima <[email protected]>
  • Loading branch information
sfjro committed Jun 18, 2024
1 parent d042574 commit f52c34d
Showing 1 changed file with 12 additions and 2 deletions.
14 changes: 12 additions & 2 deletions fs/aufs/f_op.c
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,12 @@ static ssize_t au_do_iter(struct file *h_file, int rw, struct kiocb *kio,
} else
/* currently there is no such fs */
WARN_ON_ONCE(1);
kio->ki_filp = file;
if (!is_sync_kiocb(kio)) {
/* do not restore ki_filp */
fput(file);
get_file(h_file);
} else
kio->ki_filp = file;

out:
return err;
Expand Down Expand Up @@ -344,7 +349,12 @@ static ssize_t aufs_write_iter(struct kiocb *kio, struct iov_iter *iov_iter)
err = PTR_ERR(h_file);
if (IS_ERR(h_file))
goto out;

if (!is_sync_kiocb(kio)) {
/* .vs. sb_start_write() in aio_write() */
if (S_ISREG(inode->i_mode))
__sb_writers_acquired(inode->i_sb, SB_FREEZE_WRITE);
file_end_write(file);
}
err = au_do_iter(h_file, MAY_WRITE, kio, iov_iter);
au_write_post(inode, h_file, &wpre, err);

Expand Down

0 comments on commit f52c34d

Please sign in to comment.