MNT_RELATIME
Rev.1を表示中。最新版はこちら。
MNT_RELATIMEはinode->i_atime更新下の条件で、MNT_NOATIMEならMNT_RELATIMEに係る影響ないのに、mntフラグのMNT_RELATIME設定はMNT_NOATIMに係る設定となっていて、MNT_RELATIME自体の設定は実装されていない。- 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以外のフラグはファイルシステムに依存する。ファイル/ディレクトリ参照時に、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; }