xfs/
lib.rs

1#![recursion_limit="100"]
2#[macro_use]
3extern crate nom;
4
5use std::error;
6use std::fmt;
7use std::fs::File;
8use std::io;
9use std::io::prelude::*;
10use std::str::FromStr;
11
12use self::nom::{le_u8, is_digit, space, newline};
13
14#[cfg(test)]
15mod tests {
16    use nom;
17
18    #[test]
19    fn it_parses_a_u32() {
20        let input = b"12345";
21        let result = super::take_u32(input);
22        match result {
23            nom::IResult::Done(_, f) => assert_eq!(f, 12345u32),
24            _ => unreachable!(),
25        }
26    }
27
28    #[test]
29    fn it_parses_a_u32_with_whitespace() {
30        let input = b"12345 ";
31        let result = super::take_u32(input);
32        match result {
33            nom::IResult::Done(_, f) => assert_eq!(f, 12345u32),
34            _ => unreachable!(),
35        }
36
37    }
38
39    #[test]
40    fn it_parses_extent_allocation() {
41        let example_output = b"extent_alloc 4260849 125170297 4618726 131131897";
42        match super::extent_alloc(example_output) {
43            nom::IResult::Done(_, result) => {
44                assert_eq!(result.allocated_extents, 4260849);
45                assert_eq!(result.freed_blocks, 131131897);
46            }
47            _ => unreachable!(),
48        }
49    }
50
51    #[test]
52    fn it_parses_allocation_btree() {
53        let example_output = b"abt 29491162 337391304 11257328 11133039";
54        match super::abt(example_output) {
55            nom::IResult::Done(_, result) => {
56                assert_eq!(result.inserts, 11257328);
57            }
58            _ => unreachable!(),
59        }
60    }
61
62    #[test]
63    fn it_parses_block_mapping() {
64        let example_output = b"blk_map 381213360 115456141 10903633 69612322 7448401 507596777 0";
65        match super::blk_map(example_output) {
66            nom::IResult::Done(_, result) => {
67                assert_eq!(result.list_delete, 7448401);
68            }
69            _ => unreachable!(),
70        }
71    }
72
73    #[test]
74    fn it_parses_block_map_btree() {
75        let example_output = b"bmbt 771328 6236258 602114 86646";
76        match super::bmbt(example_output) {
77            nom::IResult::Done(_, result) => {
78                assert_eq!(result.deletes, 86646);
79            }
80            _ => unreachable!(),
81        }
82    }
83
84    #[test]
85    fn it_parses_directory_operations() {
86        let example_output = b"dir 21253907 6921870 6969079 779205554";
87        match super::dir(example_output) {
88            nom::IResult::Done(_, result) => {
89                assert_eq!(result.lookups, 21253907);
90            }
91            _ => unreachable!(),
92        }
93    }
94
95    #[test]
96    fn it_parses_transactions() {
97        let example_output = b"trans 126946406 38184616 6342392";
98        match super::trans(example_output) {
99            nom::IResult::Done(_, result) => {
100                assert_eq!(result.waited, 126946406);
101            }
102            _ => unreachable!(),
103        }
104    }
105
106    #[test]
107    fn it_parses_inode_operations() {
108        let example_output = b"ig 17754368 2019571 102 15734797 0 15672217 3962470";
109        match super::ig(example_output) {
110            nom::IResult::Done(_, result) => {
111                assert_eq!(result.cache_lookups, 17754368);
112            }
113            _ => unreachable!(),
114        }
115    }
116
117    #[test]
118    fn it_parses_log_operations() {
119        let example_output = b"log 129491915 3992515264 458018 153771989 127040250";
120        match super::log(example_output) {
121            nom::IResult::Done(_, result) => {
122                assert_eq!(result.log_writes, 129491915);
123            }
124            _ => unreachable!(),
125        }
126    }
127
128    #[test]
129    fn it_parses_tail_pushing_stats() {
130        let example_output = b"push_ail 171473415 0 6896837 3324292 8069877 65884 1289485 0 22535 7337";
131        match super::push_ail(example_output) {
132            nom::IResult::Done(_, result) => {
133                assert_eq!(result.logspace, 171473415);
134            }
135            _ => unreachable!(),
136        }
137    }
138
139    #[test]
140    fn it_parses_io_map_write_convert() {
141        let example_output = b"xstrat 4140059 0";
142        match super::xstrat(example_output) {
143            nom::IResult::Done(_, result) => {
144                assert_eq!(result.quick, 4140059);
145            }
146            _ => unreachable!(),
147        }
148    }
149
150    #[test]
151    fn it_parses_read_write_stats() {
152        let example_output = b"rw 1595677950 1046884251";
153        match super::rw(example_output) {
154            nom::IResult::Done(_, result) => {
155                assert_eq!(result.write, 1595677950);
156            }
157            _ => unreachable!(),
158        }
159    }
160
161    #[test]
162    fn it_parses_attribute_operations() {
163        let example_output = b"attr 194724197 0 7 0";
164        match super::attr(example_output) {
165            nom::IResult::Done(_, result) => {
166                assert_eq!(result.get, 194724197);
167            }
168            _ => unreachable!(),
169        }
170    }
171
172    #[test]
173    fn it_parses_inode_clustering() {
174        let example_output = b"icluster 20772185 2488203 13909520";
175        match super::icluster(example_output) {
176            nom::IResult::Done(_, result) => {
177                assert_eq!(result.count, 20772185);
178            }
179            _ => unreachable!(),
180        }
181    }
182
183    #[test]
184    fn it_parses_vnode_statistics() {
185        let example_output = b"vnodes 62578 15959666 0 0 15897088 15897088 15897088 0";
186        match super::vnodes(example_output) {
187            nom::IResult::Done(_, result) => {
188                assert_eq!(result.active, 62578);
189            }
190            _ => unreachable!(),
191        }
192    }
193
194    #[test]
195    fn it_parses_buf_statistics() {
196        let example_output = b"buf 2090581631 1972536890 118044776 225145 9486625 0 0 2000152616 809762";
197        match super::buf(example_output) {
198            nom::IResult::Done(_, result) => {
199                assert_eq!(result.get, 2090581631);
200            }
201            _ => unreachable!(),
202        }
203    }
204
205    #[test]
206    fn it_parses_extended_precision_counters() {
207        let example_output = b"xpc 6908312903680 67735504884757 19760115252482";
208        match super::xpc(example_output) {
209            nom::IResult::Done(_, result) => {
210                assert_eq!(result.xstrat_bytes, 6908312903680);
211            }
212            _ => unreachable!(),
213        }
214    }
215
216     #[test]
217    fn it_parses_debug() {
218        let example_output = b"debug 0";
219        match super::debug(example_output) {
220            nom::IResult::Done(_, result) => {
221                assert_eq!(result, false);
222            }
223            _ => unreachable!(),
224        }
225    }
226
227    #[test]
228    fn it_parses_example() {
229        let example_output = b"extent_alloc 4260849 125170297 4618726 131131897
230abt 29491162 337391304 11257328 11133039
231blk_map 381213360 115456141 10903633 69612322 7448401 507596777 0
232bmbt 771328 6236258 602114 86646
233dir 21253907 6921870 6969079 779205554
234trans 126946406 38184616 6342392
235ig 17754368 2019571 102 15734797 0 15672217 3962470
236log 129491915 3992515264 458018 153771989 127040250
237push_ail 171473415 0 6896837 3324292 8069877 65884 1289485 0 22535 7337
238xstrat 4140059 0
239rw 1595677950 1046884251
240attr 194724197 0 7 0
241icluster 20772185 2488203 13909520
242vnodes 62578 15959666 0 0 15897088 15897088 15897088 0
243buf 2090581631 1972536890 118044776 225145 9486625 0 0 2000152616 809762
244xpc 6908312903680 67735504884757 19760115252482
245debug 0";
246        let result = super::parse(example_output).unwrap();
247
248        assert_eq!(result.extent_allocation.freed_extents, 4618726);
249        assert_eq!(result.allocation_btree.lookups, 29491162);
250        assert_eq!(result.block_mapping.unmap, 10903633);
251        assert_eq!(result.block_map_btree.inserts, 602114);
252        assert_eq!(result.directory_operations.get_dents, 779205554);
253        assert_eq!(result.transactions.empty, 6342392);
254        assert_eq!(result.inode_operations.inode_attr_changes, 3962470);
255        assert_eq!(result.log_operations.force_sleep, 127040250);
256        assert_eq!(result.tail_pushing_stats.push_ail_flush, 7337);
257        assert_eq!(result.io_map_write_convert.split, 0);
258        assert_eq!(result.read_write_stats.read, 1046884251);
259        assert_eq!(result.attribute_operations.list, 0);
260        assert_eq!(result.inode_clustering.flushinode, 13909520);
261        assert_eq!(result.vnode_statistics.free, 0);
262        assert_eq!(result.buf_statistics.get_read, 809762);
263        assert_eq!(result.extended_precision_counters.read_bytes, 19760115252482);
264        assert_eq!(result.debug, false);
265    }
266
267    #[test]
268    fn it_parses_newer_version_with_extra_fields() {
269        let example_output = b"extent_alloc 0 0 0 0
270abt 0 0 0 0
271blk_map 0 0 0 0 0 0 0
272bmbt 0 0 0 0
273dir 0 0 0 0
274trans 0 0 0
275ig 0 0 0 0 0 0 0
276log 0 0 0 0 0
277push_ail 0 0 0 0 0 0 0 0 0 0
278xstrat 0 0
279rw 0 0
280attr 0 0 0 0
281icluster 0 0 0
282vnodes 0 0 0 0 0 0 0 0
283buf 0 0 0 0 0 0 0 0 0
284abtb2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
285abtc2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
286bmbt2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
287ibt2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
288fibt2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
289qm 0 0 0 0 0 0 0 0
290xpc 0 0 0
291debug 0
292";
293        let result = super::parse(example_output).unwrap();
294        assert_eq!(result.extent_allocation.freed_extents, 0);
295        assert_eq!(result.allocation_btree.lookups, 0);
296        assert_eq!(result.block_mapping.unmap, 0);
297        assert_eq!(result.block_map_btree.inserts, 0);
298        assert_eq!(result.directory_operations.get_dents, 0);
299        assert_eq!(result.transactions.empty, 0);
300        assert_eq!(result.inode_operations.inode_attr_changes, 0);
301        assert_eq!(result.log_operations.force_sleep, 0);
302        assert_eq!(result.tail_pushing_stats.push_ail_flush, 0);
303        assert_eq!(result.io_map_write_convert.split, 0);
304        assert_eq!(result.read_write_stats.read, 0);
305        assert_eq!(result.attribute_operations.list, 0);
306        assert_eq!(result.inode_clustering.flushinode, 0);
307        assert_eq!(result.vnode_statistics.free, 0);
308        assert_eq!(result.buf_statistics.get_read, 0);
309        assert_eq!(result.extended_precision_counters.read_bytes, 0);
310        assert_eq!(result.debug, false);
311    }
312}
313
314pub struct XfsStat {
315    pub extent_allocation: ExtentAllocation,
316    pub allocation_btree: AllocationBTree,
317    pub block_mapping: BlockMapping,
318    pub block_map_btree: BlockMapBTree,
319    pub directory_operations: DirectoryOperations,
320    pub transactions: Transactions,
321    pub inode_operations: InodeOperations,
322    pub log_operations: LogOperations,
323    pub tail_pushing_stats: TailPushingStats,
324    pub io_map_write_convert: IoMapWriteConvert,
325    pub read_write_stats: ReadWriteStats,
326    pub attribute_operations: AttributeOperations,
327    pub inode_clustering: InodeClustering,
328    pub vnode_statistics: VnodeStatistics,
329    pub buf_statistics: BufStatistics,
330    pub extended_precision_counters: ExtendedPrecisionCounters,
331    pub debug: bool,
332}
333
334pub struct ExtentAllocation {
335    /// Number of file system extents allocated over all XFS filesystems.
336    pub allocated_extents: u32,
337    /// Number of file system blocks allocated over all XFS filesystems.
338    pub allocated_blocks: u32,
339    /// Number of file system extents freed over all XFS filesystems.
340    pub freed_extents: u32,
341    /// Number of file system blocks freed over all XFS filesystems.
342    pub freed_blocks: u32,
343}
344
345pub struct AllocationBTree {
346    /// Number of lookup operations in XFS filesystem allocation btrees.
347    pub lookups: u32,
348    /// Number of compares in XFS filesystem allocation btree lookups.
349    pub compares: u32,
350    /// Number of extent records inserted into XFS filesystem allocation btrees.
351    pub inserts: u32,
352    /// Number of extent records deleted from XFS filesystem allocation btrees.
353    pub deletes: u32,
354}
355
356pub struct BlockMapping {
357    /// Number of block map for read operations performed on XFS files.
358    pub map_read: u32,
359    /// Number of block map for write operations performed on XFS files.
360    pub map_write: u32,
361    /// Number of block unmap (delete) operations performed on XFS files.
362    pub unmap: u32,
363    /// Number of extent list insertion operations for XFS files.
364    pub list_insert: u32,
365    /// Number of extent list deletion operations for XFS files.
366    pub list_delete: u32,
367    /// Number of extent list lookup operations for XFS files.
368    pub list_lookup: u32,
369    /// Number of extent list comparisons in XFS extent list lookups.
370    pub list_compare: u32,
371}
372
373pub struct BlockMapBTree {
374    /// Number of block map btree lookup operations on XFS files.
375    pub lookups: u32,
376    /// Number of block map btree compare operations in XFS block map lookups.
377    pub compares: u32,
378    /// Number of block map btree records inserted for XFS files.
379    pub inserts: u32,
380    /// Number of block map btree records deleted for XFS files.
381    pub deletes: u32,
382}
383
384pub struct DirectoryOperations {
385    /// This is a count of the number of file name directory lookups in XFS
386    /// filesystems. It counts only those lookups which miss in the operating
387    /// system's directory name lookup cache and must search the real directory
388    /// structure for the name in question. The count is incremented once for each
389    /// level of a pathname search that results in a directory lookup.
390    pub lookups: u32,
391    /// This is the number of times a new directory entry was created in XFS filesystems. Each time that a new file, directory, link, symbolic link, or special file is created in the directory hierarchy the count is incremented.
392    pub creates: u32,
393    /// This is the number of times an existing directory entry was removed in XFS filesystems. Each time that a file, directory, link, symbolic link, or special file is removed from the directory hierarchy the count is incremented.
394    pub removes: u32,
395    /// This is the number of times the XFS directory getdents operation was performed. The getdents operation is used by programs to read the contents of directories in a file system independent fashion. This count corresponds exactly to the number of times the getdents(2) system call was successfully used on an XFS directory.
396    pub get_dents: u32,
397}
398
399pub struct Transactions {
400    /// This is the number of meta-data transactions which waited to be committed to the on-disk log before allowing the process performing the transaction to continue. These transactions are slower and more expensive than asynchronous transactions, because they force the in memory log buffers to be forced to disk more often and they wait for the completion of the log buffer writes. Synchronous transactions include file truncations and all directory updates when the file system is mounted with the 'wsync' option.
401    pub waited: u32,
402    /// This is the number of meta-data transactions which did not wait to be committed to the on-disk log before allowing the process performing the transaction to continue. These transactions are faster and more efficient than synchronous transactions, because they commit their data to the in memory log buffers without forcing those buffers to be written to disk. This allows multiple asynchronous transactions to be committed to disk in a single log buffer write. Most transactions used in XFS file systems are asynchronous.
403    pub async: u32,
404    /// This is the number of meta-data transactions which did not actually change anything. These are transactions which were started for some purpose, but in the end it turned out that no change was necessary.
405    pub empty: u32,
406}
407
408pub struct InodeOperations {
409    /// This is the number of times the operating system looked for an XFS inode in the inode cache. Whether the inode was found in the cache or needed to be read in from the disk is not indicated here, but this can be computed from the ig_found and ig_missed counts.
410    pub cache_lookups: u32,
411    /// This is the number of times the operating system looked for an XFS inode in the inode cache and found it. The closer this count is to the ig_attempts count the better the inode cache is performing.
412    pub cache_hits: u32,
413    /// This is the number of times the operating system looked for an XFS inode in the inode cache and saw that it was there but was unable to use the in memory inode because it was being recycled by another process.
414    pub cache_recycle: u32,
415    /// This is the number of times the operating system looked for an XFS inode in the inode cache and the inode was not there. The further this count is from the ig_attempts count the better.
416    pub cache_missed: u32,
417    /// This is the number of times the operating system looked for an XFS inode in the inode cache and found that it was not there but upon attempting to add the inode to the cache found that another process had already inserted it.
418    pub cache_dup: u32,
419    /// This is the number of times the operating system recycled an XFS inode from the inode cache in order to use the memory for that inode for another purpose. Inodes are recycled in order to keep the inode cache from growing without bound. If the reclaim rate is high it may be beneficial to raise the vnode_free_ratio kernel tunable variable to increase the size of the inode cache.
420    pub cache_reclaime: u32,
421    /// This is the number of times the operating system explicitly changed the attributes of an XFS inode. For example, this could be to change the inode's owner, the inode's size, or the inode's timestamps.
422    pub inode_attr_changes: u32,
423}
424
425pub struct LogOperations {
426    /// This variable counts the number of log buffer writes going to the physical log partitions of all XFS filesystems. Log data traffic is proportional to the level of meta-data updating. Log buffer writes get generated when they fill up or external syncs occur.
427    pub log_writes: u32,
428    /// This variable counts (in 512-byte units) the information being written to the physical log partitions of all XFS filesystems. Log data traffic is proportional to the level of meta-data updating. The rate with which log data gets written depends on the size of internal log buffers and disk write speed. Therefore, filesystems with very high meta-data updating may need to stripe the log partition or put the log partition on a separate drive.
429    pub log_blocks: u32,
430    /// This variable keeps track of times when a logged transaction can not get any log buffer space. When this occurs, all of the internal log buffers are busy flushing their data to the physical on-disk log.
431    pub noiclogs: u32,
432    /// The number of times the in-core log is forced to disk. It is equivalent to the number of successful calls to the function xfs_log_force().
433    pub log_forced: u32,
434    /// Value exported from the xs_log_force_sleep field of struct xfsstats.
435    pub force_sleep: u32,
436}
437
438pub struct TailPushingStats {
439    /// Value from the xs_try_logspace field of struct xfsstats.
440    pub logspace: u32,
441    /// Value from the xs_sleep_logspace field of struct xfsstats.
442    pub sleep_logspace: u32,
443    /// The number of times the tail of the AIL is moved forward. It is equivalent to the number of successful calls to the function xfs_trans_push_ail().
444    pub push_ails: u32,
445    /// Value from xs_push_ail_success field of struct xfsstats.
446    pub push_ail_success: u32,
447    /// Value from xs_push_ail_pushbuf field of struct xfsstats.
448    pub push_ail_pushbuf: u32,
449    /// Value from xs_push_ail_pinned field of struct xfsstats.
450    pub push_ail_pinned: u32,
451    /// Value from xs_push_ail_locked field of struct xfsstats.
452    pub push_ail_locked: u32,
453    /// Value from xs_push_ail_flushing field of struct xfsstats.
454    pub push_ail_flushing: u32,
455    /// Value from xs_push_ail_restarts field of struct xfsstats.
456    pub push_ail_restarts: u32,
457    /// Value from xs_push_ail_flush field of struct xfsstats.
458    pub push_ail_flush: u32,
459}
460
461pub struct IoMapWriteConvert {
462    /// This is the number of buffers flushed out by the XFS flushing daemons which are written to contiguous space on disk. The buffers handled by the XFS daemons are delayed allocation buffers, so this count gives an indication of the success of the XFS daemons in allocating contiguous disk space for the data being flushed to disk.
463    pub quick: u32,
464    /// This is the number of buffers flushed out by the XFS flushing daemons which are written to non-contiguous space on disk. The buffers handled by the XFS daemons are delayed allocation buffers, so this count gives an indication of the failure of the XFS daemons in allocating contiguous disk space for the data being flushed to disk. Large values in this counter indicate that the file system has become fragmented.
465    pub split: u32,
466}
467
468pub struct ReadWriteStats {
469    /// This is the number of write(2) system calls made to files in XFS file systems.
470    pub write: u32,
471    /// This is the number of read(2) system calls made to files in XFS file systems.
472    pub read: u32,
473}
474
475pub struct AttributeOperations {
476    /// The number of "get" operations performed on extended file attributes within XFS filesystems. The "get" operation retrieves the value of an extended attribute.
477    pub get: u32,
478    /// The number of "set" operations performed on extended file attributes within XFS filesystems. The "set" operation creates and sets the value of an extended attribute.
479    pub set: u32,
480    /// The number of "remove" operations performed on extended file attributes within XFS filesystems. The "remove" operation deletes an extended attribute.
481    pub remove: u32,
482    /// The number of "list" operations performed on extended file attributes within XFS filesystems. The "list" operation retrieves the set of extended attributes associated with a file.
483    pub list: u32,
484}
485
486pub struct InodeClustering {
487    /// This is the number of calls to xfs_iflush which gets called when an inode is being flushed (such as by bdflush or tail pushing). xfs_iflush searches for other inodes in the same cluster which are dirty and flushable.
488    pub count: u32,
489    /// Value from xs_icluster_flushcnt field of struct xfsstats.
490    pub flushcnt: u32,
491    /// This is the number of times that the inode clustering was not able to flush anything but the one inode it was called with.
492    pub flushinode: u32,
493}
494
495pub struct VnodeStatistics {
496    /// Number of vnodes not on free lists.
497    pub active: u32,
498    /// Number of times vn_alloc called.
499    pub alloc: u32,
500    /// Number of times vn_get called.
501    pub get: u32,
502    /// Number of times vn_hold called.
503    pub hold: u32,
504    /// Number of times vn_rele called.
505    pub rele: u32,
506    /// Number of times vn_reclaim called.
507    pub reclaim: u32,
508    /// Number of times vn_remove called.
509    pub remove: u32,
510    /// Number of times vn_free called.
511    pub free: u32,
512}
513
514pub struct BufStatistics {
515    pub get: u32,
516    pub create: u32,
517    pub get_locked: u32,
518    pub get_locked_waited: u32,
519    pub busy_locked: u32,
520    pub miss_locked: u32,
521    pub page_retries: u32,
522    pub page_found: u32,
523    pub get_read: u32,
524}
525
526pub struct ExtendedPrecisionCounters {
527    /// This is a count of bytes of file data flushed out by the XFS flushing daemons.
528    pub xstrat_bytes: u64,
529    /// This is a count of bytes written via write(2) system calls to files in XFS file systems. It can be used in conjunction with the write_calls count to calculate the average size of the write operations to files in XFS file systems.
530    pub write_bytes: u64,
531    /// This is a count of bytes read via read(2) system calls to files in XFS file systems. It can be used in conjunction with the read_calls count to calculate the average size of the read operations to files in XFS file systems.
532    pub read_bytes: u64,
533}
534
535#[derive(Debug)]
536pub enum XfsError {
537    /// We encounter an error reading from /proc/fs/xfs/stat
538    Io(io::Error),
539    /// We don't have enough information for a complete parse
540    Incomplete,
541    /// We encounter an error with the data wer're parsing
542    Parse,
543}
544
545impl fmt::Display for XfsError {
546    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
547        match *self {
548            // Both underlying errors already impl `Display`, so we defer to
549            // their implementations.
550            XfsError::Io(ref err) => write!(f, "IO error: {}", err),
551            XfsError::Incomplete => write!(f, "Not enough data for XFS parse"),
552            XfsError::Parse => write!(f, "Parse error"),
553        }
554    }
555}
556
557impl error::Error for XfsError {
558    fn description(&self) -> &str {
559        // Both underlying errors already impl `Error`, so we defer to their
560        // implementations.
561        match *self {
562            XfsError::Io(ref err) => err.description(),
563            XfsError::Incomplete => "There is not enough data for parsing",
564            XfsError::Parse => "There was an error parsing",
565        }
566    }
567
568    fn cause(&self) -> Option<&error::Error> {
569        match *self {
570            // N.B. Both of these implicitly cast `err` from their concrete
571            // types (either `&io::Error` or `&num::ParseIntError`)
572            // to a trait object `&Error`. This works because both error types
573            // implement `Error`.
574            XfsError::Io(ref err) => Some(err),
575            XfsError::Incomplete => None,
576            XfsError::Parse => None,
577        }
578    }
579}
580
581impl From<io::Error> for XfsError {
582    fn from(err: io::Error) -> XfsError {
583        XfsError::Io(err)
584    }
585}
586
587pub fn parse(input: &[u8]) -> Result<XfsStat, XfsError> {
588    match xfs_stat(input) {
589        nom::IResult::Done(_, stat) => Ok(stat),
590        nom::IResult::Error(_) => {
591            Err(XfsError::Parse)
592        },
593        nom::IResult::Incomplete(_) => {
594            Err(XfsError::Incomplete)
595        },
596        // _ => None,
597    }
598}
599
600pub fn read() -> Result<String, XfsError> {
601    let mut f = try!(File::open("/proc/fs/xfs/stat"));
602    let mut s = String::new();
603    try!(f.read_to_string(&mut s));
604    Ok(s)
605}
606
607pub fn get() -> Result<XfsStat, XfsError> {
608    let contents = try!(read());
609    parse((&contents[..]).as_bytes())
610}
611
612named!(xfs_stat <XfsStat>,
613  chain!(
614    extent_alloc: extent_alloc ~
615    newline ~
616    abt: abt ~
617    newline ~
618    blk_map: blk_map ~
619    newline ~
620    block_map_btree: bmbt ~
621    newline ~
622    directory_operations: dir ~
623    newline ~
624    transactions: trans ~
625    newline ~
626    inode_operations: ig ~
627    newline ~
628    log_operations: log ~
629    newline ~
630    tail_pushing_stats: push_ail ~
631    newline ~
632    io_map_write_convert: xstrat ~
633    newline ~
634    read_write_stats: rw ~
635    newline ~
636    attribute_operations: attr ~
637    newline ~
638    inode_clustering: icluster ~
639    newline ~
640    vnode_statistics: vnodes ~
641    newline ~
642    buf_statistics: buf ~
643    newline ~
644    extended_precision_counters: xpc ~
645    newline ~
646    dbg: debug,
647    || {
648      XfsStat {
649        extent_allocation: extent_alloc,
650        allocation_btree: abt,
651        block_mapping: blk_map,
652        block_map_btree: block_map_btree,
653        directory_operations: directory_operations,
654        transactions: transactions,
655        inode_operations: inode_operations,
656        log_operations:log_operations,
657        tail_pushing_stats: tail_pushing_stats,
658        io_map_write_convert: io_map_write_convert,
659        read_write_stats: read_write_stats,
660        attribute_operations: attribute_operations,
661        inode_clustering: inode_clustering,
662        vnode_statistics: vnode_statistics,
663        buf_statistics: buf_statistics,
664        extended_precision_counters: extended_precision_counters,
665        debug: dbg,
666      }
667    }
668  )
669);
670
671named!(debug <bool>,
672    chain!(
673        tag!("debug") ~
674        space ~
675        dbg: le_u8,
676        || {
677            if dbg == 1 {
678                true
679            } else {
680                false
681            }
682        }
683    )
684);
685
686named!(take_u32 <u32>,
687  chain!(
688    uint_slice: take_while!(is_digit) ~
689    opt!(space),
690    || {
691      let int_str = String::from_utf8_lossy(uint_slice);
692      u32::from_str(&int_str[..]).unwrap()
693    }
694  )
695);
696
697named!(take_u64 <u64>,
698  chain!(
699    uint_slice: take_while!(is_digit) ~
700    opt!(space),
701    || {
702      let int_str = String::from_utf8_lossy(uint_slice);
703      u64::from_str(&int_str[..]).unwrap()
704    }
705  )
706);
707
708
709named!(extent_alloc <ExtentAllocation>,
710  chain!(
711    tag!("extent_alloc") ~
712    space ~
713    allocx: take_u32 ~
714    allocb: take_u32 ~
715    freex: take_u32 ~
716    freeb: take_u32,
717    || {
718      ExtentAllocation {
719        allocated_extents: allocx,
720        allocated_blocks: allocb,
721        freed_extents: freex,
722        freed_blocks: freeb,
723      }
724    }
725  )
726);
727
728named!(abt <AllocationBTree>,
729  chain!(
730    tag!("abt") ~
731    space ~
732    lookups: take_u32 ~
733    compares: take_u32 ~
734    inserts: take_u32 ~
735    deletes: take_u32,
736    || {
737      AllocationBTree {
738        lookups: lookups,
739        compares: compares,
740        inserts: inserts,
741        deletes: deletes,
742      }
743    }
744  )
745);
746
747named!(blk_map <BlockMapping>,
748  chain!(
749    tag!("blk_map") ~
750    space ~
751    map_read: take_u32 ~
752    map_write: take_u32 ~
753    unmap: take_u32 ~
754    list_insert: take_u32 ~
755    list_delete: take_u32 ~
756    list_lookup: take_u32 ~
757    list_compare: take_u32,
758    ||{
759      BlockMapping {
760        map_read: map_read,
761        map_write: map_write,
762        unmap: unmap,
763        list_insert: list_insert,
764        list_delete: list_delete,
765        list_lookup: list_lookup,
766        list_compare: list_compare,
767      }
768    }
769  )
770);
771
772named!(bmbt <BlockMapBTree>,
773  chain!(
774    tag!("bmbt") ~
775    space ~
776    lookup: take_u32 ~
777    compare: take_u32 ~
778    insrec: take_u32 ~
779    delrec: take_u32,
780    || {
781      BlockMapBTree {
782        lookups: lookup,
783        compares: compare,
784        inserts: insrec,
785        deletes: delrec,
786      }
787    }
788  )
789);
790
791named!(dir <DirectoryOperations>,
792    chain!(
793        tag!("dir") ~
794        space ~
795        lookups: take_u32 ~
796        creates: take_u32 ~
797        removes: take_u32 ~
798        get_dents: take_u32,
799        || {
800            DirectoryOperations {
801                lookups: lookups,
802                creates: creates,
803                removes: removes,
804                get_dents: get_dents,
805            }
806        }
807    )
808);
809
810named!(trans <Transactions>,
811  chain!(
812    tag!("trans") ~
813    space ~
814    waited: take_u32 ~
815    async: take_u32 ~
816    empty: take_u32,
817    ||{
818      Transactions {
819        waited: waited,
820        async: async,
821        empty: empty,
822      }
823    }
824  )
825);
826
827named!(ig <InodeOperations>,
828  chain!(
829    tag!("ig") ~
830    space ~
831    cache_lookups: take_u32 ~
832    cache_hits: take_u32 ~
833    cache_recycle: take_u32 ~
834    cache_missed: take_u32 ~
835    cache_dup: take_u32 ~
836    cache_reclaime: take_u32 ~
837    inode_attr_changes: take_u32,
838    || {
839      InodeOperations {
840        cache_lookups: cache_lookups,
841        cache_hits: cache_hits,
842        cache_recycle: cache_recycle,
843        cache_missed: cache_missed,
844        cache_dup: cache_dup,
845        cache_reclaime: cache_reclaime,
846        inode_attr_changes: inode_attr_changes,
847      }
848    }
849  )
850);
851
852named!(log <LogOperations>,
853  chain!(
854    tag!("log") ~
855    space ~
856    log_writes: take_u32 ~
857    log_blocks: take_u32 ~
858    noiclogs: take_u32 ~
859    log_forced: take_u32 ~
860    force_sleep: take_u32,
861    || {
862      LogOperations {
863          log_writes: log_writes,
864          log_blocks: log_blocks,
865          noiclogs: noiclogs,
866          log_forced: log_forced,
867          force_sleep: force_sleep,
868      }
869    }
870  )
871);
872
873named!(push_ail <TailPushingStats>,
874    chain!(
875        tag!("push_ail") ~
876        space ~
877        logspace: take_u32 ~
878        sleep_logspace: take_u32 ~
879        push_ails: take_u32 ~
880        push_ail_success: take_u32 ~
881        push_ail_pushbuf: take_u32 ~
882        push_ail_pinned: take_u32 ~
883        push_ail_locked: take_u32 ~
884        push_ail_flushing: take_u32 ~
885        push_ail_restarts: take_u32 ~
886        push_ail_flush: take_u32,
887        || {
888            TailPushingStats {
889                logspace: logspace,
890                sleep_logspace: sleep_logspace,
891                push_ails: push_ails,
892                push_ail_success: push_ail_success,
893                push_ail_pushbuf: push_ail_pushbuf,
894                push_ail_pinned: push_ail_pinned,
895                push_ail_locked: push_ail_locked,
896                push_ail_flushing: push_ail_flushing,
897                push_ail_restarts: push_ail_restarts,
898                push_ail_flush: push_ail_flush,
899            }
900        }
901    )
902);
903
904named!(xstrat <IoMapWriteConvert>,
905    chain!(
906        tag!("xstrat") ~
907        space ~
908        quick: take_u32 ~
909        split: take_u32,
910        || {
911            IoMapWriteConvert {
912                quick: quick,
913                split: split,
914            }
915        }
916    )
917);
918
919named!(rw <ReadWriteStats>,
920    chain!(
921        tag!("rw") ~
922        space ~
923        write: take_u32 ~
924        read: take_u32,
925        || {
926            ReadWriteStats {
927                write: write,
928                read: read,
929            }
930        }
931    )
932);
933
934named!(attr <AttributeOperations>,
935    chain!(
936        tag!("attr") ~
937        space  ~
938        get: take_u32 ~
939        set: take_u32 ~
940        remove: take_u32 ~
941        list: take_u32,
942        || {
943            AttributeOperations {
944                get: get,
945                set: set,
946                remove: remove,
947                list: list,
948            }
949        }
950    )
951);
952
953named!(icluster <InodeClustering>,
954    chain!(
955        tag!("icluster") ~
956        space ~
957        count: take_u32 ~
958        flushcnt: take_u32 ~
959        flushinode: take_u32,
960        || {
961            InodeClustering {
962                count: count,
963                flushcnt: flushcnt,
964                flushinode: flushinode,
965            }
966        }
967    )
968);
969
970named!(vnodes <VnodeStatistics>,
971    chain!(
972        tag!("vnodes") ~
973        space ~
974        active: take_u32 ~
975        alloc: take_u32 ~
976        get: take_u32 ~
977        hold: take_u32 ~
978        rele: take_u32 ~
979        reclaim: take_u32 ~
980        remove: take_u32 ~
981        free: take_u32,
982        || {
983            VnodeStatistics {
984                active: active,
985                alloc: alloc,
986                get: get,
987                hold: hold,
988                rele: rele,
989                reclaim: reclaim,
990                remove: remove,
991                free: free,
992            }
993
994        }
995    )
996);
997
998named!(buf <BufStatistics>,
999    chain!(
1000        tag!("buf") ~
1001        space ~
1002        get: take_u32 ~
1003        create: take_u32 ~
1004        get_locked: take_u32 ~
1005        get_locked_waited: take_u32 ~
1006        busy_locked: take_u32 ~
1007        miss_locked: take_u32 ~
1008        page_retries: take_u32 ~
1009        page_found: take_u32 ~
1010        get_read: take_u32,
1011        || {
1012            BufStatistics {
1013                get: get,
1014                create: create,
1015                get_locked: get_locked,
1016                get_locked_waited: get_locked_waited,
1017                busy_locked: busy_locked,
1018                miss_locked: miss_locked,
1019                page_retries: page_retries,
1020                page_found: page_found,
1021                get_read: get_read,
1022            }
1023
1024        }
1025    )
1026);
1027
1028named!(xpc <ExtendedPrecisionCounters>,
1029    chain!(
1030        take_until!("xpc") ~
1031        tag!("xpc") ~
1032        space ~
1033        xstrat_bytes: take_u64 ~
1034        write_bytes: take_u64 ~
1035        read_bytes: take_u64,
1036        ||{
1037            ExtendedPrecisionCounters {
1038                xstrat_bytes: xstrat_bytes,
1039                write_bytes: write_bytes,
1040                read_bytes: read_bytes,
1041            }
1042        }
1043    )
1044);