1 use std::{
2     io::{Error, Result},
3     os::raw::c_void
4 };
5 
6 #[allow(non_camel_case_types)]
7 #[allow(dead_code)]
8 mod ffi;
9 
bintime_to_ns(bintime: &ffi::bintime) -> u6410 fn bintime_to_ns(bintime: &ffi::bintime) -> u64 {
11     (bintime.sec as u64).wrapping_mul(1_000_000_000)
12     .wrapping_add(bintime.frac / (1 << 30) / ((1 << 34) / 1_000_000_000))
13 }
14 
15 #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
16 pub struct PerRW {
17     pub read: u64,
18     pub write: u64,
19 }
20 
21 #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
22 pub struct PerRWC {
23     pub read: u64,
24     pub write: u64,
25     pub commit: u64,
26 }
27 
28 /// Counts of every RPC processed
29 #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
30 pub struct PerRPC {
31     pub access: u64,
32     pub backchannelctrl: u64,
33     pub bindconntosess: u64,
34     pub close: u64,
35     pub commit: u64,
36     pub create: u64,
37     pub createsess: u64,
38     pub delegpurge: u64,
39     pub delegreturn: u64,
40     pub destroyclid: u64,
41     pub destroysess: u64,
42     pub exchangeid: u64,
43     pub freestateid: u64,
44     pub fsinfo: u64,
45     pub fsstat: u64,
46     pub getattr: u64,
47     pub getdevinfo: u64,
48     pub getdevlist: u64,
49     pub getdirdeleg: u64,
50     pub getfh: u64,
51     pub layoutcommit: u64,
52     pub layoutget: u64,
53     pub layoutreturn: u64,
54     pub link: u64,
55     pub lock: u64,
56     pub lockt: u64,
57     pub locku: u64,
58     pub lookup: u64,
59     pub lookupp: u64,
60     pub mkdir: u64,
61     pub mknod: u64,
62     pub nverify: u64,
63     pub open: u64,
64     pub openattr: u64,
65     pub openconfirm: u64,
66     pub opendgrd: u64,
67     pub pathconf: u64,
68     pub putfh: u64,
69     pub putpubfh: u64,
70     pub putrootfh: u64,
71     pub read: u64,
72     pub readdir: u64,
73     pub readdirplus: u64,
74     pub readlink: u64,
75     pub reclaimcompl: u64,
76     pub rellckown: u64,
77     pub remove: u64,
78     pub rename: u64,
79     pub renew: u64,
80     pub restorefh: u64,
81     pub rmdir: u64,
82     pub savefh: u64,
83     pub secinfo: u64,
84     pub secinfononame: u64,
85     pub sequence: u64,
86     pub setattr: u64,
87     pub setclid: u64,
88     pub setclidcf: u64,
89     pub setssv: u64,
90     pub symlink: u64,
91     pub teststateid: u64,
92     pub v3create: u64,
93     pub verify: u64,
94     pub wantdeleg: u64,
95     pub write: u64,
96 }
97 
98 /// Server cache statistics
99 #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
100 pub struct ServerCache {
101     pub inprog: u64,
102     pub nonidem: u64,
103     pub misses: u64,
104     pub size: u64,
105     pub tcp_peak: u64
106 }
107 
108 /// Miscellaneous NFS server stats
109 #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
110 pub struct ServerMisc {
111     /// Number of currently connected NFS v4.0+ clients?
112     pub clients: u64,
113     pub delegs: u64,
114     pub lock_owner: u64,
115     pub locks: u64,
116     pub open_owner: u64,
117     pub opens: u64,
118 }
119 
120 #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
121 pub struct NfsStat {
122     /// Total time in ns that nfsd was busy with at least one operation.
123     /// May wrap!
124     pub busytime: u64,
125     /// Total bytes processed by each operation
126     pub bytes: PerRW,
127     /// Total number of operations that have completed since boot
128     pub donecnt: u64,
129     /// Cumulative duration spent processing each operation, in nanoseconds.
130     /// May wrap!
131     pub duration: PerRWC,
132     pub server_cache: ServerCache,
133     pub server_misc: ServerMisc,
134     /// Count of each RPC processed by the server
135     pub server_rpcs: PerRPC,
136     /// Total number of operations that have been started since boot
137     pub startcnt: u64,
138 }
139 
collect() -> Result<NfsStat>140 pub fn collect() -> Result<NfsStat> {
141     let mut raw = ffi::nfsstatsv1::default();
142     raw.vers = ffi::NFSSTATS_V1 as i32;
143     let flag = ffi::NFSSVC_GETSTATS | ffi::NFSSVC_NEWSTRUCT;
144 	let raw = unsafe {
145         let r = ffi::nfssvc(flag as i32, &mut raw as *mut  _ as *mut c_void);
146         if r != 0 {
147             return Err(Error::last_os_error());
148         }
149         raw
150     };
151     let bytes = PerRW {
152         read: raw.srvbytes[ffi::NFSV4OP_READ as usize],
153         write: raw.srvbytes[ffi::NFSV4OP_WRITE as usize],
154     };
155     let duration = PerRWC {
156         read: bintime_to_ns(&raw.srvduration[ffi::NFSV4OP_READ as usize]),
157         write: bintime_to_ns(&raw.srvduration[ffi::NFSV4OP_WRITE as usize]),
158         commit: bintime_to_ns(&raw.srvduration[ffi::NFSV4OP_COMMIT as usize]),
159     };
160     let server_cache = ServerCache {
161         inprog: raw.srvcache_inproghits,
162         nonidem: raw.srvcache_nonidemdonehits,
163         misses: raw.srvcache_misses,
164         size: i64::max(0, i64::from(raw.srvcache_size)) as u64,
165         tcp_peak: raw.srvcache_tcppeak
166     };
167     let server_misc = ServerMisc {
168         clients: raw.srvclients,
169         delegs: raw.srvdelegates,
170         lock_owner: raw.srvlockowners,
171         locks: raw.srvlocks,
172         open_owner: raw.srvopenowners,
173         opens: raw.srvopens,
174     };
175     let server_rpcs = PerRPC {
176         access: raw.srvrpccnt[ffi::NFSV4OP_ACCESS as usize],
177         backchannelctrl: raw.srvrpccnt[ffi::NFSV4OP_BACKCHANNELCTL as usize],
178         bindconntosess: raw.srvrpccnt[ffi::NFSV4OP_BINDCONNTOSESS as usize],
179         close: raw.srvrpccnt[ffi::NFSV4OP_CLOSE as usize],
180         commit: raw.srvrpccnt[ffi::NFSV4OP_COMMIT as usize],
181         create: raw.srvrpccnt[ffi::NFSV4OP_CREATE as usize],
182         createsess: raw.srvrpccnt[ffi::NFSV4OP_CREATESESSION as usize],
183         delegpurge: raw.srvrpccnt[ffi::NFSV4OP_DELEGPURGE as usize],
184         delegreturn: raw.srvrpccnt[ffi::NFSV4OP_DELEGRETURN as usize],
185         destroyclid: raw.srvrpccnt[ffi::NFSV4OP_DESTROYCLIENTID as usize],
186         destroysess: raw.srvrpccnt[ffi::NFSV4OP_DESTROYSESSION as usize],
187         exchangeid: raw.srvrpccnt[ffi::NFSV4OP_EXCHANGEID as usize],
188         freestateid: raw.srvrpccnt[ffi::NFSV4OP_FREESTATEID as usize],
189         fsinfo: raw.srvrpccnt[ffi::NFSV4OP_FSINFO as usize],
190         fsstat: raw.srvrpccnt[ffi::NFSV4OP_FSSTAT as usize],
191         getattr: raw.srvrpccnt[ffi::NFSV4OP_GETATTR as usize],
192         getdevinfo: raw.srvrpccnt[ffi::NFSV4OP_GETDEVINFO as usize],
193         getdevlist: raw.srvrpccnt[ffi::NFSV4OP_GETDEVLIST as usize],
194         getdirdeleg: raw.srvrpccnt[ffi::NFSV4OP_GETDIRDELEG as usize],
195         getfh: raw.srvrpccnt[ffi::NFSV4OP_GETFH as usize],
196         layoutcommit: raw.srvrpccnt[ffi::NFSV4OP_LAYOUTCOMMIT as usize],
197         layoutget: raw.srvrpccnt[ffi::NFSV4OP_LAYOUTGET as usize],
198         layoutreturn: raw.srvrpccnt[ffi::NFSV4OP_LAYOUTRETURN as usize],
199         link: raw.srvrpccnt[ffi::NFSV4OP_LINK as usize],
200         lock: raw.srvrpccnt[ffi::NFSV4OP_LOCK as usize],
201         lockt: raw.srvrpccnt[ffi::NFSV4OP_LOCKT as usize],
202         locku: raw.srvrpccnt[ffi::NFSV4OP_LOCKU as usize],
203         lookup: raw.srvrpccnt[ffi::NFSV4OP_LOOKUP as usize],
204         lookupp: raw.srvrpccnt[ffi::NFSV4OP_LOOKUPP as usize],
205         mkdir: raw.srvrpccnt[ffi::NFSV4OP_MKDIR as usize],
206         mknod: raw.srvrpccnt[ffi::NFSV4OP_MKNOD as usize],
207         nverify: raw.srvrpccnt[ffi::NFSV4OP_NVERIFY as usize],
208         open: raw.srvrpccnt[ffi::NFSV4OP_OPEN as usize],
209         openattr: raw.srvrpccnt[ffi::NFSV4OP_OPENATTR as usize],
210         openconfirm: raw.srvrpccnt[ffi::NFSV4OP_OPENCONFIRM as usize],
211         opendgrd: raw.srvrpccnt[ffi::NFSV4OP_OPENDOWNGRADE as usize],
212         pathconf: raw.srvrpccnt[ffi::NFSV4OP_PATHCONF as usize],
213         putfh: raw.srvrpccnt[ffi::NFSV4OP_PUTFH as usize],
214         putpubfh: raw.srvrpccnt[ffi::NFSV4OP_PUTPUBFH as usize],
215         putrootfh: raw.srvrpccnt[ffi::NFSV4OP_PUTROOTFH as usize],
216         read: raw.srvrpccnt[ffi::NFSV4OP_READ as usize],
217         readdir: raw.srvrpccnt[ffi::NFSV4OP_READDIR as usize],
218         readdirplus: raw.srvrpccnt[ffi::NFSV4OP_READDIRPLUS as usize],
219         readlink: raw.srvrpccnt[ffi::NFSV4OP_READLINK as usize],
220         reclaimcompl: raw.srvrpccnt[ffi::NFSV4OP_RECLAIMCOMPL as usize],
221         rellckown: raw.srvrpccnt[ffi::NFSV4OP_RELEASELCKOWN as usize],
222         remove: raw.srvrpccnt[ffi::NFSV4OP_REMOVE as usize],
223         rename: raw.srvrpccnt[ffi::NFSV4OP_RENAME as usize],
224         renew: raw.srvrpccnt[ffi::NFSV4OP_RENEW as usize],
225         restorefh: raw.srvrpccnt[ffi::NFSV4OP_RESTOREFH as usize],
226         rmdir: raw.srvrpccnt[ffi::NFSV4OP_RMDIR as usize],
227         savefh: raw.srvrpccnt[ffi::NFSV4OP_SAVEFH as usize],
228         secinfo: raw.srvrpccnt[ffi::NFSV4OP_SECINFO as usize],
229         secinfononame: raw.srvrpccnt[ffi::NFSV4OP_SECINFONONAME as usize],
230         sequence: raw.srvrpccnt[ffi::NFSV4OP_SEQUENCE as usize],
231         setattr: raw.srvrpccnt[ffi::NFSV4OP_SETATTR as usize],
232         setclid: raw.srvrpccnt[ffi::NFSV4OP_SETCLIENTID as usize],
233         setclidcf: raw.srvrpccnt[ffi::NFSV4OP_SETCLIENTIDCFRM as usize],
234         setssv: raw.srvrpccnt[ffi::NFSV4OP_SETSSV as usize],
235         symlink: raw.srvrpccnt[ffi::NFSV4OP_SYMLINK as usize],
236         teststateid: raw.srvrpccnt[ffi::NFSV4OP_TESTSTATEID as usize],
237         v3create: raw.srvrpccnt[ffi::NFSV4OP_V3CREATE as usize],
238         verify: raw.srvrpccnt[ffi::NFSV4OP_VERIFY as usize],
239         wantdeleg: raw.srvrpccnt[ffi::NFSV4OP_WANTDELEG as usize],
240         write: raw.srvrpccnt[ffi::NFSV4OP_WRITE as usize],
241     };
242 	Ok(NfsStat{
243         bytes,
244         duration,
245         startcnt: raw.srvstartcnt,
246         donecnt: raw.srvdonecnt,
247         busytime: bintime_to_ns(&raw.busytime),
248         server_cache,
249         server_misc,
250         server_rpcs
251     })
252 }
253