⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 040_fs_fcntl_c.html

📁 重读linux 2.4.2o所写的笔记
💻 HTML
📖 第 1 页 / 共 2 页
字号:
    }  }  @page {    @top {      content: flow(header);    }    @bottom {      content: flow(footer);    }  }  /* end default print css */ /* custom css *//* end custom css */  /* ui edited css */    body {    font-family: Verdana;        font-size: 10.0pt;    line-height: normal;    background-color: #ffffff;  }    .documentBG {    background-color: #ffffff;  }  /* end ui edited css */</style>   </head>  <body  revision="dcbsxfpf_28j5n5phdd:135">      <table align=center cellpadding=0 cellspacing=0 height=5716 width=802>
  <tbody>
  <tr>
    <td height=5716 valign=top width=802>
      <pre>2007-12-25  <br><br>   这个文件实现了几个系统调用接口.sys_dup sys_dup2  sys_fcntl 和fasync(异步).<br><br><font size=5><b>1.sys_dup sys_dup2</b></font><br><br>  就是clone一个fd到另一个fd,实现本身平淡无奇就是操作 task_struct:struct files_struct *files;数组,其索引就是<br>大名顶顶的fd了. 下面是man dup的简单介绍. <br> dup() and dup2() create a copy of the file descriptor oldfd.<br><br>       After a successful return from dup() or dup2(), the old and new file descriptors may be<br>       used interchangeably.  They refer to the same open file description (see  open(2))  and<br>       thus  share file offset and file status flags; for example, if the file offset is modi-<br>       fied by using lseek(2) on one of the descriptors, the offset is also  changed  for  the<br>       other.<br><br>       <b>The  two  descriptors do not share file descriptor flags (the close-on-exec flag)</b>.<br>      &nbsp;The close-on-exec flag (FD_CLOEXEC; see fcntl(2)) for the duplicate descriptor is off.<br><br>       dup() uses the lowest-numbered unused descriptor for the new descriptor.<br><br>       dup2() makes newfd be the copy of oldfd, closing newfd first if necessary.<br>dup后clos_on_exec将被清除.<br>值得一提的就是task_struct-&gt;files,就是fd的动态增长增加了些复杂度.<br>struct <font color=#000099><b>files_struct</b></font> {<br>	atomic_t count;<br>	rwlock_t file_lock;<br>	int max_fds;<br>	int max_fdset;<br>	int next_fd;<br>	struct file ** <font color=#009900>fd</font>;	/* current fd array,init is fd_arrary */<br>	fd_set *<font color=#009900>close_on_exec</font>;<br>	fd_set *<font color=#009900>open_fds</font>; /*bitmap for open fd_array*/<br>	fd_set close_on_exec_init;<br>	fd_set open_fds_init;<br>	struct file * fd_array[NR_OPEN_DEFAULT]; /*inline fd array*/<br>};<br>sys_dup寻找一个空闲的fd,而sys_dup2则使用指定的fd(老的fd其文件将被释放).<br>动态增长fd的代码就不看了.其实其中的竞争关系,files_struct的各个域的精确涵义值得去体会的...(应该不是个遗憾事...)<br><br><br><font size=5><b>2. fcntl <font size=4>ioctl sysctl</font></b></font><br>  这里是只有fcntl的. 至于sysctl是对系统本身参数的控制. ioctl大部分都是控制驱动程序的. 这些ctl函数提供给user以便于<br>user对内核各个部分做出相应的调整. 其实现本身就是<span style="FONT-SIZE:10.5pt; COLOR:#000000; LINE-HEIGHT:normal">dispatch的过程.<br>  最直接的办法是man,然后看看源代码,知道这个流程即可,具体到特性,那是纷繁复杂,每一个特性都属于不同的领域/特性.<br><font color=#000099><br><b>fcntl overview:</b></font><br></span></pre>
      <ul>
        <li>
          <span style="FONT-SIZE:10.5pt; COLOR:#000000; LINE-HEIGHT:normal">
          Duplicating a file descriptor</span>
        </li>
      </ul>
      <ul>
        <li>
          <span style="FONT-SIZE:10.5pt; COLOR:#000000; LINE-HEIGHT:normal">
          File descriptor flags (close on exec)<br>
          </span>
        </li>
      </ul>
      <pre><span style="FONT-SIZE:10.5pt; COLOR:#000000; LINE-HEIGHT:normal">       F_GETFD<br>              Read the file descriptor flags.<br>       F_SETFD<br>              Set the file descriptor flags to the value specified by arg.<br></span></pre>
      <ul>
        <li>
          <span style="FONT-SIZE:10.5pt; COLOR:#000000; LINE-HEIGHT:normal">
          File status flags</span>
        </li>
      </ul>
      <pre><span style="FONT-SIZE:10.5pt; COLOR:#000000; LINE-HEIGHT:normal">       F_GETFL<br>              Read the file status flags.<br>       F_SETFL<br>              Set the file status flags to the value  specified  by  arg.   File  access  mode<br>              (O_RDONLY,  O_WRONLY,  O_RDWR)  and  file creation flags (i.e., O_CREAT, O_EXCL,<br>              O_NOCTTY, O_TRUNC) in arg are ignored.  On Linux this command  can  only  change<br>              the O_APPEND, O_ASYNC, O_DIRECT, O_NOATIME, and O_NONBLOCK flags.<br></span></pre>
      <ul>
        <li>
          <font color=#006600><span style="FONT-SIZE:10.5pt; COLOR:#000000; LINE-HEIGHT:normal">Advisory
          locking</span></font>
        </li>
      </ul>
      <pre><span style="FONT-SIZE:10.5pt; COLOR:#000000; LINE-HEIGHT:normal">       F_GETLK,  F_SETLK and F_SETLKW are used to acquire, release, and test for the existence<br>       of record locks (also known as file-segment or file-region locks).  The third  argument<br>       lock is a pointer to a structure that has at least the following fields (in unspecified<br>       order).<br><br>         struct <font color=#3333ff><b>flock </b></font>{<br>             ...<br>             short l_type;    /* Type of lock: F_RDLCK,<br>                                 F_WRLCK, F_UNLCK */<br>             short l_whence;  /* How to interpret l_start:<br>                                 SEEK_SET, SEEK_CUR, SEEK_END */<br>             off_t l_start;   /* Starting offset for lock */<br>             off_t l_len;     /* Number of bytes to lock */<br>             pid_t l_pid;     /* PID of process blocking our lock<br>                                 (F_GETLK only) */<br>             ...<br>         };<br></span></pre>
      <ul>
        <li>
          <span style="FONT-SIZE:10.5pt; COLOR:#000000; LINE-HEIGHT:normal">
          Mandatory locking</span>
        </li>
      </ul>
      <pre><span style="FONT-SIZE:10.5pt; COLOR:#000000; LINE-HEIGHT:normal">       (Non-POSIX.)  The above record locks may be either advisory or mandatory, and are advi-<br>       sory by default.<br><br>       Advisory locks are not enforced and are useful only between cooperating processes.<br><br>       Mandatory  locks  are  enforced  for  all  processes.  If a process tries to perform an<br>       incompatible access (e.g., read(2) or write(2)) on a file region that has an incompati-<br>       ble mandatory lock, then the result depends upon whether the O_NONBLOCK flag is enabled<br>       for its open file description.  If the O_NONBLOCK flag is not enabled, then system call<br>       is blocked until the lock is removed or converted to a mode that is compatible with the<br>       access.  If the O_NONBLOCK flag is enabled, then the system call fails with  the  error<br>       EAGAIN or EWOULDBLOCK.<br><br>       To make use of mandatory locks, mandatory locking must be enabled both on the file sys-<br>       tem that contains the file to be locked, and on the file itself.  Mandatory locking  is<br>       enabled  on  a  file  system using the "-o mand" option to mount(8), or the MS_MANDLOCK<br>       flag for mount(2).  Mandatory locking is enabled on a file by disabling  group  execute<br>       permission  on  the file and enabling the set-group-ID permission bit (see chmod(1) and<br>       chmod(2)).<br><br></span><font color=#3333ff>说到文件加锁,linux有两种文件加锁的系统调用:<br>flock, fcntl(lockf就是fcntl). fcntl默认是</font><font color=#3333ff><span style="FONT-SIZE:10.5pt; COLOR:#000000; LINE-HEIGHT:normal">Advisory lock需要</span><span style="FONT-SIZE:10.5pt; COLOR:#000000; LINE-HEIGHT:normal">Mandatory lock是需要以特殊的方式安装文<br>件系统然后再把文件的属性改为:</span></font><span style="FONT-SIZE:10.5pt; COLOR:#000000; LINE-HEIGHT:normal"><span style="FONT-SIZE:10.5pt; COLOR:#000000; LINE-HEIGHT:normal"><font color=#3333ff>disabling  group  execute + enabling the set-group-ID. 然后用fcntl<br>加锁后就是Mandatory lock了.<br>flock只容许对整个文件进行加锁,是BSD风格的. fntl是posix的锁.在linux内部是都是使用 flle_lock来实现<br>的.</font><br>struct <font color=#000099><b>file_lock</b></font> {<br>	struct file_lock *fl_next;	/* singly linked list for this inode  */<br>	struct list_head fl_link;	/* doubly linked list of all locks */<br>	struct list_head fl_block;	/* circular list of blocked processes */<br>	fl_owner_t fl_owner;<br>	unsigned int fl_pid;<br>	wait_queue_head_t fl_wait;<br>	struct file *fl_file;<br>	unsigned char fl_flags;<br>	unsigned char fl_type;<br>	loff_t fl_start;<br>	loff_t fl_end;<br><br>	void (*fl_notify)(struct file_lock *);	/* unblock callback */<br>	void (*fl_insert)(struct file_lock *);	/* lock insertion callback */<br>	void (*fl_remove)(struct file_lock *);	/* lock removal callback */<br><br>	struct fasync_struct *	fl_fasync; /* for lease break notifications */<br><br>	union {<br>		struct nfs_lock_info	nfs_fl;<br>	} fl_u;<br>};<br><br></span></span></pre>
      <ul>
        <li>
          <span style="FONT-SIZE:10.5pt; COLOR:#000000; LINE-HEIGHT:normal"><span style="FONT-SIZE:10.5pt; COLOR:#000000; LINE-HEIGHT:normal">
          Managing signals</span></span>
        </li>
      </ul>
      <pre><span style="FONT-SIZE:10.5pt; COLOR:#000000; LINE-HEIGHT:normal"><span style="FONT-SIZE:10.5pt; COLOR:#000000; LINE-HEIGHT:normal">       F_GETOWN, F_SETOWN, F_GETSIG and F_SETSIG are used to manage I/O availability signals:</span></span></pre>
      <ul>
        <li>
          Leases
        </li>
      </ul>
      <pre>       F_SETLEASE  and F_GETLEASE (Linux 2.4 onwards) are used (respectively) to establish and<br>       retrieve the current setting of the calling process’s lease on the file referred to  by<br>       fd.   A  file  lease  provides  a  mechanism whereby the process holding the lease (the<br>       "lease holder") is notified (via delivery of a  signal)  when  a  process  (the  "lease<br>       breaker") tries to open(2) or truncate(2) that file.<br>关于Leases,man里介绍的很清楚了.<br><br><font color=#3333ff><br>我们来具体看看fcntl的功能,这里仅仅给出一个简单的注释,</font><br>static long <font color=#000099><b>do_fcntl</b></font>(unsigned int fd, unsigned int cmd,<br>		     unsigned long arg, struct file * filp)<br>{<br>	long err = -EINVAL;<br><br>	switch (cmd) {<br>		case F_DUPFD: <font color=#3333ff>/* 类似dup2,但是不是强制以arg为fd,而是dup到arg开始的第一个空闲fd */</font><br>			if (arg &lt; NR_OPEN) {<br>				get_file(filp);<br>				err = dupfd(filp, arg);<br>			}<br>			break;<br>		case F_GETFD: <font color=#000099>/* get set close on exec*/</font><br>                        .....<br>		case F_SETFD:<br>			.....<br>		case F_GETFL: <font color=#3333ff>/*get set filp-&gt;f_flags*/</font><br>                     ......<br>		case F_SETFL:<br>                     .....<br>		<b>case F_GETLK</b>: <font color=#3333ff><b>/*Posix Lock 操作*/</b></font><br>			err = fcntl_getlk(fd, (struct flock *) arg);<br>			break;<br>		<b>case F_SETLK</b>:<br>		<b>case F_SETLKW</b>:<br>			err = fcntl_setlk(fd, cmd, (struct flock *) arg);<br>			break;<br>		case<font color=#3333ff> F_GETOWN</font>: <font color=#3333ff>/*分析dnotify.c的时候说过,owener用于记录当文件发生变化<br>                               需要通知的进程, owener在不同的情景中有不同的用法:<br>                              <font color=#cc0000> 1. dir notify  2.lease(via fl-&gt;fl_fasync) <br>                               3. fasync (via specific fasync queue)</font><br>                               */</font><br>			/*<br>			 * XXX If f_owner is a process group, the<br>			 * negative return value will get converted<br>			 * into an error.  Oops.  If we keep the<br>			 * current syscall conventions, the only way<br>			 * to fix this will be in libc.<br>			 */<br>			err = filp-&gt;f_owner.pid;<br>			break;<br>		case<font color=#3333ff> F_SETOWN:</font><br>			lock_kernel();<br>			filp-&gt;f_owner.pid = arg;<br>			filp-&gt;f_owner.uid = current-&gt;uid;<br>			filp-&gt;f_owner.euid = current-&gt;euid;<br>			err = 0;<br>			if (S_ISSOCK (filp-&gt;f_dentry-&gt;d_inode-&gt;i_mode))<br>				err = sock_fcntl (filp, F_SETOWN, arg);<br>			unlock_kernel();<br>			break;<br>		case <font color=#3333ff>F_GETSIG:</font><br>			err = filp-&gt;f_owner.signum;<br>			break;<br>		case <font color=#3333ff>F_SETSIG</font>:<br>			/* arg == 0 restores default behaviour. */<br>			if (arg &lt; 0 || arg &gt; _NSIG) {<br>				break;<br>			}<br>			err = 0;<br>			filp-&gt;f_owner.signum = arg;<br>			break;<br>		<font color=#cc33cc>case F_GETLEASE:</font><br>			err = fcntl_getlease(filp);<br>			break;<br>		<font color=#cc33cc>case F_SETLEASE:</font><br>			err = fcntl_setlease(fd, filp, arg);<br>			break;<br>		<font color=#336666>case F_NOTIFY: /*dir notify 通知*/</font><br>			err = fcntl_dirnotify(fd, filp, arg);<br>			break;<br>		default:<br>			/* sockets need a few special fcntls. */<br>			err = -EINVAL;<br>			if (S_ISSOCK (filp-&gt;f_dentry-&gt;d_inode-&gt;i_mode))<br>				err = sock_fcntl (filp, cmd, arg);<br>			break;<br>	}<br><br>	return err;<br>}<br><br><font size=5><b>3. fasync</b></font><br><br>这里着重解释下 filp-&gt;f_owner, dnotify, lease,和 fasync直接的关系: 文件异步通知的使用.<br>思路蛮简单的:<br>    一个file结构是一次open特定的(多个file可以使用同一个dentry),也就是说file是一个进程特定的结构,其中的<br>f_owner,用于记录需要获取异步通知的进程之uid/gid/signum等信息, <b>f_owner是需要通知的进程</b>.<br>    然后,有两中方式使用f_owner: <br>1) dnotify_struct -&gt; filep-&gt;f_owner  <br>   dnotify 使用了异步通知机制, dnotify_struct挂接到inode下,需要的时候从inode找到owner,发送一个信号给指定进程.<br>dnotify 创建时直接初始化了owner,设置好了各个参数.<br><br>2) fasync 文件异步通知<br>struct <font color=#000099><b>fasync_struct</b></font> {<br>	int	magic;<br>	int	fa_fd;<br>	struct	fasync_struct	*fa_next; /* singly linked list */<br>	struct	file 		*fa_file;<br>};<br> 其实dir notify也可以用这个东西的,这是一个通用的结构.和dnotify_struct 其实没有什么不同.<br>有两个函数提供fasync: <br><br>  a)生成一个fasync结构,挂接到指定队列.<br>extern int <font color=#3333ff><b>fasync_helper</b></font>(int, struct file *, int, struct fasync_struct **);<br><br>  b)通知指定的owner<br>extern void <font color=#3333ff><b>kill_fasync</b></font>(struct fasync_struct **, int, int);<br><br><br>3)file lease <br>  这是建立在fasync机制上的一个应用. 特殊的地方是挂接到file_lock-&gt;fl_fasync.... (这也能叫特殊啊)<br><br>4)fasync调用<br>file_operations{  fasync }<br>就是调用<font color=#3333ff><b>fasync_helper, </b><font color=#000000>就是队列不同而已. 合适的时候会有sig发送到指定进程....<br>(这个和fsync可不是一对啊)<br><br><br></font></font></pre>
    </td>
  </tr>
  </tbody>
</table></body></html>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -