Index: linux-2.6.10/drivers/char/qtronix.c =================================================================== --- linux-2.6.10.orig/drivers/char/qtronix.c 2004-12-24 14:35:50.000000000 -0700 +++ linux-2.6.10/drivers/char/qtronix.c 2006-01-03 16:16:52.000000000 -0700 @@ -537,7 +537,7 @@ i--; } if (count-i) { - file->f_dentry->d_inode->i_atime = CURRENT_TIME; + file->f_dentry->d_inode->i_atime = current_fs_time(inode->i_sb); return count-i; } if (signal_pending(current)) Index: linux-2.6.10/drivers/char/random.c =================================================================== --- linux-2.6.10.orig/drivers/char/random.c 2005-04-06 09:38:33.000000000 -0600 +++ linux-2.6.10/drivers/char/random.c 2006-01-03 16:16:52.000000000 -0700 @@ -1743,8 +1743,9 @@ if (p == buffer) { return (ssize_t)ret; } else { - file->f_dentry->d_inode->i_mtime = CURRENT_TIME; - mark_inode_dirty(file->f_dentry->d_inode); + struct inode *inode = file->f_dentry->d_inode; + inode->i_mtime = current_fs_time(inode->i_sb); + mark_inode_dirty(inode); return (ssize_t)(p - buffer); } } Index: linux-2.6.10/drivers/char/sonypi.c =================================================================== --- linux-2.6.10.orig/drivers/char/sonypi.c 2004-12-24 14:35:23.000000000 -0700 +++ linux-2.6.10/drivers/char/sonypi.c 2006-01-03 16:18:31.000000000 -0700 @@ -537,7 +537,8 @@ } if (ret > 0) - file->f_dentry->d_inode->i_atime = CURRENT_TIME; + struct inode *inode = file->f_dentry->d_inode; + inode->i_atime = current_fs_time(inode->i_sb); return ret; } Index: linux-2.6.10/drivers/char/tty_io.c =================================================================== --- linux-2.6.10.orig/drivers/char/tty_io.c 2005-04-06 09:38:33.000000000 -0600 +++ linux-2.6.10/drivers/char/tty_io.c 2006-01-03 16:16:52.000000000 -0700 @@ -1018,7 +1018,7 @@ tty_ldisc_deref(ld); unlock_kernel(); if (i > 0) - inode->i_atime = CURRENT_TIME; + inode->i_atime = current_fs_time(inode->i_sb); return i; } @@ -1095,7 +1095,8 @@ cond_resched(); } if (written) { - file->f_dentry->d_inode->i_mtime = CURRENT_TIME; + struct inode *inode = file->f_dentry->d_inode; + inode->i_mtime = current_fs_time(inode->i_sb); ret = written; } up(&tty->atomic_write); Index: linux-2.6.10/fs/attr.c =================================================================== --- linux-2.6.10.orig/fs/attr.c 2004-12-24 14:34:00.000000000 -0700 +++ linux-2.6.10/fs/attr.c 2006-01-03 16:16:52.000000000 -0700 @@ -14,6 +14,7 @@ #include #include #include +#include /* Taken over from the old code... */ @@ -87,11 +88,14 @@ if (ia_valid & ATTR_GID) inode->i_gid = attr->ia_gid; if (ia_valid & ATTR_ATIME) - inode->i_atime = attr->ia_atime; + inode->i_atime = timespec_trunc(attr->ia_atime, + get_sb_time_gran(inode->i_sb)); if (ia_valid & ATTR_MTIME) - inode->i_mtime = attr->ia_mtime; + inode->i_mtime = timespec_trunc(attr->ia_mtime, + get_sb_time_gran(inode->i_sb)); if (ia_valid & ATTR_CTIME) - inode->i_ctime = attr->ia_ctime; + inode->i_ctime = timespec_trunc(attr->ia_ctime, + get_sb_time_gran(inode->i_sb)); if (ia_valid & ATTR_MODE) { umode_t mode = attr->ia_mode; @@ -131,14 +135,17 @@ int notify_change(struct dentry * dentry, struct iattr * attr) { struct inode *inode = dentry->d_inode; - mode_t mode = inode->i_mode; + mode_t mode; int error; - struct timespec now = CURRENT_TIME; + struct timespec now; unsigned int ia_valid = attr->ia_valid; if (!inode) BUG(); + mode = inode->i_mode; + now = current_fs_time(inode->i_sb); + attr->ia_ctime = now; if (!(ia_valid & ATTR_ATIME_SET)) attr->ia_atime = now; Index: linux-2.6.10/fs/bad_inode.c =================================================================== --- linux-2.6.10.orig/fs/bad_inode.c 2004-12-24 14:35:50.000000000 -0700 +++ linux-2.6.10/fs/bad_inode.c 2006-01-03 16:16:52.000000000 -0700 @@ -105,7 +105,8 @@ remove_inode_hash(inode); inode->i_mode = S_IFREG; - inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; + inode->i_atime = inode->i_mtime = inode->i_ctime = + current_fs_time(inode->i_sb); inode->i_op = &bad_inode_ops; inode->i_fop = &bad_file_ops; } Index: linux-2.6.10/fs/binfmt_misc.c =================================================================== --- linux-2.6.10.orig/fs/binfmt_misc.c 2004-12-24 14:34:31.000000000 -0700 +++ linux-2.6.10/fs/binfmt_misc.c 2006-01-03 16:16:52.000000000 -0700 @@ -509,7 +509,8 @@ inode->i_gid = 0; inode->i_blksize = PAGE_CACHE_SIZE; inode->i_blocks = 0; - inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; + inode->i_atime = inode->i_mtime = inode->i_ctime = + current_fs_time(inode->i_sb); } return inode; } Index: linux-2.6.10/fs/ext2/dir.c =================================================================== --- linux-2.6.10.orig/fs/ext2/dir.c 2004-12-24 14:34:58.000000000 -0700 +++ linux-2.6.10/fs/ext2/dir.c 2006-01-03 16:16:52.000000000 -0700 @@ -426,7 +426,7 @@ ext2_set_de_type (de, inode); err = ext2_commit_chunk(page, from, to); ext2_put_page(page); - dir->i_mtime = dir->i_ctime = CURRENT_TIME; + dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; EXT2_I(dir)->i_flags &= ~EXT2_BTREE_FL; mark_inode_dirty(dir); } @@ -516,7 +516,7 @@ de->inode = cpu_to_le32(inode->i_ino); ext2_set_de_type (de, inode); err = ext2_commit_chunk(page, from, to); - dir->i_mtime = dir->i_ctime = CURRENT_TIME; + dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; EXT2_I(dir)->i_flags &= ~EXT2_BTREE_FL; mark_inode_dirty(dir); /* OFFSET_CACHE */ @@ -564,7 +564,7 @@ pde->rec_len = cpu_to_le16(to-from); dir->inode = 0; err = ext2_commit_chunk(page, from, to); - inode->i_ctime = inode->i_mtime = CURRENT_TIME; + inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC; EXT2_I(inode)->i_flags &= ~EXT2_BTREE_FL; mark_inode_dirty(inode); out: Index: linux-2.6.10/fs/ext2/ialloc.c =================================================================== --- linux-2.6.10.orig/fs/ext2/ialloc.c 2004-12-24 14:34:47.000000000 -0700 +++ linux-2.6.10/fs/ext2/ialloc.c 2006-01-03 16:16:52.000000000 -0700 @@ -577,7 +577,7 @@ inode->i_ino = ino; inode->i_blksize = PAGE_SIZE; /* This is the optimal IO size (for stat), not the fs block size */ inode->i_blocks = 0; - inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC; memset(ei->i_data, 0, sizeof(ei->i_data)); ei->i_flags = EXT2_I(dir)->i_flags & ~EXT2_BTREE_FL; if (S_ISLNK(mode)) Index: linux-2.6.10/fs/ext2/inode.c =================================================================== --- linux-2.6.10.orig/fs/ext2/inode.c 2004-12-24 14:33:51.000000000 -0700 +++ linux-2.6.10/fs/ext2/inode.c 2006-01-03 16:16:52.000000000 -0700 @@ -493,7 +493,7 @@ /* We are done with atomic stuff, now do the rest of housekeeping */ - inode->i_ctime = CURRENT_TIME; + inode->i_ctime = CURRENT_TIME_SEC; /* had we spliced it onto indirect block? */ if (where->bh) @@ -953,7 +953,7 @@ case EXT2_TIND_BLOCK: ; } - inode->i_mtime = inode->i_ctime = CURRENT_TIME; + inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; if (inode_needs_sync(inode)) { sync_mapping_buffers(inode->i_mapping); ext2_sync_inode (inode); Index: linux-2.6.10/fs/ext2/ioctl.c =================================================================== --- linux-2.6.10.orig/fs/ext2/ioctl.c 2004-12-24 14:35:49.000000000 -0700 +++ linux-2.6.10/fs/ext2/ioctl.c 2006-01-03 16:16:52.000000000 -0700 @@ -59,7 +59,7 @@ ei->i_flags = flags; ext2_set_inode_flags(inode); - inode->i_ctime = CURRENT_TIME; + inode->i_ctime = CURRENT_TIME_SEC; mark_inode_dirty(inode); return 0; } @@ -72,7 +72,7 @@ return -EROFS; if (get_user(inode->i_generation, (int __user *) arg)) return -EFAULT; - inode->i_ctime = CURRENT_TIME; + inode->i_ctime = CURRENT_TIME_SEC; mark_inode_dirty(inode); return 0; default: Index: linux-2.6.10/fs/ext2/namei.c =================================================================== --- linux-2.6.10.orig/fs/ext2/namei.c 2004-12-24 14:35:25.000000000 -0700 +++ linux-2.6.10/fs/ext2/namei.c 2006-01-03 16:16:52.000000000 -0700 @@ -211,7 +211,7 @@ if (inode->i_nlink >= EXT2_LINK_MAX) return -EMLINK; - inode->i_ctime = CURRENT_TIME; + inode->i_ctime = CURRENT_TIME_SEC; ext2_inc_count(inode); atomic_inc(&inode->i_count); @@ -337,7 +337,7 @@ goto out_dir; ext2_inc_count(old_inode); ext2_set_link(new_dir, new_de, new_page, old_inode); - new_inode->i_ctime = CURRENT_TIME; + new_inode->i_ctime = CURRENT_TIME_SEC; if (dir_de) new_inode->i_nlink--; ext2_dec_count(new_inode); @@ -362,7 +362,7 @@ * rename. * ext2_dec_count() will mark the inode dirty. */ - old_inode->i_ctime = CURRENT_TIME; + old_inode->i_ctime = CURRENT_TIME_SEC; ext2_delete_entry (old_de, old_page); ext2_dec_count(old_inode); Index: linux-2.6.10/fs/ext2/super.c =================================================================== --- linux-2.6.10.orig/fs/ext2/super.c 2004-12-24 14:35:01.000000000 -0700 +++ linux-2.6.10/fs/ext2/super.c 2006-01-03 16:19:06.000000000 -0700 @@ -595,7 +595,7 @@ es = (struct ext2_super_block *) (((char *)bh->b_data) + offset); sbi->s_es = es; sb->s_magic = le16_to_cpu(es->s_magic); - sb->s_flags |= MS_ONE_SECOND; + set_sb_time_gran(sb, 1000000000U); if (sb->s_magic != EXT2_SUPER_MAGIC) goto cantfind_ext2; Index: linux-2.6.10/fs/ext2/xattr.c =================================================================== --- linux-2.6.10.orig/fs/ext2/xattr.c 2005-04-06 09:38:35.000000000 -0600 +++ linux-2.6.10/fs/ext2/xattr.c 2006-01-03 16:16:52.000000000 -0700 @@ -702,7 +702,7 @@ /* Update the inode. */ EXT2_I(inode)->i_file_acl = new_bh ? new_bh->b_blocknr : 0; - inode->i_ctime = CURRENT_TIME; + inode->i_ctime = CURRENT_TIME_SEC; if (IS_SYNC(inode)) { error = ext2_sync_inode (inode); if (error) Index: linux-2.6.10/fs/ext3/ialloc.c =================================================================== --- linux-2.6.10.orig/fs/ext3/ialloc.c 2004-12-24 14:34:45.000000000 -0700 +++ linux-2.6.10/fs/ext3/ialloc.c 2006-01-03 16:16:52.000000000 -0700 @@ -558,7 +558,7 @@ /* This is the optimal IO size (for stat), not the fs block size */ inode->i_blksize = PAGE_SIZE; inode->i_blocks = 0; - inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC; memset(ei->i_data, 0, sizeof(ei->i_data)); ei->i_next_alloc_block = 0; Index: linux-2.6.10/fs/ext3/inode.c =================================================================== --- linux-2.6.10.orig/fs/ext3/inode.c 2005-04-06 09:38:35.000000000 -0600 +++ linux-2.6.10/fs/ext3/inode.c 2006-01-03 16:16:52.000000000 -0700 @@ -626,7 +626,7 @@ /* We are done with atomic stuff, now do the rest of housekeeping */ - inode->i_ctime = CURRENT_TIME; + inode->i_ctime = CURRENT_TIME_SEC; ext3_mark_inode_dirty(handle, inode); /* had we spliced it onto indirect block? */ @@ -2199,7 +2199,7 @@ ; } up(&ei->truncate_sem); - inode->i_mtime = inode->i_ctime = CURRENT_TIME; + inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; ext3_mark_inode_dirty(handle, inode); /* In a multi-transaction truncate, we only make the final Index: linux-2.6.10/fs/ext3/ioctl.c =================================================================== --- linux-2.6.10.orig/fs/ext3/ioctl.c 2004-12-24 14:34:31.000000000 -0700 +++ linux-2.6.10/fs/ext3/ioctl.c 2006-01-03 16:16:52.000000000 -0700 @@ -87,7 +87,7 @@ ei->i_flags = flags; ext3_set_inode_flags(inode); - inode->i_ctime = CURRENT_TIME; + inode->i_ctime = CURRENT_TIME_SEC; err = ext3_mark_iloc_dirty(handle, inode, &iloc); flags_err: @@ -121,7 +121,7 @@ return PTR_ERR(handle); err = ext3_reserve_inode_write(handle, inode, &iloc); if (err == 0) { - inode->i_ctime = CURRENT_TIME; + inode->i_ctime = CURRENT_TIME_SEC; inode->i_generation = generation; err = ext3_mark_iloc_dirty(handle, inode, &iloc); } Index: linux-2.6.10/fs/ext3/namei.c =================================================================== --- linux-2.6.10.orig/fs/ext3/namei.c 2004-12-24 14:34:58.000000000 -0700 +++ linux-2.6.10/fs/ext3/namei.c 2006-01-03 16:16:52.000000000 -0700 @@ -1251,7 +1251,7 @@ * happen is that the times are slightly out of date * and/or different from the directory change time. */ - dir->i_mtime = dir->i_ctime = CURRENT_TIME; + dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; ext3_update_dx_flag(dir); dir->i_version++; ext3_mark_inode_dirty(handle, dir); @@ -2029,7 +2029,7 @@ * recovery. */ inode->i_size = 0; ext3_orphan_add(handle, inode); - inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; + inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC; ext3_mark_inode_dirty(handle, inode); dir->i_nlink--; ext3_update_dx_flag(dir); @@ -2079,7 +2079,7 @@ retval = ext3_delete_entry(handle, dir, de, bh); if (retval) goto end_unlink; - dir->i_ctime = dir->i_mtime = CURRENT_TIME; + dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC; ext3_update_dx_flag(dir); ext3_mark_inode_dirty(handle, dir); inode->i_nlink--; @@ -2169,7 +2169,7 @@ if (IS_DIRSYNC(dir)) handle->h_sync = 1; - inode->i_ctime = CURRENT_TIME; + inode->i_ctime = CURRENT_TIME_SEC; ext3_inc_count(handle, inode); atomic_inc(&inode->i_count); @@ -2270,7 +2270,7 @@ * Like most other Unix systems, set the ctime for inodes on a * rename. */ - old_inode->i_ctime = CURRENT_TIME; + old_inode->i_ctime = CURRENT_TIME_SEC; ext3_mark_inode_dirty(handle, old_inode); /* @@ -2303,9 +2303,9 @@ if (new_inode) { new_inode->i_nlink--; - new_inode->i_ctime = CURRENT_TIME; + new_inode->i_ctime = CURRENT_TIME_SEC; } - old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME; + old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC; ext3_update_dx_flag(old_dir); if (dir_bh) { BUFFER_TRACE(dir_bh, "get_write_access"); Index: linux-2.6.10/fs/ext3/super.c =================================================================== --- linux-2.6.10.orig/fs/ext3/super.c 2005-04-06 09:38:35.000000000 -0600 +++ linux-2.6.10/fs/ext3/super.c 2006-01-03 16:16:52.000000000 -0700 @@ -1318,7 +1318,7 @@ if (!parse_options ((char *) data, sb, &journal_inum, NULL, 0)) goto failed_mount; - sb->s_flags |= MS_ONE_SECOND; + set_sb_time_gran(sb, 1000000000U); sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | ((sbi->s_mount_opt & EXT3_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0); Index: linux-2.6.10/fs/ext3/xattr.c =================================================================== --- linux-2.6.10.orig/fs/ext3/xattr.c 2005-04-06 09:38:35.000000000 -0600 +++ linux-2.6.10/fs/ext3/xattr.c 2006-01-03 16:16:52.000000000 -0700 @@ -723,7 +723,7 @@ /* Update the inode. */ EXT3_I(inode)->i_file_acl = new_bh ? new_bh->b_blocknr : 0; - inode->i_ctime = CURRENT_TIME; + inode->i_ctime = CURRENT_TIME_SEC; ext3_mark_inode_dirty(handle, inode); if (IS_SYNC(inode)) handle->h_sync = 1; Index: linux-2.6.10/fs/inode.c =================================================================== --- linux-2.6.10.orig/fs/inode.c 2006-01-03 15:33:21.000000000 -0700 +++ linux-2.6.10/fs/inode.c 2006-01-03 16:16:52.000000000 -0700 @@ -1131,19 +1131,6 @@ EXPORT_SYMBOL(bmap); -/* - * Return true if the filesystem which backs this inode considers the two - * passed timespecs to be sufficiently different to warrant flushing the - * altered time out to disk. - */ -static int inode_times_differ(struct inode *inode, - struct timespec *old, struct timespec *new) -{ - if (IS_ONE_SECOND(inode)) - return old->tv_sec != new->tv_sec; - return !timespec_equal(old, new); -} - /** * update_atime - update the access time * @inode: inode accessed @@ -1163,8 +1150,8 @@ if (IS_RDONLY(inode)) return; - now = current_kernel_time(); - if (inode_times_differ(inode, &inode->i_atime, &now)) { + now = current_fs_time(inode->i_sb); + if (!timespec_equal(&inode->i_atime, &now)) { inode->i_atime = now; mark_inode_dirty_sync(inode); } else { @@ -1194,14 +1181,13 @@ if (IS_RDONLY(inode)) return; - now = current_kernel_time(); - - if (inode_times_differ(inode, &inode->i_mtime, &now)) + now = current_fs_time(inode->i_sb); + if (!timespec_equal(&inode->i_mtime, &now)) sync_it = 1; inode->i_mtime = now; if (ctime_too) { - if (inode_times_differ(inode, &inode->i_ctime, &now)) + if (!timespec_equal(&inode->i_ctime, &now)) sync_it = 1; inode->i_ctime = now; } Index: linux-2.6.10/fs/locks.c =================================================================== --- linux-2.6.10.orig/fs/locks.c 2004-12-24 14:35:28.000000000 -0700 +++ linux-2.6.10/fs/locks.c 2006-01-03 16:16:52.000000000 -0700 @@ -1228,7 +1228,7 @@ { struct file_lock *flock = inode->i_flock; if (flock && IS_LEASE(flock) && (flock->fl_type & F_WRLCK)) - *time = CURRENT_TIME; + *time = current_fs_time(inode->i_sb); else *time = inode->i_mtime; } Index: linux-2.6.10/include/linux/fs.h =================================================================== --- linux-2.6.10.orig/include/linux/fs.h 2006-01-03 16:04:26.000000000 -0700 +++ linux-2.6.10/include/linux/fs.h 2006-01-03 16:16:52.000000000 -0700 @@ -124,7 +124,8 @@ #define MS_REC 16384 #define MS_VERBOSE 32768 #define MS_POSIXACL (1<<16) /* VFS does not apply the umask */ -#define MS_ONE_SECOND (1<<17) /* fs has 1 sec a/m/ctime resolution */ +#define MS_ONE_SECOND (1<<17) /* fs has 1 sec time resolution (obsolete) */ +#define MS_TIME_GRAN (1<<18) /* fs has s_time_gran field */ #define MS_ACTIVE (1<<30) #define MS_NOUSER (1<<31) @@ -803,8 +804,33 @@ * even looking at it. You had been warned. */ struct semaphore s_vfs_rename_sem; /* Kludge */ + + /* Granuality of c/m/atime in ns. + Cannot be worse than a second */ +#ifndef __GENKSYMS__ + u32 s_time_gran; +#endif }; +extern struct timespec current_fs_time(struct super_block *sb); + +static inline u32 get_sb_time_gran(struct super_block *sb) +{ + if (sb->s_flags & MS_TIME_GRAN) + return sb->s_time_gran; + if (sb->s_flags & MS_ONE_SECOND) + return 1000000000U; + return 1; +} + +static inline void set_sb_time_gran(struct super_block *sb, u32 time_gran) +{ + sb->s_time_gran = time_gran; + sb->s_flags |= MS_TIME_GRAN; + if (time_gran == 1000000000U) + sb->s_flags |= MS_ONE_SECOND; +} + /* * Snapshotting support. */ Index: linux-2.6.10/include/linux/time.h =================================================================== --- linux-2.6.10.orig/include/linux/time.h 2004-12-24 14:35:00.000000000 -0700 +++ linux-2.6.10/include/linux/time.h 2006-01-03 16:16:52.000000000 -0700 @@ -90,6 +90,7 @@ struct timespec current_kernel_time(void); #define CURRENT_TIME (current_kernel_time()) +#define CURRENT_TIME_SEC ((struct timespec) { xtime.tv_sec, 0 }) extern void do_gettimeofday(struct timeval *tv); extern int do_settimeofday(struct timespec *tv); @@ -103,6 +104,8 @@ extern int do_getitimer(int which, struct itimerval *value); extern void getnstimeofday (struct timespec *tv); +extern struct timespec timespec_trunc(struct timespec t, unsigned gran); + static inline void set_normalized_timespec (struct timespec *ts, time_t sec, long nsec) { Index: linux-2.6.10/kernel/time.c =================================================================== --- linux-2.6.10.orig/kernel/time.c 2004-12-24 14:34:26.000000000 -0700 +++ linux-2.6.10/kernel/time.c 2006-01-03 16:16:52.000000000 -0700 @@ -36,6 +36,7 @@ #include #include +#include /* * The timezone where the local system is located. Used as a default by some @@ -433,6 +434,50 @@ EXPORT_SYMBOL(current_kernel_time); +/** + * current_fs_time - Return FS time + * @sb: Superblock. + * + * Return the current time truncated to the time granuality supported by + * the fs. + */ +struct timespec current_fs_time(struct super_block *sb) +{ + struct timespec now = current_kernel_time(); + return timespec_trunc(now, get_sb_time_gran(sb)); +} +EXPORT_SYMBOL(current_fs_time); + +/** + * timespec_trunc - Truncate timespec to a granuality + * @t: Timespec + * @gran: Granuality in ns. + * + * Truncate a timespec to a granuality. gran must be smaller than a second. + * Always rounds down. + * + * This function should be only used for timestamps returned by + * current_kernel_time() or CURRENT_TIME, not with do_gettimeofday() because + * it doesn't handle the better resolution of the later. + */ +struct timespec timespec_trunc(struct timespec t, unsigned gran) +{ + /* + * Division is pretty slow so avoid it for common cases. + * Currently current_kernel_time() never returns better than + * jiffies resolution. Exploit that. + */ + if (gran <= jiffies_to_usecs(1) * 1000) { + /* nothing */ + } else if (gran == 1000000000) { + t.tv_nsec = 0; + } else { + t.tv_nsec -= t.tv_nsec % gran; + } + return t; +} +EXPORT_SYMBOL(timespec_trunc); + #ifdef CONFIG_TIME_INTERPOLATION void getnstimeofday (struct timespec *tv) {