<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>http://wiki.old.lustre.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Yep</id>
	<title>Obsolete Lustre Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="http://wiki.old.lustre.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Yep"/>
	<link rel="alternate" type="text/html" href="http://wiki.old.lustre.org/index.php?title=Special:Contributions/Yep"/>
	<updated>2026-04-12T05:52:12Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.39.7</generator>
	<entry>
		<id>http://wiki.old.lustre.org/index.php?title=Clustered_Metadata&amp;diff=3581</id>
		<title>Clustered Metadata</title>
		<link rel="alternate" type="text/html" href="http://wiki.old.lustre.org/index.php?title=Clustered_Metadata&amp;diff=3581"/>
		<updated>2007-06-21T07:36:02Z</updated>

		<summary type="html">&lt;p&gt;Yep: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Clustered Metadata Design (in progress) =&lt;br /&gt;
&lt;br /&gt;
This document describes the design of the clustered metadata handling&lt;br /&gt;
for Lustre.  This material depends on other Lustre design, such as: &lt;br /&gt;
: &lt;br /&gt;
* General recovery&lt;br /&gt;
* Orphan Recovery&lt;br /&gt;
* Metadata Write Back caching&lt;br /&gt;
&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
Overall the clustered metadata handling is structured as follows.  &lt;br /&gt;
&lt;br /&gt;
* A cluster of metadata servers manage a collection of inode groups.   Each inode group is a Lustre device exporting the usual metadata   api, augmented with a few operations specifically crafted for   metadata clustering.  We call these collections of inodes inode   groups.&lt;br /&gt;
* Directory formats for file systems used on the MDS devices are   changed to introduce a allow directory entries to contain an inode   group and identifier of the inode.&lt;br /&gt;
* A logical clustered metadata driver is introduced below the client   Lustre file system write back cache driver that maintains   connections with the MDS servers.&lt;br /&gt;
* There is a single metadata protocol that is used by the client file   system to make updates on the MDS&#039;s and by the MDS&#039;s to make   updates involving other MDS&#039;s.&lt;br /&gt;
* There is a single recovery protocol that is used by the clients -   MDS and MDS-MDS service.&lt;br /&gt;
* Directories can be split across multiple MDS nodes.  In that case a   primary MDS directory inode contains an extended attribute that   points at other MDS inodes which we call directory objects.&lt;br /&gt;
&lt;br /&gt;
= Configuration management and Startup =&lt;br /&gt;
&lt;br /&gt;
The configuration will name an MDS server, and optionally a failover&lt;br /&gt;
node, which hold the root inode for a fileset.  Clients will contact&lt;br /&gt;
that MDS for the root inode during mount, as they do already.   &lt;br /&gt;
&lt;br /&gt;
They will also fetch from it a clustering descriptor.  The clustering&lt;br /&gt;
descriptor contains a header and an array lists what inode groups are&lt;br /&gt;
served by what server.&lt;br /&gt;
&lt;br /&gt;
Through normal mechanisms clients will wait and probe for available&lt;br /&gt;
metadata servers, during startup and cluster transitions.  When new&lt;br /&gt;
servers are found or configurations have changed they can update their&lt;br /&gt;
clustering descriptor as they update the LOV striping descriptor for&lt;br /&gt;
OST&#039;s.&lt;br /&gt;
&lt;br /&gt;
= Data Structures =&lt;br /&gt;
&lt;br /&gt;
The fid will contain a new 32 bit integer to name the inode group.  &lt;br /&gt;
&lt;br /&gt;
Directory entries will contain a new 32 bit integer to name the inode&lt;br /&gt;
group. &lt;br /&gt;
&lt;br /&gt;
Directory inodes on the MDS, when large, contain a new EA which is a&lt;br /&gt;
descriptor of how the directory is split over directory objects,&lt;br /&gt;
residing on other MDS&#039;s.  This EA is subject to ordinary concurrency&lt;br /&gt;
control by the MDS holding the inode.  The EA is virtually identical&lt;br /&gt;
to the LOV EA. &lt;br /&gt;
&lt;br /&gt;
= The clustered metadata client (CMC) =&lt;br /&gt;
&lt;br /&gt;
Client systems will have the write back client (WBD) or client file&lt;br /&gt;
system directly communicate with the CMC driver: it offers the&lt;br /&gt;
metadata api to the file system and uses the metadata api offered by a&lt;br /&gt;
collection of MDC drivers.  Each MDC driver managed the metadata&lt;br /&gt;
traffic to one. &lt;br /&gt;
&lt;br /&gt;
The function of the CMC is very simple: it figures out from the&lt;br /&gt;
command issued what MDC to use.  This is based on: &lt;br /&gt;
* the inode groups in the request&lt;br /&gt;
* a hash value of names used in the request, combined with the EA of   a primary inode involved in the request.&lt;br /&gt;
* for readdir the directory offset combined with the EA of the   primary inode&lt;br /&gt;
* the clustering descriptor&lt;br /&gt;
&lt;br /&gt;
In any case every command is dispatched to a single metadata server,&lt;br /&gt;
the clients will not engage more than one metadata server for a single&lt;br /&gt;
request.  &lt;br /&gt;
&lt;br /&gt;
The api changes here are minimal and the client part of the&lt;br /&gt;
implementation is very trivial.&lt;br /&gt;
&lt;br /&gt;
= MDS implementation =&lt;br /&gt;
&lt;br /&gt;
For the most part, operations are extremely similar or identical to&lt;br /&gt;
what they were before.   In some cases multiple mds servers are&lt;br /&gt;
involved in updates.&lt;br /&gt;
&lt;br /&gt;
Getattr, open, readdir, setattr and lookup methods are unaffected. &lt;br /&gt;
&lt;br /&gt;
Methods adding entries to directories are modified in some cases: &lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;mkdir&#039;&#039;&#039; always create the new directory on another MDS&lt;br /&gt;
* &#039;&#039;&#039;unlink, rmdir, rename&#039;&#039;&#039;: may involve more than one MDS&lt;br /&gt;
* &#039;&#039;&#039;large directories&#039;&#039;&#039; all operations making updates to    directories can cause a directory split. The directory split is   discussed below.&lt;br /&gt;
* &#039;&#039;&#039;other operations&#039;&#039;&#039; If no splits large directories are   encountered  all other operations proceed as they are executed on   one MDS.&lt;br /&gt;
&lt;br /&gt;
== Directory Split ==&lt;br /&gt;
&lt;br /&gt;
A directory that is growing larger will be split.  There is a fairly heavy penalty associated with splitting the directory and also with renames in within split directories.  Moreover, at the point of splitting, inodes become remote and will incur a penalty upon unlink.&lt;br /&gt;
&lt;br /&gt;
Probably it is best to delay the split until the directory is fairly large, and then to split over several nodes, to avoid further splits being necessary soon afterwards.&lt;br /&gt;
&lt;br /&gt;
= Recovery =&lt;br /&gt;
&lt;br /&gt;
== Transaction Replay ==&lt;br /&gt;
&lt;br /&gt;
The MDS - MDS interaction is managed as follows.  The node approached&lt;br /&gt;
with a request change is made the coordinator of the transaction.&lt;br /&gt;
&lt;br /&gt;
=== Mechanisms ===&lt;br /&gt;
&lt;br /&gt;
The coordinator will first establish that the transaction can commit on all nodes, by acquiring locks on directories and checking for available space existing entries with the same name etc.  It may also first perform a directory split if the size is becoming too large, and more MDS nodes are still available.  &lt;br /&gt;
&lt;br /&gt;
All nodes involved in the transaction need to have a transaction sequence number to place the transaction into their sequence and allow correctly replay. &lt;br /&gt;
&lt;br /&gt;
At this point the coordinator will:&lt;br /&gt;
* start a transaction locally. &lt;br /&gt;
* It will then report the transaction sequence number to all other nodes involved in the transaction.  &lt;br /&gt;
* These nodes will commit (in memory as usual), write a journal record for replay and reply to the coordinator.  &lt;br /&gt;
* The coordinator will then commit its own transaction.&lt;br /&gt;
* The replay log records are subject to normal log commit cancelation messages, but on the coordinator commit messages must be received from all other nodes before the record will be canceled.&lt;br /&gt;
&lt;br /&gt;
In this way if the results of the transaction survive on any of the nodes, they can be replayed on all.&lt;br /&gt;
&lt;br /&gt;
=== Cluster crashes and the transaction sequence ===&lt;br /&gt;
&lt;br /&gt;
If the cluster crashes abruptly, there is the opportunity for transactions to be in progress affecting multiple nodes.  Dependencies between the transactions must be managed to ensure serializibility of the protocol. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Example: In transaction one, a node X creates directories a.  Then in transaction 2 a cross MDS node rename moves a file with a directory entry on node Y into this directory.  It is now possible for this file to lose its directory entry on Y and for the transaction on X not to commit. More complex examples exist.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We see 4 solutions:&lt;br /&gt;
&lt;br /&gt;
* Disk commit delay locks: dependent transactions many not commit before the parent transaction commits.&lt;br /&gt;
* Commit acks: transactions may not proceed until previous pre-requisite transactions have committed.&lt;br /&gt;
* Synchronous NVRAM journal on all MDS nodes&lt;br /&gt;
* Shared journal among all MDS nodes &lt;br /&gt;
&lt;br /&gt;
The first and last method offer the most opportunity to proceed without synchronous disk writes. The last method involves  contention on a shared resource.&lt;br /&gt;
&lt;br /&gt;
Although exhaustive analysis remains, it is clear that rename and splitting the directories are the primary culprits. Hence, we wonder about the following policy related issues:&lt;br /&gt;
* Only split really large directories, say after 1M entries.&lt;br /&gt;
* Do not needlessly create subdirectories on other nodes.  A much better policy is likely to keep directories with one owner, or possibly one client system generating them together.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Replay ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To order transaction sequences Lustre uses reply ack&#039;s: the acks&lt;br /&gt;
server only one purpose to release a lock that enforces ordering of&lt;br /&gt;
the transaction sequence.  In the case where MDS operations involve&lt;br /&gt;
more than server, the reply &amp;quot;ack&amp;quot; from the primary to secondary&lt;br /&gt;
servers should only be sent after the client has sent the ack to the&lt;br /&gt;
first server.  This MDS-MDS reply ack is now not really an ack anymore&lt;br /&gt;
but a simple lock cancelation review.&lt;br /&gt;
&lt;br /&gt;
Clients will replay lost transactions to the mds which they originally&lt;br /&gt;
engaged for the request.  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Orphaned children will be cleaned up only&lt;br /&gt;
after replay completes to allow orphaned objects to be re-used during&lt;br /&gt;
replay.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Failover ==&lt;br /&gt;
&lt;br /&gt;
The configuration data can designate a standby MDS that will take over&lt;br /&gt;
from a failed MDS.  By organizing the servers in one or more rings,&lt;br /&gt;
the nearest working left neighbor MDS can be the failover node.  This&lt;br /&gt;
leads to a simple scheme with multiple failover nodes, avoiding quorum&lt;br /&gt;
and other complications beyond what is needed for two node clusters.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Locking =&lt;br /&gt;
&lt;br /&gt;
We believe locking can be done in fid order as it is currently done on the MDS.&lt;/div&gt;</summary>
		<author><name>Yep</name></author>
	</entry>
	<entry>
		<id>http://wiki.old.lustre.org/index.php?title=Logging_API&amp;diff=3565</id>
		<title>Logging API</title>
		<link rel="alternate" type="text/html" href="http://wiki.old.lustre.org/index.php?title=Logging_API&amp;diff=3565"/>
		<updated>2007-06-21T06:19:32Z</updated>

		<summary type="html">&lt;p&gt;Yep: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Lustre Logging API =&lt;br /&gt;
&lt;br /&gt;
In numerous places Lustre needs a logging API.  Generally log records are written transactionally and canceled when a commit on another system completes.  There are many uses for this, all associated with updates of persistent information on multiple systems.&lt;br /&gt;
&lt;br /&gt;
Log records are stored in log objects. Log objects are currently implemented as files, and possibly, in some minor ways, the api below reflects this.  We speak of log objects and sometimes of llog&#039;s (lustre-logs).&lt;br /&gt;
&lt;br /&gt;
= API Requirements =&lt;br /&gt;
&lt;br /&gt;
* The api should be usable through methods.  &lt;br /&gt;
* The methods should mask wether the api is used remotely or locally.&lt;br /&gt;
* Logs only grow&lt;br /&gt;
* Logs can be removed, and remote callers may not assume open logs remain available&lt;br /&gt;
&lt;br /&gt;
* Access to logs should be mostly through a stateless api that can be called remotely&lt;br /&gt;
* Access to logs should go through some kind of authentication/authorization system&lt;br /&gt;
: &lt;br /&gt;
&lt;br /&gt;
= Fundamental Data Structures =&lt;br /&gt;
&lt;br /&gt;
#  Log objects can be identified in two ways:&lt;br /&gt;
* Through a name: &lt;br /&gt;
* the interpretation of the name is up to the driver servicing the call.&lt;br /&gt;
* typical examples of named logs are files identified by a pathname&lt;br /&gt;
* text versions of UUID&#039;s&lt;br /&gt;
* profile names&lt;br /&gt;
* Through an object id, the llog_logid.&lt;br /&gt;
: A directory of llogs which can look up a name to get an id can provide translation from a naming system to an id based access system.  In our implementation we use a file system directory to provide this catalog function.&lt;br /&gt;
#  Logs only contain records&lt;br /&gt;
#  Records in logs have the following structure:&lt;br /&gt;
* llog_rec_hdr: a header, indicating the index, length and type; the header is 16 bytes in length&lt;br /&gt;
* body which is opaque 32 bit aligned blob ; the body is 32 byte aligned&lt;br /&gt;
* llog_rec_tail: length and index of the record again, for walking backward ; the tail is 16 byes length.&lt;br /&gt;
#  The first record in every log is a 4K llog_log_rec&lt;br /&gt;
* The body of this record contains:&lt;br /&gt;
* a bitmap of records that are allocated; bit 0 is set immediately because the header itself occupies it&lt;br /&gt;
* A collection of log records behind the header&lt;br /&gt;
#  Records can be accessed:&lt;br /&gt;
* by iterating through a specific log&lt;br /&gt;
* by providing a llog_cookie&lt;br /&gt;
: 4. Some logs are potentially very large, for example, replication logs, and require a hierarchical structure, where a catalog of logs is held at the top level.  In some cases the catalog structure is two deep.&lt;br /&gt;
* A catalog api is provided which exploits the lower lustre log api &lt;br /&gt;
* Catalog entries &lt;br /&gt;
&lt;br /&gt;
= Cancellation API =&lt;br /&gt;
&lt;br /&gt;
This describes typical use of the logging api to manage distributed commit of related distributed persistent updates.&lt;br /&gt;
&lt;br /&gt;
We consider systems that make related updates&lt;br /&gt;
&lt;br /&gt;
: originator:: the first system performing a transaction&lt;br /&gt;
: replicators:: one or more other systems performing a related update&lt;br /&gt;
&lt;br /&gt;
The key requirement is that the replicators must complete their updates.  This is accomplished by transactionally recording the originators action in a log. When the replicators related action completes, it cancels the log entry on the originator.  Here we describe the handshakes and protocols involved.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Normal Operation ==&lt;br /&gt;
&lt;br /&gt;
* Originator performs a transaction and as part of the transaction writes a log record for each replicator.&lt;br /&gt;
* The log record creation produces a &#039;&#039;log_cookie&#039;&#039;.&lt;br /&gt;
* The log_cookie is sent to the replicator.&lt;br /&gt;
* The replicator performs the related transaction and executes a commit callback for that.&lt;br /&gt;
* The call back to put the log_cookie up for cancellation&lt;br /&gt;
* When the replicator has a page full of cancellation cookies it sends the cookies to the originator&lt;br /&gt;
* The originator cancels the log records associated with the cookies and cleans up empty log files&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Notes&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
#  These replication scenarios are closely related to commit callbacks and rpc&#039;s Key differences are&lt;br /&gt;
* The commit callbacks with transaction numbers involve a volatile client and persistent server&lt;br /&gt;
* The transaction sequence is determined by the server in the volatile-persistent case by the originator in the replicating case&lt;br /&gt;
&lt;br /&gt;
: === Examples ===&lt;br /&gt;
: &lt;br /&gt;
: ==== deletion of files ====&lt;br /&gt;
&lt;br /&gt;
* change needs to be replicated from mds to ost&#039;s&lt;br /&gt;
* osc&#039;s on mds act as originator for the change log, using storage from the mds&lt;br /&gt;
* osc&#039;s write log records&lt;br /&gt;
* osc&#039;s generate cancel cookies&lt;br /&gt;
* osc&#039;s send cookies to ost&#039;s &lt;br /&gt;
* ost&#039;s act as replicators&lt;br /&gt;
* remove objects&lt;br /&gt;
* pass osc generated cookies as parameters to obd_destroy transactions&lt;br /&gt;
* collect cookies in pages for bulk cancellation rpcs to the osc on mds&lt;br /&gt;
* cancel records on the osc&#039;s on mds&lt;br /&gt;
&lt;br /&gt;
: ==== file size changes ====&lt;br /&gt;
&lt;br /&gt;
* changes orginate on OST&#039;s need to be implemented on the MDS&lt;br /&gt;
* Upon the first file size change in an io epoch on OST:&lt;br /&gt;
* writes a new size change record for new epoch&lt;br /&gt;
* records the size of the previous epoch in the record&lt;br /&gt;
* records the object id of the previous epoch in the record&lt;br /&gt;
* it generates a cancellation cookie&lt;br /&gt;
* when MDS knows epoch has ended&lt;br /&gt;
* it obtains the size at completion of epoch from client (or exceptionally from the OST)&lt;br /&gt;
* it obtains cancellation cookies for each OST from the client or from the OST&#039;s&lt;br /&gt;
* it postpones starting a new epoch until the size is known &lt;br /&gt;
* it starts a setattr transaction to store the size&lt;br /&gt;
* when it commits, it cancels the records on the OST&#039;s&lt;br /&gt;
&lt;br /&gt;
* RAID1 OST&lt;br /&gt;
* The primary is the originator, the secondary the replica&lt;br /&gt;
* Writes on the primary are accompanied by a change record for an extent&lt;br /&gt;
* &lt;br /&gt;
&lt;br /&gt;
== Connections ==&lt;br /&gt;
&lt;br /&gt;
In order to process cancellation and recovery actions the originators and replicators use a ptlrpc connection to execute remote procedure calls.  The connection can be set up on the originator or the replicator and we call the system setting up the connection the initiator.&lt;br /&gt;
&lt;br /&gt;
* The originator and the replicator establish a connection.  &lt;br /&gt;
* The logging subsystem on each end of the connection receives a log connection active completion event&lt;br /&gt;
* if connections are active log_cookies can be accepted for cancellation by the cancellation daemons&lt;br /&gt;
* if connections are not active the log_cookies are not collected for cancellation&lt;br /&gt;
* A generation number is associated with the connections&lt;br /&gt;
* it increases for each connection complete event&lt;br /&gt;
: &lt;br /&gt;
== Cancellation timeout ==&lt;br /&gt;
&lt;br /&gt;
* If the replicator times out during cancellation&lt;br /&gt;
* It will continue to process the transactions with cookies&lt;br /&gt;
* The cancellation daemon will drop the cookies&lt;br /&gt;
&lt;br /&gt;
== Initiator Connect Event ==&lt;br /&gt;
&lt;br /&gt;
When the replicator receives a connect complete event it &lt;br /&gt;
: &lt;br /&gt;
* Fetches the catalogs log_id for the catalog it needs to process through a get_cat_info call&lt;br /&gt;
* The replicator needs to know what the catalog logid is for processing&lt;br /&gt;
* When it has received the catalog it calls process catalog:&lt;br /&gt;
* The replicator calls sync &lt;br /&gt;
* It only processes records in logs from previous log connection generations&lt;br /&gt;
* The catalog processing repeats operations that should have been performed by the initiator earlier&lt;br /&gt;
* The replicator must be able to distinguish: &lt;br /&gt;
* the operation already took place&lt;br /&gt;
* the operation was not performed&lt;br /&gt;
* If the operations are performed:&lt;br /&gt;
* During this processing the replicator generates cookies as it normally does&lt;br /&gt;
* Upon commit cookies are queued on the replicator for bulk cancellation of log records&lt;br /&gt;
* If the update was already performed:&lt;br /&gt;
* the replicator can queue a cancellation cookie back immediately &lt;br /&gt;
&lt;br /&gt;
== Log Removal Failure ==&lt;br /&gt;
: &lt;br /&gt;
* If an initiator crashes during log removal, the log entries may re-appear after recovery&lt;br /&gt;
* It is important that the removal of a log from a catalog and the removal of the log file are atomic&lt;br /&gt;
* Upon reconnection the replicator will again process the log  &lt;br /&gt;
&lt;br /&gt;
= Log API&#039;s =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Low Level Log Operations ==&lt;br /&gt;
&lt;br /&gt;
Logs can be opened and/or created. This fills in a log handle. The log handle can be used through the log handle api.  &lt;br /&gt;
&lt;br /&gt;
: &amp;lt;pre&amp;gt;&lt;br /&gt;
: int llog_create(struct obd_device *obd, struct llog_handle **, struct llog_logid *, char *name);&lt;br /&gt;
: &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
: If llog_id is not null open an existing log with this ID.  If name is not null, open or create a log with that name. Otherwise open a nameless log.  The object id of the log is stored in the handle upon success of opening or creation.&lt;br /&gt;
&lt;br /&gt;
: &amp;lt;pre&amp;gt;&lt;br /&gt;
: int llog_close(struct llog_handle *loghandle);&lt;br /&gt;
: &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
: Close the log and free the handle. Remove the handle from the catalogs list of open handles.  If the log has a flag set of destroy if empty the log may be zapped.&lt;br /&gt;
&lt;br /&gt;
: &amp;lt;pre&amp;gt;   &lt;br /&gt;
: int llog_destroy(struct llog_handle *);&lt;br /&gt;
: &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
: Destroy the log object and close the handle.&lt;br /&gt;
&lt;br /&gt;
: &amp;lt;pre&amp;gt;&lt;br /&gt;
: int llog_write_rec(struct llog_handle *handle, struct llog_rec_hdr *rec, struct llog_cookie *cookie, int cookie_count, void *buf);&lt;br /&gt;
: &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
: Write a record in the log.  If buf is null the record is complete, if buf is not null it inserted in the middle.  Records are multiples of 128 bits in size and have a hdr and tail. Write the cookie for the entry into the cookie pointer. (cookie_count is probably a mistake).&lt;br /&gt;
&lt;br /&gt;
: &amp;lt;pre&amp;gt;&lt;br /&gt;
: int llog_next_block(struct llog_handle *h, int curr_idx, int next_idx, __u64 *offset, void *buf, int len);&lt;br /&gt;
: &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
: Index curr_idx is in the block at offset *offset.  Set *offset to the block offset of record next_idx.  Copy len bytes from the start of that block into the buffer buf.&lt;br /&gt;
&lt;br /&gt;
: &amp;lt;pre&amp;gt;&lt;br /&gt;
: int (*lop_read_header)(struct llog_handle *handle);&lt;br /&gt;
: &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
: Read the header of the log into the handle and also read the last rec_tail in the log to find the last index that was used in the log.&lt;br /&gt;
&lt;br /&gt;
== Higher Level Log Operations ==&lt;br /&gt;
&lt;br /&gt;
: &amp;lt;pre&amp;gt;&lt;br /&gt;
: int llog_init_handle(struct llog_handle *handle, int flags, struct obd_uuid *uuid);&lt;br /&gt;
: &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
: Initialize the handle.  Try to read it from the log file, but if the log has no header yet, build it from the arguments.  If the header is read, verify the flags and UUID in the log equal those of the arguments.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== OBD Level Log Operations ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
: int llog_add_record(struct llog_handle *cathandle, struct llog_trans_hdr *rec,&lt;br /&gt;
: struct llog_cookie *logcookies, void *buf)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
: int llog_delete_log(struct llog_handle *cathandle,struct llog_handle *loghandle)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
: int llog_cancel_records(struct llog_handle *cathandle, int count, struct llog_cookie *cookies)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* For each cookie in the cookie array, we clear the log in-use bit and either:&lt;br /&gt;
* the log is empty, so mark it free in the catalog header and delete it&lt;br /&gt;
* the log is not empty, just write out the log header&lt;br /&gt;
* The cookies may be in different log files, so we need to get new logs each time.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
: int llog_next_block(struct llog_handle *loghandle, int cur_idx, int next_idx,&lt;br /&gt;
: __u64 *cur_offset, void *buf, int len)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Return the block in the log that contains record with index next_idx. The current idx at offset cur_offset is used to optimize the search. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
: typedef int (*llog_cb_t)(struct llog_handle *, struct llog_trans_hdr *rec, void *data);&lt;br /&gt;
: int llog_process_log(struct llog_handle *loghandle, llog_cb_t cb, void *data)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Call the callback function cb&lt;/div&gt;</summary>
		<author><name>Yep</name></author>
	</entry>
	<entry>
		<id>http://wiki.old.lustre.org/index.php?title=Fsck_Support&amp;diff=3401</id>
		<title>Fsck Support</title>
		<link rel="alternate" type="text/html" href="http://wiki.old.lustre.org/index.php?title=Fsck_Support&amp;diff=3401"/>
		<updated>2007-06-19T07:34:11Z</updated>

		<summary type="html">&lt;p&gt;Yep: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Where to get e2fsck support for Lustre ==&lt;br /&gt;
&lt;br /&gt;
In order to support some of the more advanced features of Lustre (e.g. extents and large inode/EA support) you need a patched e2fsprogs.  This can be downloaded (RPM, SRPM) from the lfsck directory of the customer download site.  See  http://clusterfs.com/download.html&lt;br /&gt;
&lt;br /&gt;
=== Code for e2fsprogs-lustre ===&lt;br /&gt;
We maintain a quilt patchset of all the CFS changes to the upstream e2fsprogs.  The patches are available in the .src.rpm in the &#039;&#039;e2fsprogs/patches&#039;&#039; directory.&lt;br /&gt;
&lt;br /&gt;
== Using e2fsck and lfsck ==&lt;br /&gt;
In a node crash case it is not neccesary to run e2fsck on the filesystem - the ext3 journaling will ensure that the filesystem remains coherent.  The only time we really required that e2fsck is run on a device is when there is some sort of event that may cause problems outside of what ext3 journaling can handle, such as hardware device failure, IO errors, etc.  If the ext3 kernel code detects corruption on the disk it will mount the filesystem read-only to prevent further corruption but still allow read access to the device.&lt;br /&gt;
&lt;br /&gt;
In such a situation, it is normally only &#039;&#039;required&#039;&#039; that e2fsck be run on the bad device before placing it back into service.  In the vast majority of cases Lustre will be able to cope with inconsistencies it finds on the disk and between other devices in the filesystem.  For good problem analysis it is always strongly recommended that e2fsck is run under a logger like &#039;&#039;&#039;script&#039;&#039;&#039; to record all of the output and changes that are made to the filesystem in case this information is needed later.  If time permits, it is also a good idea to first run e2fsck in non-fixing mode (-n option) to first assess the type/extent of damage to the filesystem.  The drawback is that in this mode e2fsck doesn&#039;t recover the filesystem journal, so there may appear to be filesystem corruption when none really exists.  Briefly mounting and unmounting the ext3 filesystem (directly on the node like &amp;quot;mount -t ldiskfs /dev/{ostdev} /mnt/ost; umount /mnt/ost&amp;quot;, with Lustre stopped, &#039;&#039;&#039;NOT&#039;&#039;&#039; via Lustre) will cause the journal to be recovered if there is concern/confusion about whether corruption is real or only due to the journal not being replayed.&lt;br /&gt;
&lt;br /&gt;
While e2fsck is very good at fixing filesystem corruption (better than any other similar filesystem recovery tool, and a primary reason why ext3 was chosen over other filesystems for Lustre), it is often useful to know what type of damage there is, and an ext3 expert may be able to make more intelligent decisions about what needs fixing compared to e2fsck.  CFS support is available for such situations.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
root# {stop lustre services for this device, if running}&lt;br /&gt;
root# script /tmp/e2fsck.sda&lt;br /&gt;
Script started, file is /tmp/e2fsck.sda&lt;br /&gt;
root# mount -t ldiskfs /dev/sda /mnt/ost&lt;br /&gt;
root# umount /mnt/ost&lt;br /&gt;
root# e2fsck -fn /dev/sda   # don&#039;t fix filesystem, just check for corruption&lt;br /&gt;
root# e2fsck -fp /dev/sda   # fix filesystem using &amp;quot;prudent&amp;quot; answers (usually &#039;y&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In addition, the e2fsprogs package contains an &#039;&#039;&#039;lfsck&#039;&#039;&#039; tool which does distributed coherency checking for the Lustre filesystem, after e2fsck has been run.  This is not required in a large majority of cases, at the small chance of having some leaked space in the filesystem.  It can also be run once Lustre is already started (with care) to avoid a lengthy downtime.&lt;br /&gt;
&lt;br /&gt;
=== How to run e2fsck+lfsck on a corrupted Lustre filesystem ===&lt;br /&gt;
&lt;br /&gt;
In cases where the MDS or an OST become corrupted for some reason, it is possible to run a distributed check on the filesystem to determine what sort of problems exist.&lt;br /&gt;
&lt;br /&gt;
The first step is to run &#039;e2fsck -f&#039; on the individual MDS/OST &#039;&#039;&#039;with Lustre stopped&#039;&#039;&#039; that had problems in order to fix any local filesystem damage.  It is a very good idea to run this e2fsck under &amp;quot;script&amp;quot; as shown above so that you have a log of whatever changes it made to the filesystem in case this is needed later.  After this is complete it is then possible to bring the filesystem up if necessary to reduce the outage window.&lt;br /&gt;
&lt;br /&gt;
Next, a full e2fsck of the MDS is necessary in order to create a databse for lfsck.  The use of the &#039;-n&#039; option is critical for a mounted filesystem (i.e. if Lustre is running), otherwise you will corrupt your filesystem.  The mdsdb file can grow fairly large, depending on the number of files in the filesystem (10GB or more for millions of files, though the actual file size is larger because the file is sparse).  It is fastest if this is written to a local filesystem because of the seeking and small writes.  Depending on the number of files, this step can take several hours.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
e2fsck -n -v --mdsdb /tmp/mdsdb /dev/{mdsdev}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next this file must be made accessible on all of the OSTs (either via a shared filesystem, or by copying it to the OSTs - pdcp is very useful here), and the OSTs need to run a similar e2fsck step.  There is a stub mdsdb file generated called {mdsdb}.mdshdr that can be used instead of the full mdsdb file, if the OSTs do not have shared filesystem access to the MDS filesystem.  The mdsdb is only used for reading so it does not need to be in shared storage for all of the OSTs.  The OST e2fsck --ostdb step can be run in parallel on all of the OSTs.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
e2fsck -n -v --mdsdb /tmp/mdsdb --ostdb /tmp/{ostNdb} /dev/{ostNdev}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, the mdsdb and all of the ostdb files need to be made available on a mounted client so that lfsck can be run to examine the filesystem and optionally correct defects it finds.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
lfsck -n -v --mdsdb /tmp/mdsdb --ostdb /tmp/{ost1db} /tmp/{ost2db} ... /lustre/mount/point&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By default lfsck does not repair any inconsistencies it finds, only reporting the errors.  It checks for 3 kinds of inconsistencies:&lt;br /&gt;
&lt;br /&gt;
#  Inode exists but has missing objects = dangling inode.  This normally happens if there was a problem with an OST.&lt;br /&gt;
#  Inode is missing but OST has unreferenced objects = orphan object.  This normally happens if there was a problem with the MDS.&lt;br /&gt;
#  Multiple inodes reference the same objects. This can happen if there was corruption on the MDS, or if the MDS storage is cached and loses some but not all writes.&lt;br /&gt;
&lt;br /&gt;
If the filesystem is in use and being modified while the --mdsdb and --ostdb steps are running, lfsck may report inconsistencies where none exist because of files and objects being created/removed after the database files were collected, so the results should be examined closely and you may want to re-run the test and/or contact CFS support for guidance.&lt;br /&gt;
&lt;br /&gt;
The easiest problem to resolve is that of orphaned objects.  Using the &#039;-l&#039; option to lfsck it can link these objects to new files and put them into lost+found in the Lustre filesystem, where they can be examined and saved or deleted as necessary.  If you are certain the objects are not useful, lfsck can run with the &#039;-d&#039; option to delete orphaned objects and free up any space they are using.&lt;br /&gt;
&lt;br /&gt;
To fix dangling inodes, lfsck will create new zero-length objects are created on the OSTs if the &#039;-c&#039; option is given.  These files will read back with binary zeros for the stripes that had objects recreated.  Such files can also be read even without lfsck repair by using &#039;&#039;&#039;dd if=/lustre/bad/file of=/new/file bs=4k conv=sync,noerror&#039;&#039;&#039;.  Because this is rarely useful to have files with large holes in them, most users delete these files after reading them (if useful) and/or restoring them from backup.  Note that it is not possible to write to the holes of such a file without having lfsck recreate the objects, so it is generally easier to delete these files and restore them from backup.&lt;br /&gt;
&lt;br /&gt;
To fix inodes with duplicate objects, lfsck will copy the duplicate object to a new object and assign that to one of the files if the &#039;-c&#039; option is given.  One of the files will be OK, and one will likely contain garbage, but lfsck cannot tell by itself which one is correct.&lt;/div&gt;</summary>
		<author><name>Yep</name></author>
	</entry>
	<entry>
		<id>http://wiki.old.lustre.org/index.php?title=File:Software_breakdown.jpg&amp;diff=3122</id>
		<title>File:Software breakdown.jpg</title>
		<link rel="alternate" type="text/html" href="http://wiki.old.lustre.org/index.php?title=File:Software_breakdown.jpg&amp;diff=3122"/>
		<updated>2007-06-11T08:36:34Z</updated>

		<summary type="html">&lt;p&gt;Yep: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Yep</name></author>
	</entry>
	<entry>
		<id>http://wiki.old.lustre.org/index.php?title=Coding_Guidelines&amp;diff=3110</id>
		<title>Coding Guidelines</title>
		<link rel="alternate" type="text/html" href="http://wiki.old.lustre.org/index.php?title=Coding_Guidelines&amp;diff=3110"/>
		<updated>2007-06-11T07:46:02Z</updated>

		<summary type="html">&lt;p&gt;Yep: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;All Lustre developers should follow the guidelines in this page very strictly to avoid problems during code merges later on. Please make the required changes to the default formatting rules in the editor you use to comply to the guidelines below.&lt;br /&gt;
&lt;br /&gt;
== Guidelines ==&lt;br /&gt;
&lt;br /&gt;
1. There should be no tabs in any files.&lt;br /&gt;
&lt;br /&gt;
2. Blocks should be indented by 8 spaces.&lt;br /&gt;
&lt;br /&gt;
3. New files should contain the following along with the license boilerplate.  This will cause vim and emacs to use spaces instead of tabs for indenting.  If you use a different editor, it also needs to be set to use spaces for indening Lustre code.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;background:lightgrey;&amp;quot;&amp;gt;&lt;br /&gt;
  /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-&lt;br /&gt;
   * vim:expandtab:shiftwidth=8:tabstop=8:&lt;br /&gt;
   */&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
4. All lines should wrap at 80 characters. If it&#039;s getting too hard to wrap there, you probably need to break it up into more functions.  In some cases, it is acceptable to remove a few spaces between function arguments to avoid overflowing onto the next line.&lt;br /&gt;
&lt;br /&gt;
5. Don&#039;t have spaces or tabs on blank lines or at the end of lines.&lt;br /&gt;
&lt;br /&gt;
6. Don&#039;t use &amp;quot;inline&amp;quot; unless you&#039;re doing something so performance critical that the function call overhead will make a difference -- in other words: never.  It makes debugging harder.&lt;br /&gt;
&lt;br /&gt;
All of our wrapping, parenthesis, brace placement, etc. rules are basically Linux kernel rules, which are basically K&amp;amp;R. For those of you in need of a refresher, great detail is provided below.&lt;br /&gt;
&lt;br /&gt;
== Great detail ==&lt;br /&gt;
&lt;br /&gt;
a. When you wrap, the next line should start after the parenthesis:&lt;br /&gt;
&amp;lt;pre style=&amp;quot;background:lightgrey;&amp;quot;&amp;gt;&lt;br /&gt;
  right:&lt;br /&gt;
 &lt;br /&gt;
  variable = do_something_complicated(long_argument, longer_argument,&lt;br /&gt;
                                      longest_argument(sub_argument,&lt;br /&gt;
                                                       foo_argument),&lt;br /&gt;
                                      last_argument);&lt;br /&gt;
 &lt;br /&gt;
  if (some_long_condition(arg1, arg2, arg3) &amp;lt; some_long_value &amp;amp;&amp;amp;&lt;br /&gt;
      another_long_condition(very_long_argument_name,&lt;br /&gt;
                             another_long_argument_name) &amp;gt;&lt;br /&gt;
      second_long_value) {&lt;br /&gt;
  }&lt;br /&gt;
                             &lt;br /&gt;
 &lt;br /&gt;
  wrong:&lt;br /&gt;
 &lt;br /&gt;
  variable = do_something_complicated(long_argument, longer_argument,&lt;br /&gt;
                    longest_argument(sub_argument, foo_argument),&lt;br /&gt;
                    last_argument);&lt;br /&gt;
 &lt;br /&gt;
  if (some_long_condition(arg1, arg2, arg3) &amp;lt; some_long_value &amp;amp;&amp;amp;&lt;br /&gt;
              another_long_condition(very_long_argument_name,&lt;br /&gt;
                    another_long_argument_name) &amp;gt;&lt;br /&gt;
                    second_long_value) {&lt;br /&gt;
  }&lt;br /&gt;
 &amp;lt;/pre&amp;gt;&lt;br /&gt;
b. If you&#039;re wrapping put the operators at the end of the line, and if there are no parentheses indent 8 more:&lt;br /&gt;
 &amp;lt;pre style=&amp;quot;background:lightgrey;&amp;quot;&amp;gt;&lt;br /&gt;
  off = le32_to_cpu(fsd-&amp;gt;fsd_client_start) +&lt;br /&gt;
          cl_idx * le16_to_cpu(fsd-&amp;gt;fsd_client_size);&lt;br /&gt;
 &amp;lt;/pre&amp;gt;&lt;br /&gt;
c. Binary and ternary (but not unary) operators should be separated from their arguments by one space.&lt;br /&gt;
 &amp;lt;pre style=&amp;quot;background:lightgrey;&amp;quot;&amp;gt;&lt;br /&gt;
  a++;&lt;br /&gt;
  b |= c;&lt;br /&gt;
  d = f &amp;gt; g ? 0 : 1;&lt;br /&gt;
 &amp;lt;/pre&amp;gt;&lt;br /&gt;
d. Function calls should be nestled against the parentheses, the parentheses should crowd the arguments, and one space after commas:&lt;br /&gt;
 &amp;lt;pre style=&amp;quot;background:lightgrey;&amp;quot;&amp;gt;&lt;br /&gt;
  right: do_foo(bar, baz);&lt;br /&gt;
  wrong: do_foo ( bar,baz );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
e. All &#039;&#039;if&#039;&#039;, &#039;&#039;for&#039;&#039;, &#039;&#039;while&#039;&#039;, etc. expressions should be separated by a space from the parenthesis, one space after the semicolons:&lt;br /&gt;
 &amp;lt;pre style=&amp;quot;background:lightgrey;&amp;quot;&amp;gt;&lt;br /&gt;
  for (a = 0; a &amp;lt; b; a++)&lt;br /&gt;
  if (a &amp;lt; b || a == c)&lt;br /&gt;
  while (1)&lt;br /&gt;
 &amp;lt;/pre&amp;gt;&lt;br /&gt;
f. Opening braces should be on the same line as the line that introduces the block, except for function calls.  Closing braces get their own line, except for &amp;quot;else&amp;quot;.&lt;br /&gt;
 &amp;lt;pre style=&amp;quot;background:lightgrey;&amp;quot;&amp;gt;&lt;br /&gt;
  int foo(void)&lt;br /&gt;
  {&lt;br /&gt;
          if (bar) {&lt;br /&gt;
                  this();&lt;br /&gt;
                  that();&lt;br /&gt;
          } else if (baz) {&lt;br /&gt;
                  ;&lt;br /&gt;
          } else {&lt;br /&gt;
                  ;&lt;br /&gt;
          }&lt;br /&gt;
          do {&lt;br /&gt;
                  cow();&lt;br /&gt;
          } while (0);&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
g. If one part of a compound &#039;&#039;if&#039;&#039; block has braces, all should.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;background:lightgrey;&amp;quot;&amp;gt;&lt;br /&gt;
  right:&lt;br /&gt;
 &lt;br /&gt;
  if (foo) {&lt;br /&gt;
          bar();&lt;br /&gt;
          baz();&lt;br /&gt;
  } else {&lt;br /&gt;
          salmon();&lt;br /&gt;
  }&lt;br /&gt;
 &lt;br /&gt;
  wrong:&lt;br /&gt;
 &lt;br /&gt;
  if (foo) {&lt;br /&gt;
          bar();&lt;br /&gt;
          baz();&lt;br /&gt;
  } else&lt;br /&gt;
          moose();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
h. When you make a macro, protect those who might call it by using do/while and parentheses; line up your backslashes:&lt;br /&gt;
&amp;lt;pre style=&amp;quot;background:lightgrey;&amp;quot;&amp;gt;&lt;br /&gt;
  right:&lt;br /&gt;
 &lt;br /&gt;
  #define DO_STUFF(a)                              \&lt;br /&gt;
  do {                                             \&lt;br /&gt;
          int b = (a) + MAGIC;                     \&lt;br /&gt;
          do_other_stuff(b);                       \&lt;br /&gt;
  } while (0)&lt;br /&gt;
 &lt;br /&gt;
  wrong:&lt;br /&gt;
 &lt;br /&gt;
  #define DO_STUFF(a) \&lt;br /&gt;
  { \&lt;br /&gt;
          int b = a + MAGIC; \&lt;br /&gt;
          do_other_stuff(b); \&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
i. If you nest preprocessor commands, use spaces to visually delineate:&lt;br /&gt;
&amp;lt;pre style=&amp;quot;background:lightgrey;&amp;quot;&amp;gt;&lt;br /&gt;
  #ifdef __KERNEL__&lt;br /&gt;
  # include &amp;lt;goose&amp;gt;&lt;br /&gt;
  # define MOOSE steak&lt;br /&gt;
  #else&lt;br /&gt;
  # include &amp;lt;mutton&amp;gt;&lt;br /&gt;
  # define MOOSE prancing&lt;br /&gt;
  #endif&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
j.  For very long #ifdefs include the conditional with each #endif to make it readable:&lt;br /&gt;
&amp;lt;pre style=&amp;quot;background:lightgrey;&amp;quot;&amp;gt;&lt;br /&gt;
  #ifdef __KERNEL__&lt;br /&gt;
  # if LINUX_VERSION_CODE &amp;gt;= KERNEL_VERSION(2,5,0)&lt;br /&gt;
  /* lots&lt;br /&gt;
     of&lt;br /&gt;
     stuff */&lt;br /&gt;
  # endif /* KERNEL_VERSION(2,5,0) */&lt;br /&gt;
  #else /* !__KERNEL__ */&lt;br /&gt;
  # if HAVE_FEATURE&lt;br /&gt;
  /* more&lt;br /&gt;
   * stuff */&lt;br /&gt;
  # endif&lt;br /&gt;
  #endif /* __KERNEL__ */ &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
k. Comments should have the leading &#039;&#039;&#039;/*&#039;&#039;&#039; on the same line as the comment, and the trailing &#039;&#039;&#039;*/&#039;&#039;&#039; at the end of the last comment line.  Intermediate lines should start with a &#039;&#039;&#039;*&#039;&#039;&#039; aligned with the first line&#039;s &#039;&#039;&#039;*&#039;&#039;&#039;:&lt;br /&gt;
&amp;lt;pre style=&amp;quot;background:lightgrey;&amp;quot;&amp;gt; &lt;br /&gt;
 /* This is a short comment */&lt;br /&gt;
 &lt;br /&gt;
  /* This is a multi-line comment.  I wish the line would wrap already,&lt;br /&gt;
   * as I don&#039;t have much to write about. */&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
l. Function declarations absolutely should NOT go into .c files, unless they are forward declarations for static functions that can&#039;t otherwise be moved before the caller.  Instead, the declaration should go into the most &amp;quot;local&amp;quot; header available (preferrably *_internal.h for a given piece of code).&lt;br /&gt;
&lt;br /&gt;
m. Structure and constant declarations should not be declared in multiple places.  Put the struct into the most &amp;quot;local&amp;quot; header possible.  If it is something that is passed over the wire it needs to go into lustre_idl.h, and needs to be correctly swabbed when the RPC message is unpacked.&lt;br /&gt;
&lt;br /&gt;
n. The types and printf/printk formats used by Lustre code are:&lt;br /&gt;
&amp;lt;pre style=&amp;quot;background:lightgrey;&amp;quot;&amp;gt;&lt;br /&gt;
   __u64                 LPU64/LPX64/LPD64 (unsigned, hex, signed)&lt;br /&gt;
   size_t                LPSZ (or cast to int and use %u / %d)&lt;br /&gt;
   __u32/int             %u/%x/%d (unsigned, hex, signed)&lt;br /&gt;
   (unsigned) long long  %llu/%llx/%lld&lt;br /&gt;
   loff_t                %lld after a cast to long long (unfortunately)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
*&#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Front_Page FrontPage]&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Yep</name></author>
	</entry>
	<entry>
		<id>http://wiki.old.lustre.org/index.php?title=Coding_Guidelines&amp;diff=3109</id>
		<title>Coding Guidelines</title>
		<link rel="alternate" type="text/html" href="http://wiki.old.lustre.org/index.php?title=Coding_Guidelines&amp;diff=3109"/>
		<updated>2007-06-11T07:45:00Z</updated>

		<summary type="html">&lt;p&gt;Yep: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;All Lustre developers should follow the guidelines in this page very strictly to avoid problems during code merges later on. Please make the required changes to the default formatting rules in the editor you use to comply to the guidelines below.&lt;br /&gt;
&lt;br /&gt;
== Guidelines ==&lt;br /&gt;
&lt;br /&gt;
1. There should be no tabs in any files.&lt;br /&gt;
&lt;br /&gt;
2. Blocks should be indented by 8 spaces.&lt;br /&gt;
&lt;br /&gt;
3. New files should contain the following along with the license boilerplate.  This will cause vim and emacs to use spaces instead of tabs for indenting.  If you use a different editor, it also needs to be set to use spaces for indening Lustre code.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;background:lightgrey;&amp;quot;&amp;gt;&lt;br /&gt;
  /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-&lt;br /&gt;
   * vim:expandtab:shiftwidth=8:tabstop=8:&lt;br /&gt;
   */&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
4. All lines should wrap at 80 characters. If it&#039;s getting too hard to wrap there, you probably need to break it up into more functions.  In some cases, it is acceptable to remove a few spaces between function arguments to avoid overflowing onto the next line.&lt;br /&gt;
&lt;br /&gt;
5. Don&#039;t have spaces or tabs on blank lines or at the end of lines.&lt;br /&gt;
&lt;br /&gt;
6. Don&#039;t use &amp;quot;inline&amp;quot; unless you&#039;re doing something so performance critical that the function call overhead will make a difference -- in other words: never.  It makes debugging harder.&lt;br /&gt;
&lt;br /&gt;
All of our wrapping, parenthesis, brace placement, etc. rules are basically Linux kernel rules, which are basically K&amp;amp;R. For those of you in need of a refresher, great detail is provided below.&lt;br /&gt;
&lt;br /&gt;
== Great detail ==&lt;br /&gt;
&lt;br /&gt;
a. When you wrap, the next line should start after the parenthesis:&lt;br /&gt;
&amp;lt;pre style=&amp;quot;background:lightgrey;&amp;quot;&amp;gt;&lt;br /&gt;
  right:&lt;br /&gt;
 &lt;br /&gt;
  variable = do_something_complicated(long_argument, longer_argument,&lt;br /&gt;
                                      longest_argument(sub_argument,&lt;br /&gt;
                                                       foo_argument),&lt;br /&gt;
                                      last_argument);&lt;br /&gt;
 &lt;br /&gt;
  if (some_long_condition(arg1, arg2, arg3) &amp;lt; some_long_value &amp;amp;&amp;amp;&lt;br /&gt;
      another_long_condition(very_long_argument_name,&lt;br /&gt;
                             another_long_argument_name) &amp;gt;&lt;br /&gt;
      second_long_value) {&lt;br /&gt;
  }&lt;br /&gt;
                             &lt;br /&gt;
 &lt;br /&gt;
  wrong:&lt;br /&gt;
 &lt;br /&gt;
  variable = do_something_complicated(long_argument, longer_argument,&lt;br /&gt;
                    longest_argument(sub_argument, foo_argument),&lt;br /&gt;
                    last_argument);&lt;br /&gt;
 &lt;br /&gt;
  if (some_long_condition(arg1, arg2, arg3) &amp;lt; some_long_value &amp;amp;&amp;amp;&lt;br /&gt;
              another_long_condition(very_long_argument_name,&lt;br /&gt;
                    another_long_argument_name) &amp;gt;&lt;br /&gt;
                    second_long_value) {&lt;br /&gt;
  }&lt;br /&gt;
 &amp;lt;/pre&amp;gt;&lt;br /&gt;
b. If you&#039;re wrapping put the operators at the end of the line, and if there are no parentheses indent 8 more:&lt;br /&gt;
 &amp;lt;pre style=&amp;quot;background:lightgrey;&amp;quot;&amp;gt;&lt;br /&gt;
  off = le32_to_cpu(fsd-&amp;gt;fsd_client_start) +&lt;br /&gt;
          cl_idx * le16_to_cpu(fsd-&amp;gt;fsd_client_size);&lt;br /&gt;
 &amp;lt;/pre&amp;gt;&lt;br /&gt;
c. Binary and ternary (but not unary) operators should be separated from their arguments by one space.&lt;br /&gt;
 &amp;lt;pre style=&amp;quot;background:lightgrey;&amp;quot;&amp;gt;&lt;br /&gt;
  a++;&lt;br /&gt;
  b |= c;&lt;br /&gt;
  d = f &amp;gt; g ? 0 : 1;&lt;br /&gt;
 &amp;lt;/pre&amp;gt;&lt;br /&gt;
d. Function calls should be nestled against the parentheses, the parentheses should crowd the arguments, and one space after commas:&lt;br /&gt;
 &amp;lt;pre style=&amp;quot;background:lightgrey;&amp;quot;&amp;gt;&lt;br /&gt;
  right: do_foo(bar, baz);&lt;br /&gt;
  wrong: do_foo ( bar,baz );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
e. All &#039;&#039;if&#039;&#039;, &#039;&#039;for&#039;&#039;, &#039;&#039;while&#039;&#039;, etc. expressions should be separated by a space from the parenthesis, one space after the semicolons:&lt;br /&gt;
 &amp;lt;pre style=&amp;quot;background:lightgrey;&amp;quot;&amp;gt;&lt;br /&gt;
  for (a = 0; a &amp;lt; b; a++)&lt;br /&gt;
  if (a &amp;lt; b || a == c)&lt;br /&gt;
  while (1)&lt;br /&gt;
 &amp;lt;/pre&amp;gt;&lt;br /&gt;
f. Opening braces should be on the same line as the line that introduces the block, except for function calls.  Closing braces get their own line, except for &amp;quot;else&amp;quot;.&lt;br /&gt;
 &amp;lt;pre style=&amp;quot;background:lightgrey;&amp;quot;&amp;gt;&lt;br /&gt;
  int foo(void)&lt;br /&gt;
  {&lt;br /&gt;
          if (bar) {&lt;br /&gt;
                  this();&lt;br /&gt;
                  that();&lt;br /&gt;
          } else if (baz) {&lt;br /&gt;
                  ;&lt;br /&gt;
          } else {&lt;br /&gt;
                  ;&lt;br /&gt;
          }&lt;br /&gt;
          do {&lt;br /&gt;
                  cow();&lt;br /&gt;
          } while (0);&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
g. If one part of a compound &#039;&#039;if&#039;&#039; block has braces, all should.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;background:lightgrey;&amp;quot;&amp;gt;&lt;br /&gt;
  right:&lt;br /&gt;
 &lt;br /&gt;
  if (foo) {&lt;br /&gt;
          bar();&lt;br /&gt;
          baz();&lt;br /&gt;
  } else {&lt;br /&gt;
          salmon();&lt;br /&gt;
  }&lt;br /&gt;
 &lt;br /&gt;
  wrong:&lt;br /&gt;
 &lt;br /&gt;
  if (foo) {&lt;br /&gt;
          bar();&lt;br /&gt;
          baz();&lt;br /&gt;
  } else&lt;br /&gt;
          moose();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
h. When you make a macro, protect those who might call it by using do/while and parentheses; line up your backslashes:&lt;br /&gt;
&amp;lt;pre style=&amp;quot;background:lightgrey;&amp;quot;&amp;gt;&lt;br /&gt;
  right:&lt;br /&gt;
 &lt;br /&gt;
  #define DO_STUFF(a)                              \&lt;br /&gt;
  do {                                             \&lt;br /&gt;
          int b = (a) + MAGIC;                     \&lt;br /&gt;
          do_other_stuff(b);                       \&lt;br /&gt;
  } while (0)&lt;br /&gt;
 &lt;br /&gt;
  wrong:&lt;br /&gt;
 &lt;br /&gt;
  #define DO_STUFF(a) \&lt;br /&gt;
  { \&lt;br /&gt;
          int b = a + MAGIC; \&lt;br /&gt;
          do_other_stuff(b); \&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
i. If you nest preprocessor commands, use spaces to visually delineate:&lt;br /&gt;
&amp;lt;pre style=&amp;quot;background:lightgrey;&amp;quot;&amp;gt;&lt;br /&gt;
  #ifdef __KERNEL__&lt;br /&gt;
  # include &amp;lt;goose&amp;gt;&lt;br /&gt;
  # define MOOSE steak&lt;br /&gt;
  #else&lt;br /&gt;
  # include &amp;lt;mutton&amp;gt;&lt;br /&gt;
  # define MOOSE prancing&lt;br /&gt;
  #endif&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
j.  For very long #ifdefs include the conditional with each #endif to make it readable:&lt;br /&gt;
&amp;lt;pre style=&amp;quot;background:lightgrey;&amp;quot;&amp;gt;&lt;br /&gt;
  #ifdef __KERNEL__&lt;br /&gt;
  # if LINUX_VERSION_CODE &amp;gt;= KERNEL_VERSION(2,5,0)&lt;br /&gt;
  /* lots&lt;br /&gt;
     of&lt;br /&gt;
     stuff */&lt;br /&gt;
  # endif /* KERNEL_VERSION(2,5,0) */&lt;br /&gt;
  #else /* !__KERNEL__ */&lt;br /&gt;
  # if HAVE_FEATURE&lt;br /&gt;
  /* more&lt;br /&gt;
   * stuff */&lt;br /&gt;
  # endif&lt;br /&gt;
  #endif /* __KERNEL__ */ &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
k. Comments should have the leading &#039;&#039;&#039;/*&#039;&#039;&#039; on the same line as the comment, and the trailing &#039;&#039;&#039;*/&#039;&#039;&#039; at the end of the last comment line.  Intermediate lines should start with a &#039;&#039;&#039;*&#039;&#039;&#039; aligned with the first line&#039;s &#039;&#039;&#039;*&#039;&#039;&#039;:&lt;br /&gt;
  /* This is a short comment */&lt;br /&gt;
 &lt;br /&gt;
  /* This is a multi-line comment.  I wish the line would wrap already,&lt;br /&gt;
   * as I don&#039;t have much to write about. */&lt;br /&gt;
&lt;br /&gt;
l. Function declarations absolutely should NOT go into .c files, unless they are forward declarations for static functions that can&#039;t otherwise be moved before the caller.  Instead, the declaration should go into the most &amp;quot;local&amp;quot; header available (preferrably *_internal.h for a given piece of code).&lt;br /&gt;
&lt;br /&gt;
m. Structure and constant declarations should not be declared in multiple places.  Put the struct into the most &amp;quot;local&amp;quot; header possible.  If it is something that is passed over the wire it needs to go into lustre_idl.h, and needs to be correctly swabbed when the RPC message is unpacked.&lt;br /&gt;
&lt;br /&gt;
n. The types and printf/printk formats used by Lustre code are:&lt;br /&gt;
&amp;lt;pre style=&amp;quot;background:lightgrey;&amp;quot;&amp;gt;&lt;br /&gt;
   __u64                 LPU64/LPX64/LPD64 (unsigned, hex, signed)&lt;br /&gt;
   size_t                LPSZ (or cast to int and use %u / %d)&lt;br /&gt;
   __u32/int             %u/%x/%d (unsigned, hex, signed)&lt;br /&gt;
   (unsigned) long long  %llu/%llx/%lld&lt;br /&gt;
   loff_t                %lld after a cast to long long (unfortunately)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
*&#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Front_Page FrontPage]&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Yep</name></author>
	</entry>
	<entry>
		<id>http://wiki.old.lustre.org/index.php?title=Coding_Guidelines&amp;diff=3108</id>
		<title>Coding Guidelines</title>
		<link rel="alternate" type="text/html" href="http://wiki.old.lustre.org/index.php?title=Coding_Guidelines&amp;diff=3108"/>
		<updated>2007-06-11T07:43:22Z</updated>

		<summary type="html">&lt;p&gt;Yep: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;All Lustre developers should follow the guidelines in this page very strictly to avoid problems during code merges later on. Please make the required changes to the default formatting rules in the editor you use to comply to the guidelines below.&lt;br /&gt;
&lt;br /&gt;
== Guidelines ==&lt;br /&gt;
&lt;br /&gt;
1. There should be no tabs in any files.&lt;br /&gt;
&lt;br /&gt;
2. Blocks should be indented by 8 spaces.&lt;br /&gt;
&lt;br /&gt;
3. New files should contain the following along with the license boilerplate.  This will cause vim and emacs to use spaces instead of tabs for indenting.  If you use a different editor, it also needs to be set to use spaces for indening Lustre code.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;background:lightgrey;&amp;quot;&amp;gt;&lt;br /&gt;
  /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-&lt;br /&gt;
   * vim:expandtab:shiftwidth=8:tabstop=8:&lt;br /&gt;
   */&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
4. All lines should wrap at 80 characters. If it&#039;s getting too hard to wrap there, you probably need to break it up into more functions.  In some cases, it is acceptable to remove a few spaces between function arguments to avoid overflowing onto the next line.&lt;br /&gt;
&lt;br /&gt;
5. Don&#039;t have spaces or tabs on blank lines or at the end of lines.&lt;br /&gt;
&lt;br /&gt;
6. Don&#039;t use &amp;quot;inline&amp;quot; unless you&#039;re doing something so performance critical that the function call overhead will make a difference -- in other words: never.  It makes debugging harder.&lt;br /&gt;
&lt;br /&gt;
All of our wrapping, parenthesis, brace placement, etc. rules are basically Linux kernel rules, which are basically K&amp;amp;R. For those of you in need of a refresher, great detail is provided below.&lt;br /&gt;
&lt;br /&gt;
== Great detail ==&lt;br /&gt;
&lt;br /&gt;
a. When you wrap, the next line should start after the parenthesis:&lt;br /&gt;
&amp;lt;pre style=&amp;quot;background:lightgrey;&amp;quot;&amp;gt;&lt;br /&gt;
  right:&lt;br /&gt;
 &lt;br /&gt;
  variable = do_something_complicated(long_argument, longer_argument,&lt;br /&gt;
                                      longest_argument(sub_argument,&lt;br /&gt;
                                                       foo_argument),&lt;br /&gt;
                                      last_argument);&lt;br /&gt;
 &lt;br /&gt;
  if (some_long_condition(arg1, arg2, arg3) &amp;lt; some_long_value &amp;amp;&amp;amp;&lt;br /&gt;
      another_long_condition(very_long_argument_name,&lt;br /&gt;
                             another_long_argument_name) &amp;gt;&lt;br /&gt;
      second_long_value) {&lt;br /&gt;
  }&lt;br /&gt;
                             &lt;br /&gt;
 &lt;br /&gt;
  wrong:&lt;br /&gt;
 &lt;br /&gt;
  variable = do_something_complicated(long_argument, longer_argument,&lt;br /&gt;
                    longest_argument(sub_argument, foo_argument),&lt;br /&gt;
                    last_argument);&lt;br /&gt;
 &lt;br /&gt;
  if (some_long_condition(arg1, arg2, arg3) &amp;lt; some_long_value &amp;amp;&amp;amp;&lt;br /&gt;
              another_long_condition(very_long_argument_name,&lt;br /&gt;
                    another_long_argument_name) &amp;gt;&lt;br /&gt;
                    second_long_value) {&lt;br /&gt;
  }&lt;br /&gt;
 &amp;lt;/pre&amp;gt;&lt;br /&gt;
b. If you&#039;re wrapping put the operators at the end of the line, and if there are no parentheses indent 8 more:&lt;br /&gt;
 &amp;lt;pre style=&amp;quot;background:lightgrey;&amp;quot;&amp;gt;&lt;br /&gt;
  off = le32_to_cpu(fsd-&amp;gt;fsd_client_start) +&lt;br /&gt;
          cl_idx * le16_to_cpu(fsd-&amp;gt;fsd_client_size);&lt;br /&gt;
 &amp;lt;/pre&amp;gt;&lt;br /&gt;
c. Binary and ternary (but not unary) operators should be separated from their arguments by one space.&lt;br /&gt;
 &amp;lt;pre style=&amp;quot;background:lightgrey;&amp;quot;&amp;gt;&lt;br /&gt;
  a++;&lt;br /&gt;
  b |= c;&lt;br /&gt;
  d = f &amp;gt; g ? 0 : 1;&lt;br /&gt;
 &amp;lt;/pre&amp;gt;&lt;br /&gt;
d. Function calls should be nestled against the parentheses, the parentheses should crowd the arguments, and one space after commas:&lt;br /&gt;
 &amp;lt;pre style=&amp;quot;background:lightgrey;&amp;quot;&amp;gt;&lt;br /&gt;
  right: do_foo(bar, baz);&lt;br /&gt;
  wrong: do_foo ( bar,baz );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
e. All &#039;&#039;if&#039;&#039;, &#039;&#039;for&#039;&#039;, &#039;&#039;while&#039;&#039;, etc. expressions should be separated by a space from the parenthesis, one space after the semicolons:&lt;br /&gt;
 &amp;lt;pre style=&amp;quot;background:lightgrey;&amp;quot;&amp;gt;&lt;br /&gt;
  for (a = 0; a &amp;lt; b; a++)&lt;br /&gt;
  if (a &amp;lt; b || a == c)&lt;br /&gt;
  while (1)&lt;br /&gt;
 &amp;lt;/pre&amp;gt;&lt;br /&gt;
f. Opening braces should be on the same line as the line that introduces the block, except for function calls.  Closing braces get their own line, except for &amp;quot;else&amp;quot;.&lt;br /&gt;
 &amp;lt;pre style=&amp;quot;background:lightgrey;&amp;quot;&amp;gt;&lt;br /&gt;
  int foo(void)&lt;br /&gt;
  {&lt;br /&gt;
          if (bar) {&lt;br /&gt;
                  this();&lt;br /&gt;
                  that();&lt;br /&gt;
          } else if (baz) {&lt;br /&gt;
                  ;&lt;br /&gt;
          } else {&lt;br /&gt;
                  ;&lt;br /&gt;
          }&lt;br /&gt;
          do {&lt;br /&gt;
                  cow();&lt;br /&gt;
          } while (0);&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
g. If one part of a compound &#039;&#039;if&#039;&#039; block has braces, all should.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;background:lightgrey;&amp;quot;&amp;gt;&lt;br /&gt;
  right:&lt;br /&gt;
 &lt;br /&gt;
  if (foo) {&lt;br /&gt;
          bar();&lt;br /&gt;
          baz();&lt;br /&gt;
  } else {&lt;br /&gt;
          salmon();&lt;br /&gt;
  }&lt;br /&gt;
 &lt;br /&gt;
  wrong:&lt;br /&gt;
 &lt;br /&gt;
  if (foo) {&lt;br /&gt;
          bar();&lt;br /&gt;
          baz();&lt;br /&gt;
  } else&lt;br /&gt;
          moose();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
h. When you make a macro, protect those who might call it by using do/while and parentheses; line up your backslashes:&lt;br /&gt;
&amp;lt;pre style=&amp;quot;background:lightgrey;&amp;quot;&amp;gt;&lt;br /&gt;
  right:&lt;br /&gt;
 &lt;br /&gt;
  #define DO_STUFF(a)                              \&lt;br /&gt;
  do {                                             \&lt;br /&gt;
          int b = (a) + MAGIC;                     \&lt;br /&gt;
          do_other_stuff(b);                       \&lt;br /&gt;
  } while (0)&lt;br /&gt;
 &lt;br /&gt;
  wrong:&lt;br /&gt;
 &lt;br /&gt;
  #define DO_STUFF(a) \&lt;br /&gt;
  { \&lt;br /&gt;
          int b = a + MAGIC; \&lt;br /&gt;
          do_other_stuff(b); \&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
i. If you nest preprocessor commands, use spaces to visually delineate:&lt;br /&gt;
&lt;br /&gt;
  #ifdef __KERNEL__&lt;br /&gt;
  # include &amp;lt;goose&amp;gt;&lt;br /&gt;
  # define MOOSE steak&lt;br /&gt;
  #else&lt;br /&gt;
  # include &amp;lt;mutton&amp;gt;&lt;br /&gt;
  # define MOOSE prancing&lt;br /&gt;
  #endif&lt;br /&gt;
&lt;br /&gt;
j.  For very long #ifdefs include the conditional with each #endif to make it readable:&lt;br /&gt;
&lt;br /&gt;
  #ifdef __KERNEL__&lt;br /&gt;
  # if LINUX_VERSION_CODE &amp;gt;= KERNEL_VERSION(2,5,0)&lt;br /&gt;
  /* lots&lt;br /&gt;
     of&lt;br /&gt;
     stuff */&lt;br /&gt;
  # endif /* KERNEL_VERSION(2,5,0) */&lt;br /&gt;
  #else /* !__KERNEL__ */&lt;br /&gt;
  # if HAVE_FEATURE&lt;br /&gt;
  /* more&lt;br /&gt;
   * stuff */&lt;br /&gt;
  # endif&lt;br /&gt;
  #endif /* __KERNEL__ */ &lt;br /&gt;
&lt;br /&gt;
k. Comments should have the leading &#039;&#039;&#039;/*&#039;&#039;&#039; on the same line as the comment, and the trailing &#039;&#039;&#039;*/&#039;&#039;&#039; at the end of the last comment line.  Intermediate lines should start with a &#039;&#039;&#039;*&#039;&#039;&#039; aligned with the first line&#039;s &#039;&#039;&#039;*&#039;&#039;&#039;:&lt;br /&gt;
  /* This is a short comment */&lt;br /&gt;
 &lt;br /&gt;
  /* This is a multi-line comment.  I wish the line would wrap already,&lt;br /&gt;
   * as I don&#039;t have much to write about. */&lt;br /&gt;
&lt;br /&gt;
l. Function declarations absolutely should NOT go into .c files, unless they are forward declarations for static functions that can&#039;t otherwise be moved before the caller.  Instead, the declaration should go into the most &amp;quot;local&amp;quot; header available (preferrably *_internal.h for a given piece of code).&lt;br /&gt;
&lt;br /&gt;
m. Structure and constant declarations should not be declared in multiple places.  Put the struct into the most &amp;quot;local&amp;quot; header possible.  If it is something that is passed over the wire it needs to go into lustre_idl.h, and needs to be correctly swabbed when the RPC message is unpacked.&lt;br /&gt;
&lt;br /&gt;
n. The types and printf/printk formats used by Lustre code are:&lt;br /&gt;
&lt;br /&gt;
   __u64                 LPU64/LPX64/LPD64 (unsigned, hex, signed)&lt;br /&gt;
   size_t                LPSZ (or cast to int and use %u / %d)&lt;br /&gt;
   __u32/int             %u/%x/%d (unsigned, hex, signed)&lt;br /&gt;
   (unsigned) long long  %llu/%llx/%lld&lt;br /&gt;
   loff_t                %lld after a cast to long long (unfortunately)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
*&#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Front_Page FrontPage]&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Yep</name></author>
	</entry>
	<entry>
		<id>http://wiki.old.lustre.org/index.php?title=Coding_Guidelines&amp;diff=3107</id>
		<title>Coding Guidelines</title>
		<link rel="alternate" type="text/html" href="http://wiki.old.lustre.org/index.php?title=Coding_Guidelines&amp;diff=3107"/>
		<updated>2007-06-11T07:39:27Z</updated>

		<summary type="html">&lt;p&gt;Yep: /* Guidelines */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;All Lustre developers should follow the guidelines in this page very strictly to avoid problems during code merges later on. Please make the required changes to the default formatting rules in the editor you use to comply to the guidelines below.&lt;br /&gt;
&lt;br /&gt;
== Guidelines ==&lt;br /&gt;
&lt;br /&gt;
1. There should be no tabs in any files.&lt;br /&gt;
&lt;br /&gt;
2. Blocks should be indented by 8 spaces.&lt;br /&gt;
&lt;br /&gt;
3. New files should contain the following along with the license boilerplate.  This will cause vim and emacs to use spaces instead of tabs for indenting.  If you use a different editor, it also needs to be set to use spaces for indening Lustre code.&lt;br /&gt;
&amp;lt;pre style=&amp;quot;background:lightgrey;&amp;quot;&lt;br /&gt;
  /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-&lt;br /&gt;
   * vim:expandtab:shiftwidth=8:tabstop=8:&lt;br /&gt;
   */&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
4. All lines should wrap at 80 characters. If it&#039;s getting too hard to wrap there, you probably need to break it up into more functions.  In some cases, it is acceptable to remove a few spaces between function arguments to avoid overflowing onto the next line.&lt;br /&gt;
&lt;br /&gt;
5. Don&#039;t have spaces or tabs on blank lines or at the end of lines.&lt;br /&gt;
&lt;br /&gt;
6. Don&#039;t use &amp;quot;inline&amp;quot; unless you&#039;re doing something so performance critical that the function call overhead will make a difference -- in other words: never.  It makes debugging harder.&lt;br /&gt;
&lt;br /&gt;
All of our wrapping, parenthesis, brace placement, etc. rules are basically Linux kernel rules, which are basically K&amp;amp;R. For those of you in need of a refresher, great detail is provided below.&lt;br /&gt;
&lt;br /&gt;
== Great detail ==&lt;br /&gt;
&lt;br /&gt;
a. When you wrap, the next line should start after the parenthesis:&lt;br /&gt;
 &lt;br /&gt;
  right:&lt;br /&gt;
 &lt;br /&gt;
  variable = do_something_complicated(long_argument, longer_argument,&lt;br /&gt;
                                      longest_argument(sub_argument,&lt;br /&gt;
                                                       foo_argument),&lt;br /&gt;
                                      last_argument);&lt;br /&gt;
 &lt;br /&gt;
  if (some_long_condition(arg1, arg2, arg3) &amp;lt; some_long_value &amp;amp;&amp;amp;&lt;br /&gt;
      another_long_condition(very_long_argument_name,&lt;br /&gt;
                             another_long_argument_name) &amp;gt;&lt;br /&gt;
      second_long_value) {&lt;br /&gt;
  }&lt;br /&gt;
                             &lt;br /&gt;
 &lt;br /&gt;
  wrong:&lt;br /&gt;
 &lt;br /&gt;
  variable = do_something_complicated(long_argument, longer_argument,&lt;br /&gt;
                    longest_argument(sub_argument, foo_argument),&lt;br /&gt;
                    last_argument);&lt;br /&gt;
 &lt;br /&gt;
  if (some_long_condition(arg1, arg2, arg3) &amp;lt; some_long_value &amp;amp;&amp;amp;&lt;br /&gt;
              another_long_condition(very_long_argument_name,&lt;br /&gt;
                    another_long_argument_name) &amp;gt;&lt;br /&gt;
                    second_long_value) {&lt;br /&gt;
  }&lt;br /&gt;
 &lt;br /&gt;
b. If you&#039;re wrapping put the operators at the end of the line, and if there are no parentheses indent 8 more:&lt;br /&gt;
 &lt;br /&gt;
  off = le32_to_cpu(fsd-&amp;gt;fsd_client_start) +&lt;br /&gt;
          cl_idx * le16_to_cpu(fsd-&amp;gt;fsd_client_size);&lt;br /&gt;
 &lt;br /&gt;
c. Binary and ternary (but not unary) operators should be separated from their arguments by one space.&lt;br /&gt;
 &lt;br /&gt;
  a++;&lt;br /&gt;
  b |= c;&lt;br /&gt;
  d = f &amp;gt; g ? 0 : 1;&lt;br /&gt;
 &lt;br /&gt;
d. Function calls should be nestled against the parentheses, the parentheses should crowd the arguments, and one space after commas:&lt;br /&gt;
 &lt;br /&gt;
  right: do_foo(bar, baz);&lt;br /&gt;
  wrong: do_foo ( bar,baz );&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
e. All &#039;&#039;if&#039;&#039;, &#039;&#039;for&#039;&#039;, &#039;&#039;while&#039;&#039;, etc. expressions should be separated by a space from the parenthesis, one space after the semicolons:&lt;br /&gt;
 &lt;br /&gt;
  for (a = 0; a &amp;lt; b; a++)&lt;br /&gt;
  if (a &amp;lt; b || a == c)&lt;br /&gt;
  while (1)&lt;br /&gt;
 &lt;br /&gt;
f. Opening braces should be on the same line as the line that introduces the block, except for function calls.  Closing braces get their own line, except for &amp;quot;else&amp;quot;.&lt;br /&gt;
 &lt;br /&gt;
  int foo(void)&lt;br /&gt;
  {&lt;br /&gt;
          if (bar) {&lt;br /&gt;
                  this();&lt;br /&gt;
                  that();&lt;br /&gt;
          } else if (baz) {&lt;br /&gt;
                  ;&lt;br /&gt;
          } else {&lt;br /&gt;
                  ;&lt;br /&gt;
          }&lt;br /&gt;
          do {&lt;br /&gt;
                  cow();&lt;br /&gt;
          } while (0);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
g. If one part of a compound &#039;&#039;if&#039;&#039; block has braces, all should.&lt;br /&gt;
&lt;br /&gt;
  right:&lt;br /&gt;
 &lt;br /&gt;
  if (foo) {&lt;br /&gt;
          bar();&lt;br /&gt;
          baz();&lt;br /&gt;
  } else {&lt;br /&gt;
          salmon();&lt;br /&gt;
  }&lt;br /&gt;
 &lt;br /&gt;
  wrong:&lt;br /&gt;
 &lt;br /&gt;
  if (foo) {&lt;br /&gt;
          bar();&lt;br /&gt;
          baz();&lt;br /&gt;
  } else&lt;br /&gt;
          moose();&lt;br /&gt;
&lt;br /&gt;
h. When you make a macro, protect those who might call it by using do/while and parentheses; line up your backslashes:&lt;br /&gt;
&lt;br /&gt;
  right:&lt;br /&gt;
 &lt;br /&gt;
  #define DO_STUFF(a)                              \&lt;br /&gt;
  do {                                             \&lt;br /&gt;
          int b = (a) + MAGIC;                     \&lt;br /&gt;
          do_other_stuff(b);                       \&lt;br /&gt;
  } while (0)&lt;br /&gt;
 &lt;br /&gt;
  wrong:&lt;br /&gt;
 &lt;br /&gt;
  #define DO_STUFF(a) \&lt;br /&gt;
  { \&lt;br /&gt;
          int b = a + MAGIC; \&lt;br /&gt;
          do_other_stuff(b); \&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
i. If you nest preprocessor commands, use spaces to visually delineate:&lt;br /&gt;
&lt;br /&gt;
  #ifdef __KERNEL__&lt;br /&gt;
  # include &amp;lt;goose&amp;gt;&lt;br /&gt;
  # define MOOSE steak&lt;br /&gt;
  #else&lt;br /&gt;
  # include &amp;lt;mutton&amp;gt;&lt;br /&gt;
  # define MOOSE prancing&lt;br /&gt;
  #endif&lt;br /&gt;
&lt;br /&gt;
j.  For very long #ifdefs include the conditional with each #endif to make it readable:&lt;br /&gt;
&lt;br /&gt;
  #ifdef __KERNEL__&lt;br /&gt;
  # if LINUX_VERSION_CODE &amp;gt;= KERNEL_VERSION(2,5,0)&lt;br /&gt;
  /* lots&lt;br /&gt;
     of&lt;br /&gt;
     stuff */&lt;br /&gt;
  # endif /* KERNEL_VERSION(2,5,0) */&lt;br /&gt;
  #else /* !__KERNEL__ */&lt;br /&gt;
  # if HAVE_FEATURE&lt;br /&gt;
  /* more&lt;br /&gt;
   * stuff */&lt;br /&gt;
  # endif&lt;br /&gt;
  #endif /* __KERNEL__ */ &lt;br /&gt;
&lt;br /&gt;
k. Comments should have the leading &#039;&#039;&#039;/*&#039;&#039;&#039; on the same line as the comment, and the trailing &#039;&#039;&#039;*/&#039;&#039;&#039; at the end of the last comment line.  Intermediate lines should start with a &#039;&#039;&#039;*&#039;&#039;&#039; aligned with the first line&#039;s &#039;&#039;&#039;*&#039;&#039;&#039;:&lt;br /&gt;
  /* This is a short comment */&lt;br /&gt;
 &lt;br /&gt;
  /* This is a multi-line comment.  I wish the line would wrap already,&lt;br /&gt;
   * as I don&#039;t have much to write about. */&lt;br /&gt;
&lt;br /&gt;
l. Function declarations absolutely should NOT go into .c files, unless they are forward declarations for static functions that can&#039;t otherwise be moved before the caller.  Instead, the declaration should go into the most &amp;quot;local&amp;quot; header available (preferrably *_internal.h for a given piece of code).&lt;br /&gt;
&lt;br /&gt;
m. Structure and constant declarations should not be declared in multiple places.  Put the struct into the most &amp;quot;local&amp;quot; header possible.  If it is something that is passed over the wire it needs to go into lustre_idl.h, and needs to be correctly swabbed when the RPC message is unpacked.&lt;br /&gt;
&lt;br /&gt;
n. The types and printf/printk formats used by Lustre code are:&lt;br /&gt;
&lt;br /&gt;
   __u64                 LPU64/LPX64/LPD64 (unsigned, hex, signed)&lt;br /&gt;
   size_t                LPSZ (or cast to int and use %u / %d)&lt;br /&gt;
   __u32/int             %u/%x/%d (unsigned, hex, signed)&lt;br /&gt;
   (unsigned) long long  %llu/%llx/%lld&lt;br /&gt;
   loff_t                %lld after a cast to long long (unfortunately)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
*&#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Front_Page FrontPage]&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Yep</name></author>
	</entry>
	<entry>
		<id>http://wiki.old.lustre.org/index.php?title=Main_Page&amp;diff=2763</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="http://wiki.old.lustre.org/index.php?title=Main_Page&amp;diff=2763"/>
		<updated>2007-05-22T07:51:09Z</updated>

		<summary type="html">&lt;p&gt;Yep: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Links to Lustre resources and knowledge ==&lt;br /&gt;
&lt;br /&gt;
* Lustre Architecture Wiki - http://arch.lustre.org&lt;br /&gt;
* Lustre Manual and Documentation - http://manual.lustre.org&lt;br /&gt;
* Lustre Centre of Excellence Wiki Sites&lt;br /&gt;
** ORNL LCE Wiki - http://ornl-lce.clusterfs.com&lt;br /&gt;
* Lustre IO Performance Project Page - http://wiki.lustre.org/index.php?title=IOPerformanceProject&lt;br /&gt;
&lt;br /&gt;
== Documentation ==&lt;br /&gt;
 &lt;br /&gt;
*[http://wiki.lustre.org/index.php?title=Lustre_Documentation Lustre Documentation] - Lustre Manual and also links to older documents&lt;br /&gt;
&lt;br /&gt;
== Lustre User Group ==&lt;br /&gt;
&lt;br /&gt;
* LUG Requirements Forum - [http://wiki.lustre.org/images/7/78/LUG-Requirements-060420-final.pdf LUG-Requirements-060420-final.pdf] | [http://wiki.lustre.org/images/7/78/LUG-Requirements-060420-final.xls LUG-Requirements-060420-final.xls]&lt;br /&gt;
* Lustre Users Group (http://lustreusers.org)&lt;br /&gt;
&lt;br /&gt;
== Community Development Activities ==&lt;br /&gt;
&lt;br /&gt;
* [http://wiki.lustre.org/index.php?title=Networking_Development NetworkingDevelopment]&lt;br /&gt;
* [http://wiki.lustre.org/index.php?title=Diskless_Booting DisklessBooting]&lt;br /&gt;
* [http://wiki.lustre.org/index.php?title=Parallel_Io_Enhancements ParallelIoEnhancements]&lt;br /&gt;
* [http://wiki.lustre.org/index.php?title=Drbd_And_Lustre DrbdAndLustre]&lt;br /&gt;
* Bull- Open Source tools for Lustre http://www.bullopensource.org/lustre&lt;br /&gt;
* LLNL- Lustre Monitoring Tool http://www.sourceforge.net/projects/lmt/&lt;br /&gt;
* [http://wiki.lustre.org/index.php?title=Contributed_Patches_And_Code ContributedPatchesAndCode]&lt;br /&gt;
&lt;br /&gt;
== Lustre Testing &amp;amp; QA ==&lt;br /&gt;
&lt;br /&gt;
* [http://wiki.lustre.org/images/7/78/vision-scope.html  Vision &amp;amp; Scope of New Testing System] and [http://wiki.lustre.org/images/7/78/use-cases.html Use Cases]&lt;br /&gt;
* Buffalo Test Reports (http://buffalo.lustre.org)&lt;br /&gt;
* &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Lustre_Testing LustreTesting]&#039;&#039;&#039; - Our QA practices, procedures and support infrastructure.&lt;br /&gt;
* &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Testing_Tools TestingTools]&#039;&#039;&#039; - Help on some of available Lustre testing tools.(l2dbench, echo client/server etc..)&lt;br /&gt;
&lt;br /&gt;
== Development Practices ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Bugs&#039;&#039;&#039;&lt;br /&gt;
** &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Bug_Filing BugFiling]&#039;&#039;&#039; - A guide for testers.&lt;br /&gt;
** &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Bug_Management BugManagement]&#039;&#039;&#039; - How to accept and manage bug fixings with Bugzilla.&lt;br /&gt;
** Lustre Bugzilla (http://bugzilla.lustre.org)&lt;br /&gt;
* &#039;&#039;&#039;Development&#039;&#039;&#039;&lt;br /&gt;
** &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Coding_Guide_lines CodingGuidelines]&#039;&#039;&#039; - Formatting and indentation that should strictly be followed for any code checked into any branch.&lt;br /&gt;
** &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Contribution_Policy ContributionPolicy]&#039;&#039;&#039; - What to do to get your changes in.&lt;br /&gt;
** &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Cvs_Branches CvsBranches]&#039;&#039;&#039; - How to manage branches with CVS.&lt;br /&gt;
** &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Cvs_Tips CvsTips]&#039;&#039;&#039; - Helpful things to know while using Lustre CVS.&lt;br /&gt;
** &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Kernel_Patch_Management KernelPatchManagement]&#039;&#039;&#039; - How to handle the kernel patches.&lt;br /&gt;
** &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Lustre_Debugging LustreDebugging]&#039;&#039;&#039; - A guide to Lustre debugging.&lt;br /&gt;
** &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Lustre_Uml LustreUml]&#039;&#039;&#039; - Setting up and running Lustre on UMLs.&lt;br /&gt;
** &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Development_Cluster DevelopmentCluster]&#039;&#039;&#039; - Properties of a cluster that offers a good debugging environment.&lt;br /&gt;
** &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Linux_Debugging LinuxDebugging]&#039;&#039;&#039; - Debugging tools available for Linux kernel debugging(Kgdb, vmware, netdump, netconsole).&lt;br /&gt;
* &#039;&#039;&#039;Release Engineering&#039;&#039;&#039;&lt;br /&gt;
** &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Release_Planning ReleasePlanning]&#039;&#039;&#039; - What QA goals accompany merges and releases.&lt;br /&gt;
** &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Kernel_Patch_Management KernelPatchManagement]&#039;&#039;&#039; - How to handle the kernel patches.&lt;br /&gt;
** &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Lustre_Statuson_Linux26 LustreStatusonLinux26]&#039;&#039;&#039;  - Contributed patches and debugging hints&lt;br /&gt;
&lt;br /&gt;
== Some Design Information ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Ext3_Development Ext3Development]&#039;&#039;&#039; - community ext3 development work&lt;br /&gt;
* &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=File_Creation FileCreation]&#039;&#039;&#039; - Alternative file create path&lt;br /&gt;
* &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Design_Changes DesignChanges]&#039;&#039;&#039; - Design work summary of last 6 months&lt;br /&gt;
** &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Lock_Refinements LockRefinements]&#039;&#039;&#039; - Lustre Lite Performance lock refinements&lt;br /&gt;
** &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Import_Statest ImportStates]&#039;&#039;&#039; - Refine client import states.&lt;br /&gt;
* &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Recovery_Overview RecoveryOverview]&#039;&#039;&#039; - How Lustre recovers from various failure cases.&lt;br /&gt;
* &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Service_Monitors ServiceMonitors]&#039;&#039;&#039; - Design for permanent Lustre service monitoring.&lt;br /&gt;
* &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Raid5_Patches Raid5Patches]&#039;&#039;&#039; - patches to Linux RAID5 code to improve Lustre performance&lt;br /&gt;
&lt;br /&gt;
----&lt;/div&gt;</summary>
		<author><name>Yep</name></author>
	</entry>
	<entry>
		<id>http://wiki.old.lustre.org/index.php?title=Main_Page&amp;diff=2762</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="http://wiki.old.lustre.org/index.php?title=Main_Page&amp;diff=2762"/>
		<updated>2007-05-22T07:48:05Z</updated>

		<summary type="html">&lt;p&gt;Yep: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Main Pages ==&lt;br /&gt;
This is the new Lustre Wiki.  Here you find links to Lustre resources and knowledge.&lt;br /&gt;
* Lustre Architecture Wiki - http://arch.lustre.org&lt;br /&gt;
* Lustre Manual and Documentation - http://manual.lustre.org&lt;br /&gt;
* Lustre Centre of Excellence Wiki Sites&lt;br /&gt;
** ORNL LCE Wiki - http://ornl-lce.clusterfs.com&lt;br /&gt;
* Lustre IO Performance Project Page - http://wiki.lustre.org/index.php?title=IOPerformanceProject&lt;br /&gt;
&lt;br /&gt;
== Documentation ==&lt;br /&gt;
 &lt;br /&gt;
*[http://wiki.lustre.org/index.php?title=Lustre_Documentation Lustre Documentation] - Lustre Manual and also links to older documents&lt;br /&gt;
&lt;br /&gt;
== Lustre User Group ==&lt;br /&gt;
&lt;br /&gt;
* LUG Requirements Forum - [http://wiki.lustre.org/images/7/78/LUG-Requirements-060420-final.pdf LUG-Requirements-060420-final.pdf] | [http://wiki.lustre.org/images/7/78/LUG-Requirements-060420-final.xls LUG-Requirements-060420-final.xls]&lt;br /&gt;
* Lustre Users Group (http://lustreusers.org)&lt;br /&gt;
&lt;br /&gt;
== Community Development Activities ==&lt;br /&gt;
&lt;br /&gt;
* [http://wiki.lustre.org/index.php?title=Networking_Development NetworkingDevelopment]&lt;br /&gt;
* [http://wiki.lustre.org/index.php?title=Diskless_Booting DisklessBooting]&lt;br /&gt;
* [http://wiki.lustre.org/index.php?title=Parallel_Io_Enhancements ParallelIoEnhancements]&lt;br /&gt;
* [http://wiki.lustre.org/index.php?title=Drbd_And_Lustre DrbdAndLustre]&lt;br /&gt;
* Bull- Open Source tools for Lustre http://www.bullopensource.org/lustre&lt;br /&gt;
* LLNL- Lustre Monitoring Tool http://www.sourceforge.net/projects/lmt/&lt;br /&gt;
* [http://wiki.lustre.org/index.php?title=Contributed_Patches_And_Code ContributedPatchesAndCode]&lt;br /&gt;
&lt;br /&gt;
== Lustre Testing &amp;amp; QA ==&lt;br /&gt;
&lt;br /&gt;
* [http://wiki.lustre.org/images/7/78/vision-scope.html  Vision &amp;amp; Scope of New Testing System] and [http://wiki.lustre.org/images/7/78/use-cases.html Use Cases]&lt;br /&gt;
* Buffalo Test Reports (http://buffalo.lustre.org)&lt;br /&gt;
* &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Lustre_Testing LustreTesting]&#039;&#039;&#039; - Our QA practices, procedures and support infrastructure.&lt;br /&gt;
* &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Testing_Tools TestingTools]&#039;&#039;&#039; - Help on some of available Lustre testing tools.(l2dbench, echo client/server etc..)&lt;br /&gt;
&lt;br /&gt;
== Development Practices ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Bugs&#039;&#039;&#039;&lt;br /&gt;
** &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Bug_Filing BugFiling]&#039;&#039;&#039; - A guide for testers.&lt;br /&gt;
** &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Bug_Management BugManagement]&#039;&#039;&#039; - How to accept and manage bug fixings with Bugzilla.&lt;br /&gt;
** Lustre Bugzilla (http://bugzilla.lustre.org)&lt;br /&gt;
* &#039;&#039;&#039;Development&#039;&#039;&#039;&lt;br /&gt;
** &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Coding_Guide_lines CodingGuidelines]&#039;&#039;&#039; - Formatting and indentation that should strictly be followed for any code checked into any branch.&lt;br /&gt;
** &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Contribution_Policy ContributionPolicy]&#039;&#039;&#039; - What to do to get your changes in.&lt;br /&gt;
** &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Cvs_Branches CvsBranches]&#039;&#039;&#039; - How to manage branches with CVS.&lt;br /&gt;
** &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Cvs_Tips CvsTips]&#039;&#039;&#039; - Helpful things to know while using Lustre CVS.&lt;br /&gt;
** &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Kernel_Patch_Management KernelPatchManagement]&#039;&#039;&#039; - How to handle the kernel patches.&lt;br /&gt;
** &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Lustre_Debugging LustreDebugging]&#039;&#039;&#039; - A guide to Lustre debugging.&lt;br /&gt;
** &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Lustre_Uml LustreUml]&#039;&#039;&#039; - Setting up and running Lustre on UMLs.&lt;br /&gt;
** &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Development_Cluster DevelopmentCluster]&#039;&#039;&#039; - Properties of a cluster that offers a good debugging environment.&lt;br /&gt;
** &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Linux_Debugging LinuxDebugging]&#039;&#039;&#039; - Debugging tools available for Linux kernel debugging(Kgdb, vmware, netdump, netconsole).&lt;br /&gt;
* &#039;&#039;&#039;Release Engineering&#039;&#039;&#039;&lt;br /&gt;
** &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Release_Planning ReleasePlanning]&#039;&#039;&#039; - What QA goals accompany merges and releases.&lt;br /&gt;
** &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Kernel_Patch_Management KernelPatchManagement]&#039;&#039;&#039; - How to handle the kernel patches.&lt;br /&gt;
** &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Lustre_Statuson_Linux26 LustreStatusonLinux26]&#039;&#039;&#039;  - Contributed patches and debugging hints&lt;br /&gt;
&lt;br /&gt;
== Some Design Information ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Ext3_Development Ext3Development]&#039;&#039;&#039; - community ext3 development work&lt;br /&gt;
* &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=File_Creation FileCreation]&#039;&#039;&#039; - Alternative file create path&lt;br /&gt;
* &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Design_Changes DesignChanges]&#039;&#039;&#039; - Design work summary of last 6 months&lt;br /&gt;
** &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Lock_Refinements LockRefinements]&#039;&#039;&#039; - Lustre Lite Performance lock refinements&lt;br /&gt;
** &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Import_Statest ImportStates]&#039;&#039;&#039; - Refine client import states.&lt;br /&gt;
* &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Recovery_Overview RecoveryOverview]&#039;&#039;&#039; - How Lustre recovers from various failure cases.&lt;br /&gt;
* &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Service_Monitors ServiceMonitors]&#039;&#039;&#039; - Design for permanent Lustre service monitoring.&lt;br /&gt;
* &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Raid5_Patches Raid5Patches]&#039;&#039;&#039; - patches to Linux RAID5 code to improve Lustre performance&lt;br /&gt;
&lt;br /&gt;
----&lt;/div&gt;</summary>
		<author><name>Yep</name></author>
	</entry>
	<entry>
		<id>http://wiki.old.lustre.org/index.php?title=Lustre_Documentation&amp;diff=2386</id>
		<title>Lustre Documentation</title>
		<link rel="alternate" type="text/html" href="http://wiki.old.lustre.org/index.php?title=Lustre_Documentation&amp;diff=2386"/>
		<updated>2007-05-15T02:40:28Z</updated>

		<summary type="html">&lt;p&gt;Yep: /* Older Documentation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Lustre Documentation =&lt;br /&gt;
== Lustre Manual ==&lt;br /&gt;
&lt;br /&gt;
=== Lustre 1.6 ===&lt;br /&gt;
* &#039;&#039;&#039;Lustre Manual - HTML &#039;&#039;&#039;[http://wiki.lustre.org/images/7/78/LustreManual1_6.html Lustre 1.6 manual V1.1]&lt;br /&gt;
* &#039;&#039;&#039;Lustre Manual - PDF&#039;&#039;&#039;&lt;br /&gt;
** &#039;&#039;&#039;&#039;&#039;&#039;[http://wiki.lustre.org/images/7/78/LustreManual1_6.pdf Lustre 1.6 manual V1.1(A4)]&lt;br /&gt;
**&#039;&#039;&#039;&#039;&#039;&#039;[http://wiki.lustre.org/images/7/78/LustreManual-letter1_6.pdf Lustre 1.6 manual V1.1(Letter)]&lt;br /&gt;
* &#039;&#039;&#039;Lustre Manual Changelog &#039;&#039;&#039;[http://wiki.lustre.org/images/7/78/manual-changelog1_6.html Lustre Manual-Change log]&lt;br /&gt;
* &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Mount_Conf MountConf wiki]&#039;&#039;&#039; - A quick reference for those familiar with older versions of Lustre&lt;br /&gt;
&lt;br /&gt;
=== Lustre 1.4.8 ===&lt;br /&gt;
* &#039;&#039;&#039;Lustre Manual - HTML &#039;&#039;&#039;[http://wiki.lustre.org/images/7/78/LustreManual.html Lustre 1.4.8 manual V1.37]&lt;br /&gt;
* &#039;&#039;&#039;Lustre Manual - PDF&#039;&#039;&#039;&lt;br /&gt;
** &#039;&#039;&#039;&#039;&#039;&#039;[http://wiki.lustre.org/images/7/78/LustreManual37.pdf Lustre 1.4.8 manual V1.37(A4)]&lt;br /&gt;
** &#039;&#039;&#039;Lustre Manual Changelog &#039;&#039;&#039;[http://wiki.lustre.org/images/7/78/manual-changelog.html Lustre Manual-Change log]&lt;br /&gt;
&lt;br /&gt;
== Interim Lustre 1.8 Documentation ==&lt;br /&gt;
* &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Kerb_Lustre KerbLustre]&#039;&#039;&#039; - The 1.8 interim Lustre documentation (Kerberos....)&lt;br /&gt;
&lt;br /&gt;
== Older Documentation ==&lt;br /&gt;
This documentation will be incorporated into the manual. Until that is done you may find useful bits and pieces here.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Frequently Asked Questions&#039;&#039;&#039;&lt;br /&gt;
** [http://www.clusterfs.com/faq.html Lustre Faq]&lt;br /&gt;
* &#039;&#039;&#039;Knowledge Base&#039;&#039;&#039;&lt;br /&gt;
** [http://bugzilla.lustre.org/showdependencytree.cgi?id=2374 Lustre Knowledge Base] - questions and answers&lt;br /&gt;
* &#039;&#039;&#039;Configuration&#039;&#039;&#039;&lt;br /&gt;
** [http://wiki.lustre.org/index.php?title=Lustre_Howto LustreHowto]&#039;&#039;&#039; - A guide to getting Lustre cluster started.&lt;br /&gt;
** [http://wiki.lustre.org/index.php?title=Lustre_LDAP LustreLDAP]&#039;&#039;&#039; - A guide for using LDAP with Lustre.&lt;br /&gt;
** [http://wiki.lustre.org/index.php?title=Lustre_Wizard LustreWizard]&#039;&#039;&#039; - The &#039;&#039;Lustre wizard&#039;&#039; or &#039;&#039;lwizard&#039;&#039; is a utility that helps with creation of configuration file for a cluster through asking some simple questions.&lt;br /&gt;
** [http://wiki.lustre.org/index.php?title=Lustre_Failover LustreFailover]&#039;&#039;&#039; - Managing failover&lt;br /&gt;
** [http://wiki.lustre.org/index.php?title=Filesystem_Backup FilesystemBackup]&#039;&#039;&#039; - How to back up a Lustre filesystem&lt;br /&gt;
** [http://wiki.lustre.org/index.php?title=Fsck_Suppor FsckSupport]&#039;&#039;&#039; - The lustre fsck tool and Lustre-patched e2fsck (extents, large inode/EA support)&lt;br /&gt;
** &#039;&#039;&#039;Filesystem Tuning&#039;&#039;&#039;&lt;br /&gt;
*[http://wiki.lustre.org/images/7/78/LustreManual.html#Chapter_III-2._LustreProc LustreProc] - A guide on the &#039;&#039;&#039;proc&#039;&#039;&#039; tunables parameters for Lustre and their usage. It describes several of the &#039;&#039;proc&#039;&#039; tunables including those that effect the client&#039;s RPC behaviour and prepare for a substantial reorganization of proc entries.&lt;br /&gt;
*&#039;&#039;&#039;[http://wiki.lustre.org/images/7/78/LustreManual.html#3.2_DDN_Tuning LustreDdnTuning]&#039;&#039;&#039; - A brief guide on tuning DDN S2A 8500 (and maybe 9500) storage optimally for Lustre&lt;/div&gt;</summary>
		<author><name>Yep</name></author>
	</entry>
	<entry>
		<id>http://wiki.old.lustre.org/index.php?title=File:Mrtg-2.13.2.tar.gz&amp;diff=1768</id>
		<title>File:Mrtg-2.13.2.tar.gz</title>
		<link rel="alternate" type="text/html" href="http://wiki.old.lustre.org/index.php?title=File:Mrtg-2.13.2.tar.gz&amp;diff=1768"/>
		<updated>2007-05-07T10:13:20Z</updated>

		<summary type="html">&lt;p&gt;Yep: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Yep</name></author>
	</entry>
	<entry>
		<id>http://wiki.old.lustre.org/index.php?title=Lustre_Documentation&amp;diff=1750</id>
		<title>Lustre Documentation</title>
		<link rel="alternate" type="text/html" href="http://wiki.old.lustre.org/index.php?title=Lustre_Documentation&amp;diff=1750"/>
		<updated>2007-05-05T22:41:48Z</updated>

		<summary type="html">&lt;p&gt;Yep: /* Lustre 1.4.8 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Lustre Documentation =&lt;br /&gt;
== Lustre Manual ==&lt;br /&gt;
&lt;br /&gt;
=== Lustre 1.6 ===&lt;br /&gt;
 * &#039;&#039;&#039;Lustre Manual - HTML &#039;&#039;&#039;[http://wiki.lustre.org/images/7/78/LustreManual1_6.html Lustre 1.6 manual V1.1]&lt;br /&gt;
 * &#039;&#039;&#039;Lustre Manual - PDF&#039;&#039;&#039;&lt;br /&gt;
  . &#039;&#039;&#039;&#039;&#039;&#039;[http://wiki.lustre.org/images/7/78/LustreManual1_6.pdf Lustre 1.6 manual V1.1(A4)]&lt;br /&gt;
  . &#039;&#039;&#039;&#039;&#039;&#039;[http://wiki.lustre.org/images/7/78/LustreManual-letter1_6.pdf Lustre 1.6 manual V1.1(Letter)]&lt;br /&gt;
 * &#039;&#039;&#039;Lustre Manual Changelog &#039;&#039;&#039;[http://wiki.lustre.org/images/7/78/manual-changelog1_6.html Lustre Manual-Change log]&lt;br /&gt;
 * &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Mount_Conf MountConf wiki]&#039;&#039;&#039; - A quick reference for those familiar with older versions of Lustre&lt;br /&gt;
&lt;br /&gt;
=== Lustre 1.4.8 ===&lt;br /&gt;
 * &#039;&#039;&#039;Lustre Manual - HTML &#039;&#039;&#039;[http://wiki.lustre.org/images/7/78/LustreManual.html Lustre 1.4.8 manual V1.37]&lt;br /&gt;
 * &#039;&#039;&#039;Lustre Manual - PDF&#039;&#039;&#039;&lt;br /&gt;
  . &#039;&#039;&#039;&#039;&#039;&#039;[http://wiki.lustre.org/images/7/78/LustreManual37.pdf Lustre 1.4.8 manual V1.37(A4)]&lt;br /&gt;
 * &#039;&#039;&#039;Lustre Manual Changelog &#039;&#039;&#039;[http://wiki.lustre.org/images/7/78/manual-changelog.html Lustre Manual-Change log]&lt;br /&gt;
&lt;br /&gt;
== Interim Lustre 1.8 Documentation ==&lt;br /&gt;
 * &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Kerb_Lustre KerbLustre]&#039;&#039;&#039; - The 1.8 interim Lustre documentation (Kerberos....)&lt;br /&gt;
&lt;br /&gt;
== Older Documentation ==&lt;br /&gt;
This documentation will be incorporated into the manual. Until that is done you may find useful bits and pieces here.&lt;br /&gt;
&lt;br /&gt;
 * &#039;&#039;&#039;Frequently Asked Questions&#039;&#039;&#039;&lt;br /&gt;
  . [http://www.clusterfs.com/faq.html Lustre Faq]&lt;br /&gt;
 * &#039;&#039;&#039;Knowledge Base&#039;&#039;&#039;&lt;br /&gt;
  . [http://bugzilla.lustre.org/showdependencytree.cgi?id=2374 Lustre Knowledge Base] - questions and answers&lt;br /&gt;
 * &#039;&#039;&#039;Configuration&#039;&#039;&#039;&lt;br /&gt;
  * &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Lustre_Howto LustreHowto]&#039;&#039;&#039; - A guide to getting Lustre cluster started.&lt;br /&gt;
  * &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Lustre_LDAP LustreLDAP]&#039;&#039;&#039; - A guide for using LDAP with Lustre.&lt;br /&gt;
  * &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Lustre_Wizard LustreWizard]&#039;&#039;&#039; - The &#039;&#039;Lustre wizard&#039;&#039; or &#039;&#039;lwizard&#039;&#039; is a utility that helps with creation of configuration file for a cluster through asking some simple questions.&lt;br /&gt;
  * &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Lustre_Failover LustreFailover]&#039;&#039;&#039; - Managing failover&lt;br /&gt;
  * &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Filesystem_Backup FilesystemBackup]&#039;&#039;&#039; - How to back up a Lustre filesystem&lt;br /&gt;
  * &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Fsck_Suppor FsckSupport]&#039;&#039;&#039; - The lustre fsck tool and Lustre-patched e2fsck (extents, large inode/EA support)&lt;br /&gt;
  * &#039;&#039;&#039;Filesystem Tuning&#039;&#039;&#039;&lt;br /&gt;
   * [https://mail.clusterfs.com/wikis/attachments/LustreManual.html#Chapter_III-2._LustreProc LustreProc] - A guide on the &#039;&#039;&#039;proc&#039;&#039;&#039; tunables parameters for Lustre and their usage. It describes several of the &#039;&#039;proc&#039;&#039; tunables including those that effect the client&#039;s RPC behaviour and prepare for a substantial reorganization of proc entries.&lt;br /&gt;
   * &#039;&#039;&#039;[https://mail.clusterfs.com/wikis/attachments/LustreManual.html#3.2_DDN_Tuning LustreDdnTuning]&#039;&#039;&#039; - A brief guide on tuning DDN S2A 8500 (and maybe 9500) storage optimally for Lustre&lt;/div&gt;</summary>
		<author><name>Yep</name></author>
	</entry>
	<entry>
		<id>http://wiki.old.lustre.org/index.php?title=Lustre_Documentation&amp;diff=1749</id>
		<title>Lustre Documentation</title>
		<link rel="alternate" type="text/html" href="http://wiki.old.lustre.org/index.php?title=Lustre_Documentation&amp;diff=1749"/>
		<updated>2007-05-05T22:38:36Z</updated>

		<summary type="html">&lt;p&gt;Yep: /* Lustre 1.6 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Lustre Documentation =&lt;br /&gt;
== Lustre Manual ==&lt;br /&gt;
&lt;br /&gt;
=== Lustre 1.6 ===&lt;br /&gt;
 * &#039;&#039;&#039;Lustre Manual - HTML &#039;&#039;&#039;[http://wiki.lustre.org/images/7/78/LustreManual1_6.html Lustre 1.6 manual V1.1]&lt;br /&gt;
 * &#039;&#039;&#039;Lustre Manual - PDF&#039;&#039;&#039;&lt;br /&gt;
  . &#039;&#039;&#039;&#039;&#039;&#039;[http://wiki.lustre.org/images/7/78/LustreManual1_6.pdf Lustre 1.6 manual V1.1(A4)]&lt;br /&gt;
  . &#039;&#039;&#039;&#039;&#039;&#039;[http://wiki.lustre.org/images/7/78/LustreManual-letter1_6.pdf Lustre 1.6 manual V1.1(Letter)]&lt;br /&gt;
 * &#039;&#039;&#039;Lustre Manual Changelog &#039;&#039;&#039;[http://wiki.lustre.org/images/7/78/manual-changelog1_6.html Lustre Manual-Change log]&lt;br /&gt;
 * &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Mount_Conf MountConf wiki]&#039;&#039;&#039; - A quick reference for those familiar with older versions of Lustre&lt;br /&gt;
&lt;br /&gt;
=== Lustre 1.4.8 ===&lt;br /&gt;
 * &#039;&#039;&#039;Lustre Manual - HTML &#039;&#039;&#039;[https://mail.clusterfs.com/wikis/attachments/LustreManual.html Lustre 1.4.8 manual V1.37]&lt;br /&gt;
 * &#039;&#039;&#039;Lustre Manual - PDF&#039;&#039;&#039;&lt;br /&gt;
  . &#039;&#039;&#039;&#039;&#039;&#039;[https://mail.clusterfs.com/wikis/attachments/LustreManual37.pdf Lustre 1.4.8 manual V1.37(A4)]&lt;br /&gt;
 * &#039;&#039;&#039;Lustre Manual Changelog &#039;&#039;&#039;[https://mail.clusterfs.com/wikis/attachments/manual-changelog.html Lustre Manual-Change log]&lt;br /&gt;
&lt;br /&gt;
== Interim Lustre 1.8 Documentation ==&lt;br /&gt;
 * &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Kerb_Lustre KerbLustre]&#039;&#039;&#039; - The 1.8 interim Lustre documentation (Kerberos....)&lt;br /&gt;
&lt;br /&gt;
== Older Documentation ==&lt;br /&gt;
This documentation will be incorporated into the manual. Until that is done you may find useful bits and pieces here.&lt;br /&gt;
&lt;br /&gt;
 * &#039;&#039;&#039;Frequently Asked Questions&#039;&#039;&#039;&lt;br /&gt;
  . [http://www.clusterfs.com/faq.html Lustre Faq]&lt;br /&gt;
 * &#039;&#039;&#039;Knowledge Base&#039;&#039;&#039;&lt;br /&gt;
  . [http://bugzilla.lustre.org/showdependencytree.cgi?id=2374 Lustre Knowledge Base] - questions and answers&lt;br /&gt;
 * &#039;&#039;&#039;Configuration&#039;&#039;&#039;&lt;br /&gt;
  * &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Lustre_Howto LustreHowto]&#039;&#039;&#039; - A guide to getting Lustre cluster started.&lt;br /&gt;
  * &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Lustre_LDAP LustreLDAP]&#039;&#039;&#039; - A guide for using LDAP with Lustre.&lt;br /&gt;
  * &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Lustre_Wizard LustreWizard]&#039;&#039;&#039; - The &#039;&#039;Lustre wizard&#039;&#039; or &#039;&#039;lwizard&#039;&#039; is a utility that helps with creation of configuration file for a cluster through asking some simple questions.&lt;br /&gt;
  * &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Lustre_Failover LustreFailover]&#039;&#039;&#039; - Managing failover&lt;br /&gt;
  * &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Filesystem_Backup FilesystemBackup]&#039;&#039;&#039; - How to back up a Lustre filesystem&lt;br /&gt;
  * &#039;&#039;&#039;[http://wiki.lustre.org/index.php?title=Fsck_Suppor FsckSupport]&#039;&#039;&#039; - The lustre fsck tool and Lustre-patched e2fsck (extents, large inode/EA support)&lt;br /&gt;
  * &#039;&#039;&#039;Filesystem Tuning&#039;&#039;&#039;&lt;br /&gt;
   * [https://mail.clusterfs.com/wikis/attachments/LustreManual.html#Chapter_III-2._LustreProc LustreProc] - A guide on the &#039;&#039;&#039;proc&#039;&#039;&#039; tunables parameters for Lustre and their usage. It describes several of the &#039;&#039;proc&#039;&#039; tunables including those that effect the client&#039;s RPC behaviour and prepare for a substantial reorganization of proc entries.&lt;br /&gt;
   * &#039;&#039;&#039;[https://mail.clusterfs.com/wikis/attachments/LustreManual.html#3.2_DDN_Tuning LustreDdnTuning]&#039;&#039;&#039; - A brief guide on tuning DDN S2A 8500 (and maybe 9500) storage optimally for Lustre&lt;/div&gt;</summary>
		<author><name>Yep</name></author>
	</entry>
	<entry>
		<id>http://wiki.old.lustre.org/index.php?title=File:LUG-Requirements-060420-final.pdf&amp;diff=1709</id>
		<title>File:LUG-Requirements-060420-final.pdf</title>
		<link rel="alternate" type="text/html" href="http://wiki.old.lustre.org/index.php?title=File:LUG-Requirements-060420-final.pdf&amp;diff=1709"/>
		<updated>2007-04-30T07:25:00Z</updated>

		<summary type="html">&lt;p&gt;Yep: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Yep</name></author>
	</entry>
	<entry>
		<id>http://wiki.old.lustre.org/index.php?title=RAID5_Patches&amp;diff=1708</id>
		<title>RAID5 Patches</title>
		<link rel="alternate" type="text/html" href="http://wiki.old.lustre.org/index.php?title=RAID5_Patches&amp;diff=1708"/>
		<updated>2007-04-30T07:11:12Z</updated>

		<summary type="html">&lt;p&gt;Yep: /* Structures */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Notes about RAID5 internals =&lt;br /&gt;
&lt;br /&gt;
== Structures ==&lt;br /&gt;
&lt;br /&gt;
In Linux RAID5 handles all incoming requests by small units called &#039;&#039;&#039;stripes&#039;&#039;&#039;.&lt;br /&gt;
Stripe is a set of &#039;&#039;&#039;blocks&#039;&#039;&#039; taken from all disks at the same position.&lt;br /&gt;
Block is defined as unit of PAGE_SIZE bytes. &lt;br /&gt;
&lt;br /&gt;
For example, you have 3 disks and specified 8K chunksize. Then RAID5 will  be looking internally as the following:&lt;br /&gt;
{|border=1 cellspacing=1&lt;br /&gt;
|-&lt;br /&gt;
|       || S0  || S8  || S32 || S40 ||&lt;br /&gt;
|-&lt;br /&gt;
| Disk1 || #0  || #8  || #32 || #40 ||&lt;br /&gt;
|-&lt;br /&gt;
| Disk2 || #16 || #24 || #48 || #56 ||&lt;br /&gt;
|-&lt;br /&gt;
| Disk3 || P0  || P8  || P32 || P40 ||&lt;br /&gt;
|}&lt;br /&gt;
where:&lt;br /&gt;
  * Sn -- number of internal stripe&lt;br /&gt;
  * #n -- is an offset in sectors (512bytes)&lt;br /&gt;
  * Pn -- parity for other blocks in the stripe (actually it floats among disks)&lt;br /&gt;
&lt;br /&gt;
As you can see, 8K chunksize means 2 contig. blocks.&lt;br /&gt;
&lt;br /&gt;
== Logic ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;make_request()&#039;&#039; goes through incoming request, breaking it into &#039;&#039;&#039;blocks&#039;&#039;&#039;&lt;br /&gt;
(PAGE_SIZE) and handling them separately. given bio with bi_sector = 0&lt;br /&gt;
bi_size = 24K and array described above, &#039;&#039;make_request()&#039;&#039; would handle #0,&lt;br /&gt;
#8 and #16.&lt;br /&gt;
&lt;br /&gt;
For every block, &#039;&#039;add_stripe_bio()&#039;&#039; and &#039;&#039;handle_stripe()&#039;&#039; are called.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;add_stripe_bio()&#039;&#039; intention is to add bio to given stripe, later in&lt;br /&gt;
&#039;&#039;handle_stripe()&#039;&#039; we&#039;ll be able to use bio and its data for serving requests.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;handle_stripe()&#039;&#039; is a core of raid5, we&#039;ll discsuss it in the next part.&lt;br /&gt;
&lt;br /&gt;
== handle_stripe() ==&lt;br /&gt;
&lt;br /&gt;
the routine works with a stripe. it checks what should be done, learns current&lt;br /&gt;
state of a stripe in the internal cache, makes decision what I/O is needed to&lt;br /&gt;
satisfy users requests and does recovery.&lt;br /&gt;
&lt;br /&gt;
say, user wants to write block #0 (8 sectors starting from sector 0). raid5&#039;s&lt;br /&gt;
responsibility is to store new data and update parity P0. there are few &lt;br /&gt;
possibilities here:&lt;br /&gt;
 1. delay serving till data for block #16 is ready -- probably user will want to write #16 very soon?&lt;br /&gt;
 2. read #16, make a new parity P0; write #0 and P0&lt;br /&gt;
 3. read P0, rollback old #0 from P0 (so, it will look like we did parity with #0) and re-compute parity with new #0&lt;br /&gt;
&lt;br /&gt;
1st way looks the better because it doesn&#039;t require very expensive read, but&lt;br /&gt;
the problem is that user may need to write only #0 and not #16 in near future.&lt;br /&gt;
also, the queue can get unplugged meaning that user wants all requests to&lt;br /&gt;
complete (unfortunately, in current block layer there is no way to specify&lt;br /&gt;
which exact request user is interested in, so any completion interest means&lt;br /&gt;
immediate serving of the whole queue).&lt;br /&gt;
&lt;br /&gt;
== Problems ==&lt;br /&gt;
&lt;br /&gt;
Short list of the problem in raid5 we met in Thumper project:&lt;br /&gt;
&lt;br /&gt;
 * order of handling isn&#039;t good for large requests&lt;br /&gt;
   As &#039;&#039;handle_stripe()&#039;&#039; goes in logical block order, it&lt;br /&gt;
   handles S0, then S8, then again S0 and S8. After the first touch&lt;br /&gt;
   S0 is left with block #0 uptodate, while #16 and P0 are not. Thus&lt;br /&gt;
   if the stripe is forced for completion, we&#039;d need to read block&lt;br /&gt;
   #16 or P0 to get full uptodate stripe. Such reads hurt throughput&lt;br /&gt;
   almost to death. If just a single process writes, then things are&lt;br /&gt;
   OK, because nobody unplugs the queue and there is no requests to&lt;br /&gt;
   force completion of pending request. But the more writers, the&lt;br /&gt;
   often queue unplug happens and the often pending requests are forced&lt;br /&gt;
   for completion. Take into account that in reallity we use large&lt;br /&gt;
   chuck size (128K, 256K and even larger), hence tons of non-uptodate&lt;br /&gt;
   stripes in the cache and tons of reads in the end.&lt;br /&gt;
&lt;br /&gt;
 * memcpy() is top consumer&lt;br /&gt;
   all requests go via internal cache. on dual-core 2way opteron&lt;br /&gt;
   it takes up to 30-33% of CPU doing 1GB/s write&lt;br /&gt;
&lt;br /&gt;
 * small requests&lt;br /&gt;
   to fill I/O pipes and reach good throughput we need quite large&lt;br /&gt;
   I/O requests. Lustre does this using bio subsystem on 2.6. but&lt;br /&gt;
   as it was mentioned, raid5 handles all blocks separately and&lt;br /&gt;
   issues for every block separate I/O (bio). this is solved partial&lt;br /&gt;
   by I/O scheduler that merges small requests into bigger ones, but&lt;br /&gt;
   due to nature of block subsystem, any process that wants I/O to&lt;br /&gt;
   get completed, &#039;&#039;unplug&#039;&#039; queue and we can get many small requests&lt;br /&gt;
   in the pipe.&lt;br /&gt;
&lt;br /&gt;
We developed patches that address described problems. You can find&lt;br /&gt;
them in ftp://ftp.clusterfs.com/pub/people/alex/raid5&lt;/div&gt;</summary>
		<author><name>Yep</name></author>
	</entry>
</feed>