1. 程式人生 > >理解Linux文件系統掛載參數noatime nodiratime

理解Linux文件系統掛載參數noatime nodiratime

cat dentry 服務器 void program kernel 使用 status 系統

很多線上服務器為了提供文件系統IO性能,會在掛載文件系統的時候指定“noatime,nodiratime”參數,意味著當訪問一個文件和目錄的時候,access time都不會更新。但是如果未指定上面的參數,atime則會更新。那麽具體差異在哪裏?

未指定 noatime,nodiratime

$ touch test ; stat test ;
...
Access: 2015-04-04 00:37:23.507135507 +0800
Modify: 2015-04-04 00:37:23.507135507 +0800
Change: 2015-04-04 00:37:23.507135507 +0800

$ echo hello >> test ; stat
test; ... Access: 2015-04-04 00:37:23.507135507 +0800 Modify: 2015-04-04 00:37:38.018430637 +0800 Change: 2015-04-04 00:37:38.018430637 +0800 $ cat test ;stat test ... Access: 2015-04-04 00:38:02.916135510 +0800 Modify: 2015-04-04 00:37:38.018430637 +0800 Change: 2015-04-04 00:37:38.018430637 +0800

可以看出未指定"noatime,nodiratime"的情況下

  1. read文件的時候會導致atime更新,不會導致mtime和ctime更新
  2. write文件只會導致mtime和ctime更新,不會導致atime更新。

指定 noatime,nodiratime

$touch test ; stat test ; 
...
Access: 2015-04-04 00:28:28.680135484 +0800
Modify: 2015-04-04 00:28:28.680135484 +0800
Change: 2015-04-04 00:28:28.680135484 +0800

$ sleep 10 ; echo hello >> test ; stat test;
...
Access: 2015-04-04 00:28:28.680135484 +0800
Modify: 2015
-04-04 00:28:38.682727983 +0800 Change: 2015-04-04 00:28:38.682727983 +0800 $ cat test ;stat test ... Access: 2015-04-04 00:28:28.680135484 +0800 Modify: 2015-04-04 00:28:38.682727983 +0800 Change: 2015-04-04 00:28:38.682727983 +0800

可以看出指定"noatime,nodiratime"的情況下

  1. read文件的時候不會導致atime、mtime、ctime改變
  2. write文件只會導致mtime和ctime更新,不會導致atime更新。

實際應用場景

在平日裏經常有刪除文件的需求,大概如下

刪除過去N天內都未訪問過的文件或者目錄(刪除N天前訪問過的文件)

$ #註意這條命令很危險! 
$ find /home/fire/ -atime +N -exec rm -rf {} \;

假設 /home/fire 目錄是一周之前創建的,那麽對於這條命令有兩個執行結果

$ #註意這條命令很危險! 
$ find /home/fire/ -atime +7 -exec rm -rf {} \;
  • 指定"noatime":find的時候發現 /home/fire 是7天之前創建的,立馬就會刪除整個目錄。而且還會報錯"find: /home/fire: No such file or directory",原因就是第一個rm -rf /home/fire 之後 find失敗了。這種是很危險的!原因是會誤刪除文件。
  • 未指定"noatime":那就得看情況,如果/home/fire過去7天沒有被訪問過,那麽就和情況一一樣,直接刪除。如果過去7天內,該目錄有人訪問過,atime肯定是7天之內,那麽就會遍歷下面的目錄,依次按照之前邏輯。但是遍歷過程會更改目錄的atime。

看了上面的例子會發現find去刪除目錄的時候變得好復雜,而且一定要小心。所以find刪除更適用於刪除文件,不要刪除目錄。

刪除N天內未被訪問過的文件
$ find /home/fire/ -atime +N -type f -exec rm -f {} \;

註:

上面是轉載的原文,基本沒有問題,但關於禁止文件和目錄的訪問時間,只需指定noatime即可,因為在linux內核中,當指定了noatime,關於nodiratime的判斷也就自動跳過了。

下面是最新穩定版linux 4.13.3內核 中關於這段的代碼說明:

bool __atime_needs_update(const struct path *path, struct inode *inode,
              bool rcu)
{
    struct vfsmount *mnt = path->mnt;
    struct timespec now;

    if (inode->i_flags & S_NOATIME)
        return false;

    /* Atime updates will likely cause i_uid and i_gid to be written
     * back improprely if their true value is unknown to the vfs.
     */
    if (HAS_UNMAPPED_ID(inode))
        return false;

    if (IS_NOATIME(inode))
        return false;
    if ((inode->i_sb->s_flags & MS_NODIRATIME) && S_ISDIR(inode->i_mode))
        return false;

    if (mnt->mnt_flags & MNT_NOATIME)
        return false;
    if ((mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode))
        return false;

    now = current_time(inode);

    if (!relatime_need_update(path, inode, now, rcu))
        return false;

    if (timespec_equal(&inode->i_atime, &now))
        return false;

    return true;
}

生產環境中的Linux內核多沒有這麽新,一般是2.6.32左右的,下面是2.6.32的linux內核關於這一點的說明:

void touch_atime(struct vfsmount *mnt, struct dentry *dentry)
{
    struct inode *inode = 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 (mnt_want_write(mnt))
        return;

    inode->i_atime = now;
    mark_inode_dirty_sync(inode);
    mnt_drop_write(mnt);
}
EXPORT_SYMBOL(touch_atime);

通過查看mount(2)可以看到幾個參數說明:

MS_NOATIME
              Do not update access times for (all types of) files on this file system

MS_NODIRATIME
              Do  not  update access times for directories on this file system.  This flag provides a subset of the functionality provided by MS_NOAT-
              IME; that is, MS_NOATIME implies MS_NODIRATIME.

MS_RELATIME (Since Linux 2.6.20)
              When a file on this file system is accessed, only update the file’s last access time (atime) if the current value of atime is less  than
              or  equal  to the file’s last modification time (mtime) or last status change time (ctime).  This option is useful for programs, such as
              mutt(1), that need to know when a file has been read since it was last modified.  Since Linux 2.6.30, the kernel defaults to the  behav-
              ior  provided  by  this flag (unless MS_NOATIME was specified), and the MS_STRICTATIME flag is required to obtain traditional semantics.
              In addition, since Linux 2.6.30, the file’s last access time is always updated if it is more than 1 day old.

 MS_STRICTATIME (Since Linux 2.6.30)
              Always update the last access time (atime) when files on this file system are accessed.  (This was the  default  behavior  before  Linux
              2.6.30.)  Specifying this flag overrides the effect of setting the MS_NOATIME and MS_RELATIME flags.

通過判定MS_NODIRATIME,如果為真,就不再更新目錄的訪問時間。

上面參數中提到了MS_RELATIME,對於某些用戶某些應用,atime 信息可能是必要的,比如郵件程序和備份工具。如果完全禁止 atime 更新會使這些程序無法正常工作。針對這種情況,Linux 在內核 2.6.20 中添加了一個新的 mount 選項 relatime(relative atime 的意思)。relatime 的意思是訪問文件時,僅在 atime 早於文件的更改時間時對 atime 進行更新。在內核 2.6.24 中,又對 relatime 進行了擴展,在訪問文件時,當 atime 已經超過某個時間(例如一天)沒有更新,就對 atime 進行更新。這個擴展的意思就是調整 atime 的更新粒度。

下面是mount(8)中的參數說明:

relatime
              Update  inode  access times relative to modify or change time.  Access time is only updated if the previous access time was earlier than
              the current modify or change time. (Similar to noatime, but doesn’t break mutt or other applications that need to know  if  a  file  has
              been read since the last time it was modified.)

              Since  Linux  2.6.30,  the  kernel defaults to the behavior provided by this option (unless noatime was  specified), and the strictatime
              option is required to obtain traditional semantics. In addition, since Linux 2.6.30, the file’s last access time is always  updated   if
              it  is more than 1 day old.

strictatime
              Allows to explicitly requesting full atime updates. This makes it possible for kernel to defaults to relatime or noatime but still allow
              userspace to override it. For more details about the default system mount options see /proc/mounts.

使用 relatime(relative atime)掛載,可在前一個 atime 更新比 mtime 或者 ctime 更新舊時更新 atime。

在這個示例中,GFS2 文件系統位於 /dev/vg01/lvol0,並掛載到目錄 /mygfs2。只有在前一個 atime 更新比 mtime 或者 ctime 更新舊時才會進行 atime 更新。

mount /dev/vg01/lvol0 /mygfs2 -o relatime

參考資料:

http://www.firefoxbug.com/index.php/archives/2801/

http://www.cnblogs.com/allegro/archive/2011/04/18/2019598.html

https://mp.weixin.qq.com/s?__biz=MzA3MzYwNjQ3NA==&mid=400742435&idx=1&sn=d5fa0776ebce30be1de897cd7d1eb295&scene=1&srcid=1123K3Ka8EtwjcNXhNfUGJV7#rd

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git/tree/fs/inode.c?h=v4.13.3

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git/tree/fs/inode.c?h=linux-2.6.32.y

理解Linux文件系統掛載參數noatime nodiratime