正在加载...

诡异的mount()

五月 23rd, 2009

最近在2.6.10内核下调试硬盘分区(FAT32文件系统)保护功能,为保护FAT表、根目录和目录项等重要区域,应用程序不得操作这些区域,其中一项就是禁止更新文件访问时间(会更新目录项),使用mount()系统调用时却出现诡异现象。

[ 测试代码 ]

   1: int main()
   2: {
   3:     ... 
   4:  
   5:     mount("/dev/sda1", "/mnt/sda1", "vfat", 0, NULL); 
   6:  
   7:     ... 
   8:  
   9:     /* 读/写sda1分区里的文件 */ 
  10:  
  11:     sync(); 
  12:  
  13:     return 0;
  14: } 

[ 内核修改 ]

   1: /**    -> fs/inode.c
   2:  *    update_atime    -    update the access time
   3:  *    @inode: inode accessed
   4:  *
   5:  *    Update the accessed time on an inode and mark it for writeback.
   6:  *    This function automatically handles read only file systems and media,
   7:  *    as well as the "noatime" flag and inode specific "noatime" markers.
   8:  */
   9: void update_atime(struct inode *inode)
  10: {
  11:     struct timespec now; 
  12:  
  13:     if (IS_NOATIME(inode))
  14:         return;
  15:     if (IS_NODIRATIME(inode) && S_ISDIR(inode->i_mode))
  16:         return;
  17:     if (IS_RDONLY(inode))
  18:         return; 
  19:  
  20: +    if (inode->i_sb) {
  21: +        if (!strcmp(inode->i_sb->s_type->name, "vfat"))
  22: +            __backtrace();
  23: +    }
  24:     now = current_kernel_time();
  25:     if (inode_times_differ(inode, &inode->i_atime, &now)) {
  26:         inode->i_atime = now;
  27:         mark_inode_dirty_sync(inode);
  28:     } else {
  29:         if (!timespec_equal(&inode->i_atime, &now))
  30:             inode->i_atime = now;
  31:     }
  32: } 

测试程序第一次执行时,内核会打印如下调试信息:

   1: <4>Function entered at [<c009443c>] from [<c005bc18>]      /* c009443c T update_atime */
   2: <4> r6 = 00000000  r5 = 00000000  r4 = 00000200 
   3: <4>Function entered at [<c005b6c4>] from [<c005e2b8>]      /* c005b6c4 T do_generic_mapping_read */
   4: <4>Function entered at [<c005e0c0>] from [<c005e41c>]      /* c005e0c0 T __generic_file_aio_read */
   5: <4>Function entered at [<c005e388>] from [<c0078114>]      /* c005e388 T generic_file_read */
   6: <4> r9 = C3026000  r8 = C3027F78</span>  r7 = C005E388  r6 = BEFFF560
   7: <4> r5 = C3CE0A80  r4 = 00000200 
   8: <4>Function entered at [<c0078050>] from [<c0078360>]      /* c0078050 T vfs_read */
   9: <4> r8 = C0025154  r7 = 00000003  r6 = C3CE0A80  r5 = 00000000
  10: <4> r4 = 00000000 
  11: <4>Function entered at [<c0078318>] from [<c00249c0>]      /* c0078318 T sys_read */
  12: <4> r6 = 00000200  r5 = BEFFF560  r4 = 00000003            /* 注释部分结合System.map文件得到 */

接着修改测试代码的mount()调用:

   1: -    mount("/dev/sda1", "/mnt/sda1", "vfat", 0, NULL);
   2: +    mount("/dev/sda1", "/mnt/sda1", "vfat", MS_NOATIME, NULL); 

编译并再次执行测试程序,内核仍打印上面的调试信息,着实让人摸不着头脑。重启Linux系统,执行修改后的测试程序,内核便不再打印上述调试信息!

……

复查测试代码,查看mount()手册页,看到下面几段说明(man-pages 2.77):

MS_REMOUNT
  Remount an existing mount.  This allows you to change the mountflags and data of an  existing
  mount without having to unmount and remount the file system.  source and target should be the
  same values specified in the initial mount() call; filesystemtype is ignored.

  The following mountflags can be changed: MS_RDONLY, MS_SYNCHRONOUS, MS_MANDLOCK;
  before  kernel 2.6.16, the following could also be changed: MS_NOATIME and MS_NODIRATIME;
  and, additionally, before kernel 2.4, the following could also be changed: MS_NOSUID,
  MS_NODEV, MS_NOEXEC.

聪明的你,想到问题在哪儿了吧。:P



“诡异的mount()” 共有1条留言

  1. george On

    为什么要重启电脑呢,mount -a不就可以了吗?

我要留言

麻烦,计算一下:3+7

google reader 抓虾
bloglines my yahoo
哪吒 鲜果
* 更多订阅本站方式请看 订阅帮助