home *** CD-ROM | disk | FTP | other *** search
/ DOS/V Power Report 2004 March / VPR0403.ISO / talks / 294 / paper.dkb < prev    next >
Encoding:
Extensible Markup Language  |  2003-09-18  |  33.5 KB  |  724 lines

  1. <?xml version="1.0" encoding="ISO-8859-1"?>
  2. <article id="paper-294">
  3.   <articleinfo>
  4.     <title>XFS for Linux</title>
  5.     <author>
  6.       <firstname>Christoph</firstname>
  7.       <surname>Hellwig</surname>
  8.     </author>
  9.     <author>
  10.       <firstname>Russell</firstname>
  11.       <surname>Cattelan</surname>
  12.     </author>
  13.     <author>
  14.       <firstname>Steve</firstname>
  15.       <surname>Lord</surname>
  16.     </author>
  17.     <author>
  18.       <firstname>Jim</firstname>
  19.       <surname>Mostek</surname>
  20.     </author>
  21.     <copyright>
  22.       <year>2003</year>
  23.       <holder>SGI Inc.</holder>
  24.     </copyright>
  25.   </articleinfo>
  26.  
  27. <section>
  28. <title>
  29. Abstract
  30. </title>
  31.  
  32. <para>
  33. The limitations of traditional file systems were becoming evident as new application demands arose and
  34. larger hardware became available for SGI's MIPS-based systems and later for Intel-based Linux systems.
  35. This paper describes advanced and uniqueue features of
  36. SGI's XFS filesystem for IRIX and Linux, lessons learned during development and porting of XFS
  37. and explains the differences beteen the IRIX and Linux implementations of XFS.
  38. </para>
  39.  
  40. </section>
  41. <section>
  42. <title>
  43. Introduction to XFS
  44. </title>
  45.  
  46. <para>
  47. In the early 1990s, SGI realized its existing file system, EFS (Extent File System) would be
  48. inadequate to support the new application demands arising from the increased disk capacity,
  49. bandwidth, and parallelism available on its systems. Applications in film and video, supercomputing,
  50. and huge databases all required performance and capacities beyond what EFS, with a design similar
  51. to the Berkeley Fast File System, could provide. EFS limitations were similar to those found in
  52. Linux file systems until a few years ago: small file system sizes (8 gigabytes), small file sizes
  53. (2 gigabytes), statically allocated metadata, and slow recovery times using fsck.
  54.  
  55. To address these issues in EFS, in 1994 SGI released an advanced, journaled file system on IRIX;
  56. this file system was called XFS. Since that time, XFS has proven itself in production as a fast,
  57. highly scalable file system suitable for computer systems ranging from the desktop to supercomputers.
  58.  
  59. To help address these same issues in Linux SGI has made XFS technology available for Linux
  60. under the GNU General Public License (GPL).
  61. </para>
  62.  
  63. <section>
  64. <title>
  65. Features
  66. </title>
  67.  
  68. <para>
  69. XFS uses B+ trees extensively in place of traditional linear file system structures. B+ trees
  70. provide an efficient indexing method that is used to rapidly locate free space, to index directory
  71. entries, to manage file extents, and to keep track of the locations of file index information
  72. within the file system. XFS is a fully 64-bit file system. Most of the global counters in the
  73. system are 64-bits in length, as are the addresses used for each disk block and the unique
  74. number assigned to each file (the inode number). A single file system can theoretically be as
  75. large as 18 million terabytes. The file system is partitioned into regions called Allocation Groups
  76. (AG). Like UFS cylinder groups, each AG manages its own free space and inodes. The primary purpose
  77. of Allocation Groups is to provide scalability and parallelism within the file system. This
  78. partitioning also limits the size of the structures needed to track this information and allows
  79. the internal pointers to be 32-bits. AGs typically range in size from 0.5 to 4GB. Files and
  80. directories are not limited to allocating space within a single AG.
  81. </para>
  82. <para>
  83. XFS has a variety of sophisticated support utilities to enhance its usability. These include fast
  84. mkfs (make a file system), dump and restore utilities for backup, xfsdb (XFS debug), xfscheck
  85. (XFS check), and xfsrepair to perform file system checking and repairing. The xfs fsr utility
  86. defragments existing XFS file systems. The xfs bmap utility can be used to interpret the metadata
  87. layouts for an XFS file system. The growfs utility allows XFS file systems to be enlarged on-line.
  88. </para>
  89.  
  90. </section>
  91. <section>
  92. <title>
  93. Architecture
  94. </title>
  95.  
  96. <para>
  97. The high level structure of XFS is similar to a conventional file system with the addition of a
  98. transaction manager. XFS supports all of the standard Unix file interfaces and is entirely POSIX
  99. and XPG4compliant. It sits below the vnode interface in the IRIX kernel and takes full advantage
  100. of services provided by the kernel, including the buffer/page cache, the directory name lookup cache,
  101. and the dynamic vnode cache.
  102. </para>
  103. <para>
  104. XFS is modularized into several parts, each of which is responsible for a separate piece of the file
  105. system's functionality. The central and most important piece of the file system is the space manager.
  106. This module manages the file system free space, the allocation of inodes, and the allocation of space
  107. within individual files. The I/O manager is responsible for satisfying file I/O requests and depends
  108. on the space manager for allocating and keeping track of space for files. The directory manager
  109. implements the XFS file system name space. The buffer cache is used by all of these pieces to cache
  110. the contents of frequently accessed blocks from the underlying volume in memory. It is an integrated
  111. page and file cache shared by all file systems in the kernel. The transaction manager is used by the
  112. other pieces of the file system to make all updates to the metadata of the file system atomic. This
  113. enables the quick recovery of the file system after a crash. While the XFS implementation is modular,
  114. it is also large and complex. The current implementation is over 110,000 lines of C code (not including
  115. the buffer cache or user-level XFS utilities); in contrast, the EFS implementation is approximately
  116. 12,000 lines.
  117. </para>
  118. </section>
  119. <section>
  120. <title>
  121. Journaling
  122. </title>
  123. <para>
  124. XFS journals metadata updates by first writing them to an in-core log buffer, then asynchronously
  125. writing log buffers to the on-disk log. The on-disk log is a circular buffer: new log entries are
  126. written to the head of the log, and old log entries are removed from the tail once the inplace
  127. metadata updates occur.  After a crash, the on-disk log is read by the recovery code which is called
  128. during a mount operation. XFS metadata modifications use transactions: create, remove, link, unlink,
  129. allocate, truncate, and rename operations all require transactions. This means the operation,
  130. from the standpoint of the file system on-disk metadata, either never starts or always completes.
  131. These operations are never partially completed on-disk: they either happened or they didn't.
  132. Transactional semantics are required for databases, but until recently have not been considered
  133. necessary for file systems. This is likely to change, as huge disks and file systems require the
  134. fast recovery and good performance journaling can provide. An important aspect of journaling is
  135. write-ahead logging: metadata objects are pinned in kernel memory while the transaction is being
  136. committed to the on-disk log. The metadata is unpinned once the in-core log has been written to
  137. the on-disk log. Note that multiple transactions may be in each in-core log buffer. Multiple
  138. in-core log buffers allow for transactions when another buffer is being written. Each transaction
  139. requires space reservation from the log system (i.e., the maximum number of blocks this transaction
  140. may need to write.) All metadata objects modified by an operation, e.g., create, must be contained
  141. in one transaction.
  142. </para>
  143. </section>
  144. </section>
  145.  
  146. <section>
  147. <title>
  148. Porting XFS to Linux
  149. </title>
  150.  
  151. <section>
  152. <title>
  153. The vnode/vfs interface in IRIX
  154. </title>
  155.  
  156. <para>
  157. The vnode/vfs file system interface was developed in the mid-80s to allow the UNIX
  158. kernel to support multiple file systems simultaneously. Up to that time, UNIX kernels typically
  159. supported a single file system that was bolted directly into the kernel internals. With the
  160. advent of local area networks in the mid-80s, file sharing across networks became possible,
  161. and it was necessary to allow multiple file system types to be installed into the kernel.
  162. The vnode/vfs interface separates the file-systemindependent vnode from the file-system-dependent
  163. inode. This separation allows new file systems to re-use existing file-system-independent code,
  164. and, at least in theory, to be developed indepently of the internal kernel data structures.
  165. IRIX and XFS use the following major structures to interface between the file system and the
  166. rest of the IRIX OS components:
  167. </para>
  168.  
  169. <itemizedlist>
  170. <listitem><para>
  171. vfs ュ Virtual File System structure.
  172. </para></listitem>
  173. <listitem><para>
  174. vnode ュ Virtual node (as opposed to inode)
  175. </para></listitem>
  176. <listitem><para>
  177. bhv desc ュ behaviors are used for file system stacking
  178. </para></listitem>
  179. <listitem><para>
  180. buf ュ used as an interface to store data in memory (to and from disk)
  181. </para></listitem>
  182. <listitem><para>
  183. xfs mount ュ top-level per XFS file system structure
  184. </para></listitem>
  185. <listitem><para>
  186. xfs inode ュ top-level per XFS file structure.
  187. </para></listitem>
  188. </itemizedlist>
  189.  
  190. <para>
  191. The vnode structure points at the first behavior in the chain of file systems handling the file
  192. associated with this vnode.  The behavior also points to the function vector, xfs vnodeops, which contains all the
  193. file-system-specific routines at the file level. In IRIX, the vnodeops contains more than 57
  194. routines which can be invoked on a "file". These routines cover many functions such as create, remove,
  195. read, write, open, close, and others.
  196. </para>
  197.  
  198. </section>
  199. <section>
  200. <title>
  201. Mapping the vnode/vfs interface to Linux
  202. </title>
  203.  
  204. <para>
  205. Changing XFS to fit directly into Linux VFS interface would require significant changes to a
  206. large portion of the XFS codebase. The current source code organization would need to be
  207. significantly changed and code charing between the IRIX and Linux versions of XFS would
  208. become much more difficult.  The alternative is to integrate the vnode and vfs object as
  209. private file-system-dependent data in the struct inode and struct super block data in Linux.
  210. This approach introduces a translation layer between the XFS code and the Linux VFS interface
  211. which translate Linux VFS calls into the equivalent XFS vnode operations. The XFS vnode itself
  212. is attached to the private data area of the Linux inode, while the XFS vfs object is attached
  213. to the private data area of the Linux superblock.
  214. </para>
  215.  
  216. <para>
  217. In the initial Linux port of XFS the vnode and vfs operations remained almost unchanged from
  218. IRIX and the translation layer, called linvfs, had to a certain amount of argument and
  219. semantics remapping.  For example in IRIX the read/write entry points use the uio structures
  220. that allows to pass multiple I/O requests in one call to the filesystems while the Linux
  221. read/write entry points use a much simpler scheme with one I/O request per call.  In later
  222. revisions of XFS for Linux some vnode/vfs operations where changed to fit the Linux model
  223. better.  For example the lookup, create and rename VOPs now pass down the Linux dentry
  224. structure that describe a directory entry in all it's details insyead of just the name
  225. as in IRIX.  This allows getting rid of superflous internal lookups calls and access/race
  226. checks already handled in the generic Linux code.  A result of these changes is that more than
  227. 2,000 lines of code that were required on IRIX could be removed from the Linux XFS.
  228. </para>
  229.  
  230. <para>
  231. Another example are the already mentioned read/write entry points that got simplified
  232. to match their Linux counterparts.
  233. </para>
  234.  
  235. </section>
  236. <section>
  237. <title>
  238. fcntl Versus ioctl in IRIX and Linux
  239. </title>
  240.  
  241. <para>
  242. In IRIX, XFS supports approximately 20 special fcntl interfaces used for space pre-allocation,
  243. extent retrieval, extended file information, etc. In addition, IRIX XFS has about a dozen
  244. special system call interfaces, all implemented via the special syssgi system call.
  245. These interfaces are used for operations such as growing the file system or retrieving internal
  246. file system information.
  247. </para>
  248.  
  249. <para>
  250. The Linux file system interface has no fcntl operation. The only supported fcntl calls on Linux
  251. are file locking calls. We proposed to the Linux community that a fnctl file operation be added.
  252. After extensive discussion, it was decided to use the existing ioctl operation, linvfs_ioctl,
  253. and all of the fcntl and syssgi usages have been converted into ioctls. A shortcoming to the
  254. ioctl approach is in the semantics of an ioctl to block or character special devices which
  255. reside within the file system: In these cases, the device driver's ioctl routine will be used
  256. rather than the file system's. Outside of that, porting the fcntl and syssgi interfaces to
  257. ioctl's has been straightforward.
  258. </para>
  259.  
  260. </section>
  261. <section>
  262. <title>
  263. IRIX XFS creds and Linux
  264. </title>
  265.  
  266. <para>
  267. In older UNIX systems, the file system code used the current process's data structures to
  268. determine the user's credentials such as uid, gid, capabilities, etc. The VFS/vnode interface
  269. removed this code and introduced a cred structure which is passed to certain file system
  270. operations such as create and lookup. The file system uses this information to determine
  271. permissions and ownership.
  272.  
  273. </para>
  274. <para>
  275.  
  276. XFS was written using the VOP/vnode interface, so it regularly uses cred structures. One of
  277. the more prevalent cred usages on IRIX XFS is get_current_cred, which returns this structure
  278. for the current process.
  279.  
  280. </para>
  281. <para>
  282.  
  283. Linux is similar to older UNIX implementations in that file systems are expected to look
  284. directly at the task structure to determine the current process's credentials. Linux does not
  285. utilize a cred structure.
  286.  
  287. </para>
  288. <para>
  289.  
  290. In porting XFS to Linux, we first attempted to map the various cred fields onto the
  291. corresponding task fields. This had the undesired side-effect of producing code that
  292. utilized a cred pointer that in actuality was pointing at a task. This was determined
  293. to be unacceptable.
  294.  
  295. </para>
  296. <para>
  297.  
  298. We then considered implementing a complete cred infrastructure, which would include a pool
  299. of active creds, cred setup, teardown, lookup, etc. It was determined that this would require
  300. too much overhead.
  301.  
  302. </para>
  303. <para>
  304.  
  305. In looking at the Linux code, we saw that all of the access/permission work occurs above
  306. the file system dependent code, so having a cred is important only on creation. We then
  307. examined our own internal usage of cred fields in XFS, and found that more often than not,
  308. a cred was passed down through a VOP_, and never used. The few places that did use a
  309. cred field were changed to use the current task structure in Linux.
  310.  
  311. </para>
  312. <para>
  313.  
  314. Early versions of the XFS Linux port still passed a cred address on the VOPs, but we changed
  315. the linvfs later to always pass NULL into the cred arguments.
  316.  
  317. </para>
  318. <para>
  319.  
  320. In addition to these cred changes, we have removed many access checks from the XFS code
  321. since these are now performed at a higher layer and are redundant in the file system
  322. dependent code
  323.  
  324. </para>
  325. </section>
  326. </section>
  327.  
  328. <section>
  329. <title>
  330. XFS Caching and I/O
  331. </title>
  332.  
  333. <para>
  334. When XFS was first implemented within IRIX, the buffer cache was enhanced in a number
  335. of ways to better support XFS, both for better file I/O performance and for better
  336. journaling performance. The IRIX implementation of XFS depends on this buffer cache
  337. functionality for several key facilities.
  338. </para>
  339. <para>
  340. First, the buffer cache allows XFS to store file data which has been written by an
  341. application without first allocating space on disk. The routines which flush delayed
  342. writes are prepared to call back into XFS, when necessary, to get XFS to assign disk
  343. addresses for such blocks when it is time to flush the blocks to disk. Since delayed
  344. allocation means that XFS can determine if a large number of blocks have been written
  345. before it allocates space, XFS is able to allocate large extents for large files,
  346. without having to reallocate or fragment storage when writing small files. This facility
  347. allows XFS to optimize transfer sizes for writes, so that writes can proceed at close
  348. to the maximum speed of the disk, even if the application does its write operations
  349. in small blocks. In addition, if a file is removed and its written data is still in
  350. delayed allocation extents, the data can be discarded without ever allocating disk space.
  351. </para>
  352. <para>
  353. Second, the buffer cache provides a reservation scheme, so that blocks with delayed
  354. allocation will not result in deadlock. If too much of the available memory is used for
  355. delayed allocation, a deadlock on the memory occurs when trying to do conversion from
  356. delayed to real allocations. The deadlock can occur since the conversion requires
  357. metadata reads and writes which need available memory.
  358. </para>
  359. <para>
  360. Third, the buffer cache and the interface to disk drivers support the use of a single
  361. buffer object to refer to as much as an entire disk extent, even if the extent is
  362. very large and the buffered pages in memory are not contiguous. This is important
  363. for high performance, since allocating, initializing, and processing a control block
  364. for each disk block in, for example, a 7 MB HDTV video frame, would represent a large
  365. amount of processor overhead, particularly when one considers the cost of cache misses
  366. on modern processors. XFS has been able to deliver 7 GB/second from a single file on an
  367. SGI Origin 2000 system, so the overhead of processing millions of control blocks per
  368. second is of practical significance.
  369. </para>
  370. <para>
  371. Fourth, the buffer cache supports "pinning" buffered storage in memory, which means
  372. that the affected buffers will not be written to disk until they have been "unpinned".
  373. XFS uses a write-ahead log protocol for metadata writes, which means XFS writes a log entry
  374. containing the desired after-image before updating the actual on disk metadata. On recovery,
  375. XFS just applies after-images from the log (in case some of the metadata writes were not
  376. completed). In order to avoid having to force the log before updating metadata, XFS "pins"
  377. modified metadata pages in memory. Such pages must count against the memory reservation
  378. (just as do delayed allocation pages). XFS pins a metadata page before updating it, logs
  379. the updates, and then unpins the page when the relevant log entries have been written to
  380. disk. Since the log is usually written lazily, this in effect provides group commit
  381. of metadata updates.
  382. </para>
  383.  
  384. <section>
  385. <title>
  386. The pagebuf Module
  387. </title>
  388.  
  389. <para>
  390. Our approach to porting XFS has included adding pagebuf, a layered buffer cache module on
  391. top of the Linux page cache. This allows XFS to act on extent-sized aggregates. Key to this
  392. approach is the pagebuf structure, which is the major structure of the pagebuf layer. The
  393. pagebuf objects implemented by this module include a list of physical pages associated with
  394. the pagebuf, plus the device information needed to perform I/O.
  395. </para>
  396. <para>
  397. In earlier versions of XFS for Linux we were experimenting with a new device request interface,
  398. so that we can queue one of these pagebuf objects directly to a device, rather than having
  399. to create and queue a large number of single-block buffer_head objects for each logical
  400. I/O request.  These extensions have been superceeded by the Linux 2.5 block layer rewrite
  401. that allows the submission of multi-page bio requests, current XFS versions for Linux 2.4
  402. create and queue buffer_head objects to perform pagebuf I/O.
  403. </para>
  404. <para>
  405. A key goal for the layered buffer cache module is that its objects be strictly temporary,
  406. so that they are discarded when released by the file system, with all persistent data held
  407. purely in the page cache. This avoids creating yet another class of permanent system object,
  408. with separate locking and resource management issues. The IRIX buffer cache implementation
  409. has about 11000 lines of very complex code. By relying purely on the page cache for buffering,
  410. we avoid most of the complexity, particularly in regard to locking and resource management,
  411. of hybrid page and buffer caches, at the cost of having to pay careful attention to efficient
  412. algorithms for assembling large buffers from pages.
  413. </para>
  414. </section>
  415. <section>
  416. <title>
  417. Delayed Allocation of Disk Space for Cached Writes
  418. </title>
  419.  
  420. <para>
  421. Allocating space when appending to a file slows down writes, since reliable metadata updates
  422. (to record extent allocations) result in extra writes. Also, incremental allocations can
  423. produce too-small extents, if new extents are allocated each time a small amount of data is
  424. appended to a file (as when many processes append to a log file). Delayed allocation reserves
  425. disk space for a write but does not allocate any particular space; it simply buffers the write
  426. in the page cache. Later, when pages are flushed to disk, the page writing path must ask the file
  427. system to do the actual allocation. Also, to allow for optimal extent allocations and optimal write
  428. performance, the page writing path must collect adjacent dirty pages ("cluster" them) and write
  429. them as a unit.
  430. </para>
  431. <para>
  432. Since allocation of disk space may be required in the page writing path when delayed allocation
  433. is present, and such allocation may require the use of temporary storage for metadata I/O operations,
  434. some provision must be made to avoid memory deadlocks. The delayed allocation path for writes must
  435. make use of a main memory reservation system, which will limit the aggregate amount of memory used
  436. for dirty pages for which disk space has not been allocated, so that there will always be some
  437. minimum amount of space free to allow allocations to proceed. Any other non-preemptible memory
  438. allocations, such as kernel working storage pages, must be counted against the reservation limit,
  439. so that the remaining memory is genuinely available.
  440. </para>
  441. </section>
  442.  
  443. <section>
  444. <title>
  445. File I/O
  446. </title>
  447. <para>
  448. Early versions of XFS for Linux used an I/O path different from the normal Linux filesystems,
  449. basically a stripped down version of the IRIX XFS I/O code sitting ontop of the pagebuf
  450. layer.   In the XFS/Linux 1.2 release the buffered I/O path has been completly rewritten
  451. to use the generic Linux I/O path as much as possible but still providing XFS-uniqueue features
  452. such as delayed allocated writes and clustered writeout.
  453. </para>
  454. <para>
  455. XFS is now using the generic read/write entry points for pagecache-based filesystems
  456. (generic_file_read/generic_file_write) but wraps them with XFS-specific functionality
  457. such as dealing with DMAPI callbacks and XFS-specific locking.  This means all hard work
  458. for file I/O is done by the address_space operations where XFS against uses the generic
  459. versions for the readpage (read pages into memory), prepare_write and commit_write (copy
  460. file data into the pagecache and mark it for flushing) operations.  The writepage
  461. operations that is responsible for flushing pagecache data to disk is the heart of the
  462. XFS I/O path and completly different from the generic code to handle delayed allocated writes
  463. and clustered writeout.
  464. </para>
  465.  
  466. <para>
  467. A problem in Linux 2.4 is that the buffer layer directly writes out the buffers on
  468. it's LRU list to disk without any filesystem interaction, which makes the delayed disk
  469. block allocation and clustered writeout features of XFS impossible.
  470. </para>
  471. <para>
  472. To address this issue the Linux buffer layer has been modified to call back into the
  473. filesystems writepage method for a buffer marked for delayed allocation instead of directly
  474. writing it out.  These changes are localized to one file (fs/buffer.c) and provide XFS-compatible
  475. semantics with minimal intrusion.
  476. </para>
  477. <para>
  478. Linux 2.5 already performs all pagecache writeout through the filesystems writepage
  479. (or writepages) entry points so no modification was nessecary.
  480. </para>
  481. </section>
  482. <section>
  483. <title>
  484. Direct I/O
  485. </title>
  486.  
  487. <para>
  488. Small files which are frequently referenced are best kept in cache. Huge files, such as image and
  489. streaming media files and scientific data files, are best not cached, since blocks will always be
  490. replaced before being reused. Direct I/O is raw I/O for files: I/O directly to or from user buffers,
  491. with no data copying. The page cache must cooperate with direct I/O, so that any pages, which are
  492. cached and are modified, are read from memory, and so that writes update cached pages.
  493. </para>
  494. <para>
  495. Direct I/O and raw I/O avoid copying, by addressing user pages directly. The application promises
  496. not to change the buffer during a write. The physical pages are locked in place for the duration of
  497. the I/O, via Linux kernel methods (kiobufs in 2.4, get_user_pages in 2.5).
  498. </para>
  499. <para>
  500. Any dirty pages in the page cache must be flushed to disk before issuing direct I/O. The normal
  501. case will find no pages in the cache, and this can be efficiently tested by checking the inode.
  502. Once the pagebuf is assembled, the I/O path is largely common with the normal file I/O path,
  503. except that the write is never delayed and allocation is never delayed.
  504. </para>
  505. <para>
  506. Direct I/O is indicated at open( ) time by using the O_DIRECT flag. Usually the needed space
  507. for the file is pre-allocated using an XFS ioctl call to insure maximum performance.
  508. </para>
  509. <para>
  510. Unlike other Linux filesystems XFS allows multiple O_DIRECT writes to the same inode happen
  511. in parallel.
  512. </para>
  513. </section>
  514. </section>
  515.  
  516. <section>
  517. <title>
  518. Volume Management Layers
  519. </title>
  520.  
  521. <para>
  522. The integration of existing Linux volume managers with the XFS file system has created some
  523. issues for the XFS port to Linux.
  524. </para>
  525. <para>
  526. Traditional Linux file systems have been written to account for the requirements of the block
  527. device interface, ll_rw_block( ). ll_rw_block accepts a list of fixed size I/O requests. For
  528. any given block device on a system, the basic unit of I/O operation is set when the device is
  529. opened. This size is then a fixed length of I/O for that device. The current implementations
  530. of Linux volume managers have keyed off this fixed size I/O and utilize an I/O dispatcher algorithm.
  531. </para>
  532. <para>
  533. By using a fixed I/O length, the amount of "math" that is needed is significantly less than what
  534. it would be if the I/O length were not fixed. All I/O requests from a file system will be of the
  535. same size, as both metadata and user data is of fixed size. Therefore, all underlying devices of
  536. a logical volume must accept I/O requests of the same size. All that the volume manager needs to
  537. do for any I/O request is to determine which device in the logical volume the I/O should go to
  538. and recalculate the start block of the new device. Each I/O request is directed wholly to a new
  539. device.
  540. </para>
  541. <para>
  542. The XFS file system, however, does not assume fixed size I/O. In an XFS file system, metadata
  543. can be anywhere from 512 bytes to over 8 Kbytes. The basic minimum I/O size for user data is
  544. set at file system creation time, with a typical installation using 4 Kbytes. One of the XFS
  545. design goals was to aggregate I/O together, creating large sequential I/O.
  546. </para>
  547. <para>
  548. This feature of XFS created a problem for Linux volume managers, since the XFS file system
  549. can hand an I/O request off to a block device driver specifying the start position and
  550. length, which is not always fixed. A logical volume manager is just another block device
  551. to XFS, and a logical volume manager working in conjunction with XFS needs to be able to
  552. handle whatever size I/O request XFS desires, to some reasonable limit.
  553. </para>
  554. <para>
  555. One of the options to address this problem in XFS is to change the on disk format of the
  556. file system to use a fixed size. This would render the Linux version of XFS incompatible
  557. with the current IRIX implementations, however, and so it was deemed unacceptable, just
  558. as making different versions of NFS would be unacceptable.
  559. </para>
  560. <para>
  561. The Linux 2.4 version of XFS working around the problem of variable I/O request size by
  562. opening a device with the minimum I/O size needed: 512 bytes and performing operations
  563. in multiples of this size anyway unless the underlying device is in a blacklist of
  564. volume manages that can't handle these I/O request.
  565. </para>
  566. <para>
  567. In Linux 2.5 the new block layer interface allows to submit variable-sized requests
  568. and the burden of splitting them up is up to the actual volume managers.
  569. </para>
  570. </section>
  571.  
  572. <section>
  573. <title>
  574. Moving XFS to Open Source
  575. </title>
  576.  
  577. <para>
  578. For XFS to be a viable alternative file system for the open source community, it was deemed essential
  579. that XFS be released with a license at least compatible with the GNU General Public License (GPL).
  580. </para>
  581. <para>
  582. The IRIX operating system in which XFS was originally developed has evolved over a long period of
  583. time, and includes assorted code bases with a variety of associated third party license agreements.
  584. For the most part these agreements are in conflict with the terms and conditions of the GNU General
  585. Public License.
  586. </para>
  587. <para>
  588. The initial XFS project was an SGI initiative that started with a top-to-bottom file system design
  589. rather than an extension of an existing file system. Based upon the assertions of the original
  590. developers and the unique features of XFS, there was a priori a low probability of overlap between
  591. the XFS code and the portions of IRIX to which third-party licenses might apply. However it was
  592. still necessary to establish that the XFS source code to be open sourced was free of all
  593. encumbrances, including any associated with terms and conditions of third party licenses applying
  594. to parts of IRIX.
  595. </para>
  596. <para>
  597. SGI's objectives were:
  598. </para>
  599.  
  600. <itemizedlist>
  601. <listitem><para>
  602. to ensure the absence of any intellectual property infringements
  603. </para></listitem>
  604. <listitem><para>
  605. to establish the likely derivation history to ensure the absence of any code
  606. subject to third party terms and conditions
  607. </para></listitem>
  608. </itemizedlist>
  609.  
  610. <para>
  611. This was a major undertaking; as the initial release of buildable XFS open source
  612. contained some 400 files and 199,000 lines of source. The process was long, but
  613. relatively straightforward, and encumbrance relief was usually by removal of code.
  614.  
  615. The encumbrance review was a combined effort for SGI's Legal and Engineering
  616. organizations. The comments here will be confined to the technical issues and
  617. techniques used by the engineers.
  618. </para>
  619.  
  620. <section>
  621. <title>
  622. The Encumbrance Review Process
  623. </title>
  624.  
  625. <para>
  626. We were faced with making comparisons across several large code bases, and in particular
  627. UNIX System V Release 4.2-MP, BSD4.3 NET/2, BSD4.4-lite and the open source version of
  628. XFS. We performed the following tasks:
  629. </para>
  630.  
  631. <itemizedlist>
  632. <listitem><para>
  633. Historical survey
  634. </para>
  635. <para>
  636. We contacted as many as possible of the original XFS developers and subsequent
  637. significant maintainers, and asked a series of questions. This information was most
  638. useful as guideposts or to corroborate conclusions from the other parts of the review.
  639. </para></listitem>
  640. <listitem><para>
  641. Keyword search (all case insensitive)
  642. </para>
  643. <para>
  644. In each of the non-XFS code bases, we searched for keywords associated with unique XFS
  645. concepts or technologies (e.g. journal, transaction, etc.). In the XFS code base, we
  646. searched for keywords associated with ownership, concepts and technologies in the
  647. non-XFS code bases (e.g. att, berkeley, etc.).
  648. </para></listitem>
  649. <listitem><para>
  650. Literal copy check
  651. </para>
  652. <para>
  653. Using a specially built tool, we compared every line of each XFS source file against
  654. all of the source in the non-XFS code bases. The comparison ignored white space, and
  655. filtered out some commonly occurring strings (e.g. matching "i++;" is never going to be helpful).
  656. </para></listitem>
  657. <listitem><para>
  658. Symbol matching
  659. </para>
  660. <para>
  661. We developed tools to post-process the ASCII format databases from cscope to generate
  662. lists of symbols and their associated generic type (function, global identifier, macro,
  663. struct, union, enum, struct/union/enum member, typedef, etc.). In each XFS source file
  664. the symbols were extracted and compared against all symbols found in all the non-XFS
  665. code bases. A match occurred when the same symbol name and type was found in two
  666. different source files. Some post-processing of the symbols was done to include
  667. plausible name transformations, e.g. adding an "xfs_" prefix, or removal of all underscores, etc.
  668. </para></listitem>
  669. <listitem><para>
  670. Prototype matching
  671. </para>
  672. <para>
  673. Starting with a variant of the mkproto tool, we scanned the source code to extract
  674. ANSI C prototypes. Based on some equivalence classes, "similar" types were mapped to a
  675. smaller number of base types, and then the prototypes compared. A match occurred when the
  676. type of the function and the number and type of the arguments agreed.
  677. </para></listitem>
  678. <listitem><para>
  679. Check for similarity of function, design, concept or implementation.
  680. </para>
  681. <para>
  682. This process is based upon an understanding, and a study, of the source code. In the XFS
  683. code, for each source file, or feature implemented in a source file, or group of source
  684. files implementing a feature, it was necessary to conduct a review of the implementation
  685. of any similar source file or feature in each of the non-XFS code bases. The objective of
  686. this review is to determine if an issue of potential encumbrance arises as a consequence
  687. of similarity in the function, implementation with respect to algorithms, source code
  688. structure, etc.
  689. </para></listitem>
  690. <listitem><para>
  691. Check for evidence of license agreements.
  692. </para>
  693. <para>
  694. We examined the XFS code (especially in comments) to identify any references to relevant
  695. copyrights or license agreements.
  696. </para></listitem>
  697. </itemizedlist>
  698.  
  699. <para>
  700. In all of the steps above, the outcome was a list of possible matches. For each match,
  701. it was necessary to establish in the context of the matches (in one or more files), if
  702. there was a real encumbrance issue.
  703. We used a modified version of the tkdiff tool to graphically highlight the areas of the
  704. "match" without the visual confusion of all of the minutiae of the line-by-line differences.
  705. However, the classification of the matches was ultimately a manual process, based on
  706. the professional and technical skills of the engineers.
  707. </para>
  708.  
  709. </section>
  710. <section>
  711. <title>
  712. Encumbrance Relief
  713. </title>
  714.  
  715. <para>
  716. Especially in view of the size of the XFS source, a very small number of real encumbrance
  717. issues were identified.  In all cases the relief was relatively straightforward, with removal
  718. of code required for IRIX, but not for Linux, being the most common technique.
  719. </para>
  720. </section>
  721. </section>
  722.  
  723. </article>
  724.