MNT_RELATIME
MNT_RELATIMEはinode->i_atime更新下の条件で、MNT_NOATIMEならMNT_RELATIMEに係る影響ないのに、mntフラグのMNT_RELATIME設定はMNT_NOATIMに係る設定となっていて、MNT_RELATIME自体の設定は実装されていない。
ファイル/ディレクトリ参照時に、atim更新のfile_accessed()がコールされ、MNT_NOATIMEでないなら、touch_atime()がコールされMNT_RELATIMEに係る条件でatimeが更新される。
- mntフラグ設定
mnt_flags = MNT_RELATIME;
if (flags & MS_NOATIME) {
mnt_flags |= MS_NOATIME;
}
でなく
mnt_flags = 0;
if (flags & MS_NOATIME) {
mnt_flags |= MS_NOATIME;
}
else {
mnt_flags |= MNT_RELATIME;
}
- atime更新
if (!mnt->mnt_flags & MNT_NOATIME) {
if (mnt->mnt_flags & MNT_RELATIME)) {
if (inode->i_mtime > inode->i_atime ||
inode->i_ctime > inode->i_atime ||
time - inode->i_atime > 24*60*60) {
inode->i_atime = time;
}
}
}
else {
inode->i_atime = time;
}
}
これは、mntコマンド属性表示のMNT_RELATIMEならMNT_NOATIMEでない旨とする意味合いの属性とする運用上故かと、従ってMNT_NOATIMEでMNT_RELATIMEと成り得ない。MS_STRICTATIMEは、MNT_RELATIME/MNT_NOATIMEがクリアされ、i_atimeは無条件に更新される。ただしMS_NODIRATIMEならディレクトリは更新されない。mntコマンドの属性表示でMNT_RELATIME/MNT_NOATIMEが表示されていないなら、MS_STRICTATIME。サンプル
[root@localhost /]# mount /dev/sda5 /mnt5 [root@localhost /]# mount /dev/sda6 /mnt6 -o noatime [root@localhost /]# mount /dev/sda7 /mnt7 -o strictatime [root@localhost /]# mount : /dev/sda5 on /mnt5 type ext3 (rw,relatime,data=ordered) /dev/sda6 on /mnt6 type ext3 (rw,noatime,data=ordered) /dev/sda7 on /mnt7 type ext3 (rw,data=ordered)
カーネル
mnt_flagsはブロックデバイスに係るフラグ、flagsはファイルシステムに係るフラグで、MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_ACTIVE | MS_BORN | MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT | MS_STRICTATIME以外のフラグはファイルシステムに依存し、mnt bind/mntフラグの変更は、flagsに係る属性のみである。ファイル/ディレクトリ参照時に、atim更新のfile_accessed()がコールされ、MNT_NOATIMEでないなら、touch_atime()がコールされMNT_RELATIMEに係る条件でatimeが更新される。
#define MS_MGC_VAL 0xC0ED0000
#define MS_MGC_MSK 0xffff0000
#define MS_NOATIME 1024 /* Do not update access times. */
#define MS_NODIRATIME 2048 /* Do not update directory access times */
#define MS_RELATIME (1<<21) /* Update atime relative to mtime/ctime. */
long do_mount(const char *dev_name, const char *dir_name,
const char *type_page, unsigned long flags, void *data_page)
{
struct path path;
int retval = 0;
int mnt_flags = 0;
if ((flags & MS_MGC_MSK) == MS_MGC_VAL)
flags &= ~MS_MGC_MSK;
if (!dir_name || !*dir_name || !memchr(dir_name, 0, PAGE_SIZE))
return -EINVAL;
if (data_page)
((char *)data_page)[PAGE_SIZE - 1] = 0;
retval = kern_path(dir_name, LOOKUP_FOLLOW, &path);
if (retval)
return retval;
retval = security_sb_mount(dev_name, &path,
type_page, flags, data_page);
if (retval)
goto dput_out;
if (!(flags & MS_NOATIME))
mnt_flags |= MNT_RELATIME;
if (flags & MS_NOSUID)
mnt_flags |= MNT_NOSUID;
if (flags & MS_NODEV)
mnt_flags |= MNT_NODEV;
if (flags & MS_NOEXEC)
mnt_flags |= MNT_NOEXEC;
if (flags & MS_NOATIME)
mnt_flags |= MNT_NOATIME;
if (flags & MS_NODIRATIME)
mnt_flags |= MNT_NODIRATIME;
if (flags & MS_STRICTATIME)
mnt_flags &= ~(MNT_RELATIME | MNT_NOATIME);
if (flags & MS_RDONLY)
mnt_flags |= MNT_READONLY;
flags &= ~(MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_ACTIVE | MS_BORN |
MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT |
MS_STRICTATIME);
if (flags & MS_REMOUNT)
retval = do_remount(&path, flags & ~MS_REMOUNT, mnt_flags,
data_page);
else if (flags & MS_BIND)
retval = do_loopback(&path, dev_name, flags & MS_REC);
else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
retval = do_change_type(&path, flags);
else if (flags & MS_MOVE)
retval = do_move_mount(&path, dev_name);
else
retval = do_new_mount(&path, type_page, flags, mnt_flags,
dev_name, data_page);
dput_out:
path_put(&path);
return retval;
}
ファイル/ディレクトリ参照時のdo_generic_file_read()/vfs_readdir()からfile_accessed()がコールされ、かかるfileのinode->atimeが更新される。
static inline void file_accessed(struct file *file)
{
if (!(file->f_flags & O_NOATIME))
touch_atime(&file->f_path);
}
void touch_atime(struct path *path)
{
struct vfsmount *mnt = path->mnt;
struct inode *inode = path->dentry->d_inode;
struct timespec now;
if (inode->i_flags & S_NOATIME)
return;
if (IS_NOATIME(inode))
return;
if ((inode->i_sb->s_flags & MS_NODIRATIME) && S_ISDIR(inode->i_mode))
return;
if (mnt->mnt_flags & MNT_NOATIME)
return;
if ((mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode))
return;
now = current_fs_time(inode->i_sb);
if (!relatime_need_update(mnt, inode, now))
return;
if (timespec_equal(&inode->i_atime, &now))
return;
if (!sb_start_write_trylock(inode->i_sb))
return;
if (__mnt_want_write(mnt))
goto skip_update;
update_time(inode, &now, S_ATIME);
__mnt_drop_write(mnt);
skip_update:
sb_end_write(inode->i_sb);
}
static int relatime_need_update(struct vfsmount *mnt, struct inode *inode,
struct timespec now)
{
if (!(mnt->mnt_flags & MNT_RELATIME))
return 1;
if (timespec_compare(&inode->i_mtime, &inode->i_atime) >= 0)
return 1;
if (timespec_compare(&inode->i_ctime, &inode->i_atime) >= 0)
return 1;
if ((long)(now.tv_sec - inode->i_atime.tv_sec) >= 24*60*60)
return 1;
return 0;
}






