From 7becd9624caeaf45d8ab7450674d77a5bfa47e7b Mon Sep 17 00:00:00 2001 From: anserper Date: Thu, 16 Jul 2009 09:03:28 +0000 Subject: [PATCH] b=18801 i=Oleg Drokin i=Alexander Zarochentsev atime, mtime and additional POSIX compliance stuff for direct I/O and lockless I/O --- lustre/autoconf/lustre-core.m4 | 19 ++++++++ lustre/include/linux/lustre_compat25.h | 6 +++ lustre/llite/file.c | 86 +++++++++++++++++++++++++++++++--- lustre/tests/sanityN.sh | 17 +++++++ 4 files changed, 122 insertions(+), 6 deletions(-) diff --git a/lustre/autoconf/lustre-core.m4 b/lustre/autoconf/lustre-core.m4 index be856f9..1d2eaf3 100644 --- a/lustre/autoconf/lustre-core.m4 +++ b/lustre/autoconf/lustre-core.m4 @@ -964,6 +964,23 @@ LB_LINUX_TRY_COMPILE([ EXTRA_KCFLAGS="$tmp_flags" ]) +# LC_FILE_UPDATE_TIME +# 2.6.9 has inode_update_time instead of file_update_time +AC_DEFUN([LC_FILE_UPDATE_TIME], +[AC_MSG_CHECKING([if file_update_time is exported]) +LB_LINUX_TRY_COMPILE([ + #include +],[ + file_update_time(NULL); +],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_FILE_UPDATE_TIME, 1, + [use file_update_time]) +],[ + AC_MSG_RESULT(no) +]) +]) + # LC_FILE_WRITEV # 2.6.19 replaced writev with aio_write AC_DEFUN([LC_FILE_WRITEV], @@ -982,6 +999,7 @@ LB_LINUX_TRY_COMPILE([ ]) ]) + # LC_GENERIC_FILE_READ # 2.6.19 replaced readv with aio_read AC_DEFUN([LC_FILE_READV], @@ -1875,6 +1893,7 @@ AC_DEFUN([LC_PROG_LINUX], # 2.6.19 LC_INODE_BLKSIZE LC_VFS_READDIR_U64_INO + LC_FILE_UPDATE_TIME LC_FILE_WRITEV LC_FILE_READV diff --git a/lustre/include/linux/lustre_compat25.h b/lustre/include/linux/lustre_compat25.h index 62eeb47..34ea09e 100644 --- a/lustre/include/linux/lustre_compat25.h +++ b/lustre/include/linux/lustre_compat25.h @@ -615,5 +615,11 @@ static inline int ll_quota_off(struct super_block *sb, int off, int remount) #define bio_hw_segments(q, bio) 0 #endif +#ifdef HAVE_FILE_UPDATE_TIME +#define ll_update_time(file) file_update_time(file) +#else +#define ll_update_time(file) inode_update_time(file->f_mapping->host, 1) +#endif + #endif /* __KERNEL__ */ #endif /* _COMPAT25_H */ diff --git a/lustre/llite/file.c b/lustre/llite/file.c index dfdd142e..3425a46 100644 --- a/lustre/llite/file.c +++ b/lustre/llite/file.c @@ -1649,9 +1649,10 @@ repeat: } else { retval = ll_direct_IO(READ, file, iov_copy, *ppos, nr_segs, 0); if (retval > 0) { - lprocfs_counter_add(sbi->ll_stats, - LPROC_LL_LOCKLESS_READ, - (long)retval); + file_accessed(file); + lprocfs_counter_add(sbi->ll_stats, + LPROC_LL_LOCKLESS_READ, + (long)retval); *ppos += retval; } } @@ -1696,6 +1697,56 @@ static ssize_t ll_file_read(struct file *file, char *buf, size_t count, #endif } +/* iov_shorten from linux kernel */ +static unsigned long ll_iov_shorten(struct iovec *iov, + unsigned long nr_segs, + size_t to) +{ + unsigned long seg = 0; + size_t len = 0; + + while (seg < nr_segs) { + seg++; + if (len + iov->iov_len >= to) { + iov->iov_len = to - len; + break; + } + len += iov->iov_len; + iov++; + } + return seg; +} + +/* 2.6.22 and 2.6.27 export this as generic_segment_checks */ +static int ll_generic_segment_checks(const struct iovec *iov, + unsigned long *nr_segs, + size_t *count, + int access_flags) +{ + unsigned long seg; + size_t cnt = 0; + for (seg = 0; seg < *nr_segs; seg++) { + const struct iovec *iv = &iov[seg]; + + /* + * If any segment has a negative length, or the cumulative + * length ever wraps negative then return -EINVAL. + */ + cnt += iv->iov_len; + if (unlikely((ssize_t)(cnt|iv->iov_len) < 0)) + return -EINVAL; + if (access_ok(access_flags, iv->iov_base, iv->iov_len)) + continue; + if (seg == 0) + return -EFAULT; + *nr_segs = seg; + cnt -= iv->iov_len; /* This segment is no good */ + break; + } + *count = cnt; + return 0; +} + /* * Write to a file (through the page cache). */ @@ -1860,11 +1911,34 @@ repeat: *ppos); #endif } else { + size_t ocount, ncount; + + retval = ll_generic_segment_checks(iov_copy, &nrsegs_copy, + &ocount, VERIFY_READ); + if (retval) + GOTO(out, retval); + + retval = generic_write_checks(file, ppos, &ncount, 0); + if (retval) + GOTO(out, retval); + + if (unlikely(ocount != ncount)) { + /* we are allowed to modify the original iov too */ + nrsegs_copy = ll_iov_shorten(iov_copy, nrsegs_copy, + ncount); + chunk = 0; /* no repetition after the short write */ + } + + retval = ll_remove_suid(file, file->f_vfsmnt); + if (retval) + GOTO(out, retval); + + ll_update_time(file); retval = ll_direct_IO(WRITE, file, iov_copy, *ppos, nr_segs, 0); if (retval > 0) { - lprocfs_counter_add(sbi->ll_stats, - LPROC_LL_LOCKLESS_WRITE, - (long)retval); + lprocfs_counter_add(sbi->ll_stats, + LPROC_LL_LOCKLESS_WRITE, + (long)retval); *ppos += retval; } } diff --git a/lustre/tests/sanityN.sh b/lustre/tests/sanityN.sh index e3fb5d6..7d42930 100644 --- a/lustre/tests/sanityN.sh +++ b/lustre/tests/sanityN.sh @@ -880,6 +880,23 @@ test_38() { # bug 18801, based on the code of test_32b } run_test 38 "lockless i/o with O_DIRECT and unaligned writes" +test_39() { + local originaltime + local updatedtime + local delay=3 + + touch $DIR1/$tfile + originaltime=$(stat -c %Y $DIR1/$tfile) + log "original modification time is $originaltime" + sleep $delay + multiop $DIR1/$tfile oO_DIRECT:O_WRONLY:w$((10*1048576))c || error "multiop has failed" + updatedtime=$(stat -c %Y $DIR2/$tfile) + log "updated modification time is $updatedtime" + [ $((updatedtime - originaltime)) -ge $delay ] || error "invalid modification time" + rm -rf $DIR/$tfile +} +run_test 39 "direct I/O writes should update mtime =========" + log "cleanup: ======================================================" check_and_cleanup_lustre -- 1.8.3.1