From: Antoine Leca Date: Wed, 21 Dec 2011 22:29:29 +0000 (+0100) Subject: Subsecond timestamps support for FS X-Git-Tag: v3.3.0~1041 X-Git-Url: http://zhaoyanbai.com/repos/Bv9ARM.ch11.html?a=commitdiff_plain;h=4069cef7f95e6ec1e3557f11cf3a5e63842c16d1;p=minix.git Subsecond timestamps support for FS Expand REQ_UTIME to include tv_nsec members (as in struct timespec) in addition to tv_sec==time_t Designed with help from David van Moolenbroek --- diff --git a/include/minix/vfsif.h b/include/minix/vfsif.h index f4aac02cc..35fc94e7d 100644 --- a/include/minix/vfsif.h +++ b/include/minix/vfsif.h @@ -6,6 +6,7 @@ /* VFS/FS request fields */ #define REQ_ACTIME m9_l2 +#define REQ_ACNSEC m9_l4 #define REQ_COUNT m9_l2 #define REQ_DEV m9_l5 #define REQ_DEV2 m9_l1 @@ -19,6 +20,7 @@ #define REQ_MEM_SIZE m9_l5 #define REQ_MODE m9_s3 #define REQ_MODTIME m9_l3 +#define REQ_MODNSEC m9_l5 #define REQ_NBYTES m9_l5 #define REQ_PATH_LEN m9_s2 #define REQ_PATH_SIZE m9_l5 diff --git a/lib/libsffs/stat.c b/lib/libsffs/stat.c index dbac80867..b0aa4550f 100644 --- a/lib/libsffs/stat.c +++ b/lib/libsffs/stat.c @@ -158,11 +158,39 @@ int do_utime() if ((r = verify_inode(ino, path, NULL)) != OK) return r; - attr.a_mask = SFFS_ATTR_ATIME | SFFS_ATTR_MTIME; - attr.a_atime.tv_sec = m_in.REQ_ACTIME; - attr.a_atime.tv_nsec = 0; - attr.a_mtime.tv_sec = m_in.REQ_MODTIME; - attr.a_mtime.tv_nsec = 0; - + attr.a_mask = 0; + + switch(m_in.REQ_ACNSEC) { + case UTIME_OMIT: /* do not touch */ + break; + case UTIME_NOW: + /* XXX VFS should have time() into ACTIME, for compat; we trust it! */ + m_in.REQ_ACNSEC = 0; + /*FALLTHROUGH*/ + default: + /* cases m_in.REQ_ACNSEC < 0 || m_in.REQ_ACNSEC >= 1E9 + * are caught by VFS to cooperate with old instances of EXT2 + */ + attr.a_atime.tv_sec = m_in.REQ_ACTIME; + attr.a_atime.tv_nsec = m_in.REQ_ACNSEC; + attr.a_mask |= SFFS_ATTR_ATIME; + break; + } + switch(m_in.REQ_MODNSEC) { + case UTIME_OMIT: /* do not touch */ + break; + case UTIME_NOW: + /* XXX VFS should have time() into MODTIME, for compat; we trust it! */ + m_in.REQ_MODNSEC = 0; + /*FALLTHROUGH*/ + default: + /* cases m_in.REQ_MODNSEC < 0 || m_in.REQ_MODNSEC >= 1E9 + * are caught by VFS to cooperate with old instances + */ + attr.a_mtime.tv_sec = m_in.REQ_MODTIME; + attr.a_mtime.tv_nsec = m_in.REQ_MODNSEC; + attr.a_mask |= SFFS_ATTR_MTIME; + break; + } return sffs_table->t_setattr(path, &attr); } diff --git a/servers/ext2/time.c b/servers/ext2/time.c index 2db6dcd79..a7b6e948c 100644 --- a/servers/ext2/time.c +++ b/servers/ext2/time.c @@ -6,6 +6,7 @@ #include #include #include "inode.h" +#include #include @@ -21,14 +22,54 @@ int fs_utime() if( (rip = get_inode(fs_dev, (ino_t) fs_m_in.REQ_INODE_NR)) == NULL) return(EINVAL); - /* Only the owner of a file or the super_user can change its time. */ + /* + * Only the owner of a file or the super_user can change the timestamps. + * Here we assume VFS did that check before. + */ + r = OK; if(read_only(rip) != OK) r = EROFS; /* not even su can touch if R/O */ if(r == OK) { - rip->i_atime = fs_m_in.REQ_ACTIME; - rip->i_mtime = fs_m_in.REQ_MODTIME; - rip->i_update = CTIME; /* discard any stale ATIME and MTIME flags */ - rip->i_dirt = IN_DIRTY; + rip->i_update = CTIME; /* discard any stale ATIME and MTIME flags */ + switch(fs_m_in.REQ_ACNSEC) { + case UTIME_NOW: + rip->i_update |= ATIME; + break; + case UTIME_OMIT: /* do not touch */ + break; + default: + /* + * cases fs_m_in.REQ_ACNSEC < 0 || fs_m_in.REQ_ACNSEC >= 1E9 + * are caught by VFS to cooperate with old instances of EXT2 + */ + rip->i_atime = fs_m_in.REQ_ACTIME; + /* + * Ext2FS does not support better than second resolution, + * so we discard REQ_ACNSEC to round down + */ + break; + } + + switch(fs_m_in.REQ_MODNSEC) { + case UTIME_NOW: + rip->i_update |= MTIME; + break; + case UTIME_OMIT: /* do not touch */ + break; + default: + /* + * cases fs_m_in.REQ_MODNSEC < 0 || fs_m_in.REQ_MODNSEC >= 1E9 + * are caught by VFS to cooperate with old instances of EXT2 + */ + rip->i_mtime = fs_m_in.REQ_MODTIME; + /* + * Ext2FS does not support better than second resolution, + * so we discard REQ_MODNSEC to round down + */ + break; + } + + rip->i_dirt = IN_DIRTY; } put_inode(rip); diff --git a/servers/mfs/time.c b/servers/mfs/time.c index 48af75d03..245c1d926 100644 --- a/servers/mfs/time.c +++ b/servers/mfs/time.c @@ -1,5 +1,6 @@ #include "fs.h" #include "inode.h" +#include #include @@ -10,19 +11,59 @@ int fs_utime() { register struct inode *rip; register int r; - + /* Temporarily open the file. */ if( (rip = get_inode(fs_dev, (ino_t) fs_m_in.REQ_INODE_NR)) == NULL) return(EINVAL); - /* Only the owner of a file or the super_user can change its time. */ + /* + * Only the owner of a file or the super_user can change the timestamps. + * Here we assume VFS did that check before. + */ + r = OK; if(read_only(rip) != OK) r = EROFS; /* not even su can touch if R/O */ if(r == OK) { - rip->i_atime = fs_m_in.REQ_ACTIME; - rip->i_mtime = fs_m_in.REQ_MODTIME; - rip->i_update = CTIME; /* discard any stale ATIME and MTIME flags */ - IN_MARKDIRTY(rip); + rip->i_update = CTIME; /* discard any stale ATIME and MTIME flags */ + switch(fs_m_in.REQ_ACNSEC) { + case UTIME_NOW: + rip->i_update |= ATIME; + break; + case UTIME_OMIT: /* do not touch */ + break; + default: + /* + * cases fs_m_in.REQ_ACNSEC < 0 || fs_m_in.REQ_ACNSEC >= 1E9 + * are caught by VFS to cooperate with old instances of MFS + */ + rip->i_atime = fs_m_in.REQ_ACTIME; + /* + * MFS does not support better than second resolution, + * so we discard REQ_ACNSEC to round down + */ + break; + } + + switch(fs_m_in.REQ_MODNSEC) { + case UTIME_NOW: + rip->i_update |= MTIME; + break; + case UTIME_OMIT: /* do not touch */ + break; + default: + /* + * cases fs_m_in.REQ_MODNSEC < 0 || fs_m_in.REQ_MODNSEC >= 1E9 + * are caught by VFS to cooperate with old instances of MFS + */ + rip->i_mtime = fs_m_in.REQ_MODTIME; + /* + * MFS does not support better than second resolution, + * so we discard REQ_MODNSEC to round down + */ + break; + } + + IN_MARKDIRTY(rip); } put_inode(rip); diff --git a/servers/vfs/proto.h b/servers/vfs/proto.h index 7bfff497a..36c3ef0e8 100644 --- a/servers/vfs/proto.h +++ b/servers/vfs/proto.h @@ -12,6 +12,7 @@ /* Structs used in prototypes must be declared as such first. */ struct filp; struct fproc; +struct timespec; struct vmnt; struct vnode; struct lookup; @@ -261,7 +262,8 @@ int req_stat(endpoint_t fs_e, ino_t inode_nr, endpoint_t proc_e, vir_bytes buf); int req_sync(endpoint_t fs_e); int req_unlink(endpoint_t fs_e, ino_t inode_nr, char *lastc); int req_unmount(endpoint_t fs_e); -int req_utime(endpoint_t fs_e, ino_t inode_nr, time_t actime, time_t modtime); +int req_utime(endpoint_t fs_e, ino_t inode_nr, struct timespec * actv, + struct timespec * modtv); int req_newdriver(endpoint_t fs_e, dev_t dev, char *label); /* stadir.c */ @@ -291,7 +293,7 @@ int tll_unlock(tll_t *tllp); void tll_upgrade(tll_t *tllp); /* utility.c */ -time_t clock_time(void); +struct timespec clock_timespec(void); unsigned conv2(int norm, int w); long conv4(int norm, long x); int copy_name(size_t len, char *dest); diff --git a/servers/vfs/request.c b/servers/vfs/request.c index 443ba6905..4eab2791e 100644 --- a/servers/vfs/request.c +++ b/servers/vfs/request.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include "fproc.h" #include "vmnt.h" #include "vnode.h" @@ -1038,19 +1038,21 @@ endpoint_t fs_e; /*===========================================================================* * req_utime * *===========================================================================*/ -int req_utime(fs_e, inode_nr, actime, modtime) -endpoint_t fs_e; -ino_t inode_nr; -time_t actime; -time_t modtime; +int req_utime(endpoint_t fs_e, ino_t inode_nr, struct timespec * actimespec, + struct timespec * modtimespec) { message m; + assert(actimespec != NULL); + assert(modtimespec != NULL); + /* Fill in request message */ m.m_type = REQ_UTIME; m.REQ_INODE_NR = inode_nr; - m.REQ_ACTIME = actime; - m.REQ_MODTIME = modtime; + m.REQ_ACTIME = actimespec->tv_sec; + m.REQ_MODTIME = modtimespec->tv_sec; + m.REQ_ACNSEC = actimespec->tv_nsec; + m.REQ_MODNSEC = modtimespec->tv_nsec; /* Send/rec request */ return fs_sendrec(fs_e, &m); diff --git a/servers/vfs/time.c b/servers/vfs/time.c index 54d71f2e8..2695dc837 100644 --- a/servers/vfs/time.c +++ b/servers/vfs/time.c @@ -7,6 +7,7 @@ #include "fs.h" #include #include +#include #include "file.h" #include "fproc.h" #include "path.h" @@ -22,7 +23,7 @@ int do_utime() { /* Perform the utime(name, timep) system call. */ int r; - time_t actime, modtime, newactime, newmodtime; + struct timespec actim, modtim, newactim, newmodtim; struct vnode *vp; struct vmnt *vmp; char fullpath[PATH_MAX]; @@ -32,8 +33,9 @@ int do_utime() vname = (vir_bytes) job_m_in.utime_file; vname_length = (size_t) job_m_in.utime_length; - actime = job_m_in.utime_actime; - modtime = job_m_in.utime_modtime; + actim.tv_sec = job_m_in.utime_actime; + modtim.tv_sec = job_m_in.utime_modtime; + actim.tv_nsec = modtim.tv_nsec = 0; /* Adjust for case of 'timep' being NULL; * utime_strlen then holds the actual size: strlen(name)+1 */ @@ -48,7 +50,7 @@ int do_utime() if (fetch_name(vname, len, fullpath) != OK) return(err_code); if ((vp = eat_path(&resolve, fp)) == NULL) return(err_code); - /* Only the owner of a file or the super user can change its name. */ + /* Only the owner of a file or the super user can change timestamps. */ r = OK; if (vp->v_uid != fp->fp_effuid && fp->fp_effuid != SU_UID) r = EPERM; if (vname_length == 0 && r != OK) r = forbidden(fp, vp, W_BIT); @@ -56,12 +58,12 @@ int do_utime() if (r == OK) { /* Issue request */ if (vname_length == 0) { - newactime = newmodtime = clock_time(); + newactim = newmodtim = clock_timespec(); } else { - newactime = actime; - newmodtime = modtime; + newactim = actim; + newmodtim = modtim; } - r = req_utime(vp->v_fs_e, vp->v_inode_nr, newactime, newmodtime); + r = req_utime(vp->v_fs_e, vp->v_inode_nr, &newactim, &newmodtim); } unlock_vnode(vp); diff --git a/servers/vfs/utility.c b/servers/vfs/utility.c index f4476f679..1af39f7e6 100644 --- a/servers/vfs/utility.c +++ b/servers/vfs/utility.c @@ -1,7 +1,7 @@ /* This file contains a few general purpose utility routines. * * The entry points into this file are - * clock_time: ask the clock task for the real time + * clock_timespec: ask the clock task for the real time * copy: copy a block of data * fetch_name: go get a path name from user space * no_sys: reject a system call that FS does not handle @@ -18,6 +18,7 @@ #include #include #include +#include #include "file.h" #include "fproc.h" #include "param.h" @@ -141,9 +142,9 @@ int isokendpt_f(char *file, int line, endpoint_t endpoint, int *proc, /*===========================================================================* - * clock_time * + * clock_timespec * *===========================================================================*/ -time_t clock_time() +struct timespec clock_timespec(void) { /* This routine returns the time in seconds since 1.1.1970. MINIX is an * astrophysically naive system that assumes the earth rotates at a constant @@ -151,15 +152,20 @@ time_t clock_time() */ register int r; + struct timespec tv; clock_t uptime; clock_t realtime; time_t boottime; r = getuptime(&uptime, &realtime, &boottime); if (r != OK) - panic("clock_time err: %d", r); + panic("clock_timespec err: %d", r); - return( (time_t) (boottime + (realtime/system_hz))); + tv.tv_sec = (time_t) (boottime + (realtime/system_hz)); + /* We do not want to overflow, and system_hz can be as high as 50kHz */ + assert(system_hz < LONG_MAX/40000); + tv.tv_nsec = (realtime%system_hz) * 40000 / system_hz * 25000; + return tv; } /*===========================================================================*