diff options
author | David Howells <dhowells@redhat.com> | 2006-08-22 20:06:13 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-09-22 23:24:37 -0400 |
commit | 6aaca566503296a73f956908ec98173946134fe2 (patch) | |
tree | 7625bbfa14cddd93ed3e2afa03caf4b553116f76 /fs/nfs/client.c | |
parent | 54ceac4515986030c2502960be620198dd8fe25b (diff) |
NFS: Add server and volume lists to /proc
Make two new proc files available:
/proc/fs/nfsfs/servers
/proc/fs/nfsfs/volumes
The first lists the servers with which we are currently dealing (struct
nfs_client), and the second lists the volumes we have on those servers (struct
nfs_server).
Signed-Off-By: David Howells <dhowells@redhat.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/client.c')
-rw-r--r-- | fs/nfs/client.c | 284 |
1 files changed, 284 insertions, 0 deletions
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index dafba608c0a..27f64781444 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
@@ -1148,3 +1148,287 @@ out_free_server: | |||
1148 | dprintk("<-- nfs_clone_server() = error %d\n", error); | 1148 | dprintk("<-- nfs_clone_server() = error %d\n", error); |
1149 | return ERR_PTR(error); | 1149 | return ERR_PTR(error); |
1150 | } | 1150 | } |
1151 | |||
1152 | #ifdef CONFIG_PROC_FS | ||
1153 | static struct proc_dir_entry *proc_fs_nfs; | ||
1154 | |||
1155 | static int nfs_server_list_open(struct inode *inode, struct file *file); | ||
1156 | static void *nfs_server_list_start(struct seq_file *p, loff_t *pos); | ||
1157 | static void *nfs_server_list_next(struct seq_file *p, void *v, loff_t *pos); | ||
1158 | static void nfs_server_list_stop(struct seq_file *p, void *v); | ||
1159 | static int nfs_server_list_show(struct seq_file *m, void *v); | ||
1160 | |||
1161 | static struct seq_operations nfs_server_list_ops = { | ||
1162 | .start = nfs_server_list_start, | ||
1163 | .next = nfs_server_list_next, | ||
1164 | .stop = nfs_server_list_stop, | ||
1165 | .show = nfs_server_list_show, | ||
1166 | }; | ||
1167 | |||
1168 | static struct file_operations nfs_server_list_fops = { | ||
1169 | .open = nfs_server_list_open, | ||
1170 | .read = seq_read, | ||
1171 | .llseek = seq_lseek, | ||
1172 | .release = seq_release, | ||
1173 | }; | ||
1174 | |||
1175 | static int nfs_volume_list_open(struct inode *inode, struct file *file); | ||
1176 | static void *nfs_volume_list_start(struct seq_file *p, loff_t *pos); | ||
1177 | static void *nfs_volume_list_next(struct seq_file *p, void *v, loff_t *pos); | ||
1178 | static void nfs_volume_list_stop(struct seq_file *p, void *v); | ||
1179 | static int nfs_volume_list_show(struct seq_file *m, void *v); | ||
1180 | |||
1181 | static struct seq_operations nfs_volume_list_ops = { | ||
1182 | .start = nfs_volume_list_start, | ||
1183 | .next = nfs_volume_list_next, | ||
1184 | .stop = nfs_volume_list_stop, | ||
1185 | .show = nfs_volume_list_show, | ||
1186 | }; | ||
1187 | |||
1188 | static struct file_operations nfs_volume_list_fops = { | ||
1189 | .open = nfs_volume_list_open, | ||
1190 | .read = seq_read, | ||
1191 | .llseek = seq_lseek, | ||
1192 | .release = seq_release, | ||
1193 | }; | ||
1194 | |||
1195 | /* | ||
1196 | * open "/proc/fs/nfsfs/servers" which provides a summary of servers with which | ||
1197 | * we're dealing | ||
1198 | */ | ||
1199 | static int nfs_server_list_open(struct inode *inode, struct file *file) | ||
1200 | { | ||
1201 | struct seq_file *m; | ||
1202 | int ret; | ||
1203 | |||
1204 | ret = seq_open(file, &nfs_server_list_ops); | ||
1205 | if (ret < 0) | ||
1206 | return ret; | ||
1207 | |||
1208 | m = file->private_data; | ||
1209 | m->private = PDE(inode)->data; | ||
1210 | |||
1211 | return 0; | ||
1212 | } | ||
1213 | |||
1214 | /* | ||
1215 | * set up the iterator to start reading from the server list and return the first item | ||
1216 | */ | ||
1217 | static void *nfs_server_list_start(struct seq_file *m, loff_t *_pos) | ||
1218 | { | ||
1219 | struct list_head *_p; | ||
1220 | loff_t pos = *_pos; | ||
1221 | |||
1222 | /* lock the list against modification */ | ||
1223 | spin_lock(&nfs_client_lock); | ||
1224 | |||
1225 | /* allow for the header line */ | ||
1226 | if (!pos) | ||
1227 | return SEQ_START_TOKEN; | ||
1228 | pos--; | ||
1229 | |||
1230 | /* find the n'th element in the list */ | ||
1231 | list_for_each(_p, &nfs_client_list) | ||
1232 | if (!pos--) | ||
1233 | break; | ||
1234 | |||
1235 | return _p != &nfs_client_list ? _p : NULL; | ||
1236 | } | ||
1237 | |||
1238 | /* | ||
1239 | * move to next server | ||
1240 | */ | ||
1241 | static void *nfs_server_list_next(struct seq_file *p, void *v, loff_t *pos) | ||
1242 | { | ||
1243 | struct list_head *_p; | ||
1244 | |||
1245 | (*pos)++; | ||
1246 | |||
1247 | _p = v; | ||
1248 | _p = (v == SEQ_START_TOKEN) ? nfs_client_list.next : _p->next; | ||
1249 | |||
1250 | return _p != &nfs_client_list ? _p : NULL; | ||
1251 | } | ||
1252 | |||
1253 | /* | ||
1254 | * clean up after reading from the transports list | ||
1255 | */ | ||
1256 | static void nfs_server_list_stop(struct seq_file *p, void *v) | ||
1257 | { | ||
1258 | spin_unlock(&nfs_client_lock); | ||
1259 | } | ||
1260 | |||
1261 | /* | ||
1262 | * display a header line followed by a load of call lines | ||
1263 | */ | ||
1264 | static int nfs_server_list_show(struct seq_file *m, void *v) | ||
1265 | { | ||
1266 | struct nfs_client *clp; | ||
1267 | |||
1268 | /* display header on line 1 */ | ||
1269 | if (v == SEQ_START_TOKEN) { | ||
1270 | seq_puts(m, "NV SERVER PORT USE HOSTNAME\n"); | ||
1271 | return 0; | ||
1272 | } | ||
1273 | |||
1274 | /* display one transport per line on subsequent lines */ | ||
1275 | clp = list_entry(v, struct nfs_client, cl_share_link); | ||
1276 | |||
1277 | seq_printf(m, "v%d %02x%02x%02x%02x %4hx %3d %s\n", | ||
1278 | clp->cl_nfsversion, | ||
1279 | NIPQUAD(clp->cl_addr.sin_addr), | ||
1280 | ntohs(clp->cl_addr.sin_port), | ||
1281 | atomic_read(&clp->cl_count), | ||
1282 | clp->cl_hostname); | ||
1283 | |||
1284 | return 0; | ||
1285 | } | ||
1286 | |||
1287 | /* | ||
1288 | * open "/proc/fs/nfsfs/volumes" which provides a summary of extant volumes | ||
1289 | */ | ||
1290 | static int nfs_volume_list_open(struct inode *inode, struct file *file) | ||
1291 | { | ||
1292 | struct seq_file *m; | ||
1293 | int ret; | ||
1294 | |||
1295 | ret = seq_open(file, &nfs_volume_list_ops); | ||
1296 | if (ret < 0) | ||
1297 | return ret; | ||
1298 | |||
1299 | m = file->private_data; | ||
1300 | m->private = PDE(inode)->data; | ||
1301 | |||
1302 | return 0; | ||
1303 | } | ||
1304 | |||
1305 | /* | ||
1306 | * set up the iterator to start reading from the volume list and return the first item | ||
1307 | */ | ||
1308 | static void *nfs_volume_list_start(struct seq_file *m, loff_t *_pos) | ||
1309 | { | ||
1310 | struct list_head *_p; | ||
1311 | loff_t pos = *_pos; | ||
1312 | |||
1313 | /* lock the list against modification */ | ||
1314 | spin_lock(&nfs_client_lock); | ||
1315 | |||
1316 | /* allow for the header line */ | ||
1317 | if (!pos) | ||
1318 | return SEQ_START_TOKEN; | ||
1319 | pos--; | ||
1320 | |||
1321 | /* find the n'th element in the list */ | ||
1322 | list_for_each(_p, &nfs_volume_list) | ||
1323 | if (!pos--) | ||
1324 | break; | ||
1325 | |||
1326 | return _p != &nfs_volume_list ? _p : NULL; | ||
1327 | } | ||
1328 | |||
1329 | /* | ||
1330 | * move to next volume | ||
1331 | */ | ||
1332 | static void *nfs_volume_list_next(struct seq_file *p, void *v, loff_t *pos) | ||
1333 | { | ||
1334 | struct list_head *_p; | ||
1335 | |||
1336 | (*pos)++; | ||
1337 | |||
1338 | _p = v; | ||
1339 | _p = (v == SEQ_START_TOKEN) ? nfs_volume_list.next : _p->next; | ||
1340 | |||
1341 | return _p != &nfs_volume_list ? _p : NULL; | ||
1342 | } | ||
1343 | |||
1344 | /* | ||
1345 | * clean up after reading from the transports list | ||
1346 | */ | ||
1347 | static void nfs_volume_list_stop(struct seq_file *p, void *v) | ||
1348 | { | ||
1349 | spin_unlock(&nfs_client_lock); | ||
1350 | } | ||
1351 | |||
1352 | /* | ||
1353 | * display a header line followed by a load of call lines | ||
1354 | */ | ||
1355 | static int nfs_volume_list_show(struct seq_file *m, void *v) | ||
1356 | { | ||
1357 | struct nfs_server *server; | ||
1358 | struct nfs_client *clp; | ||
1359 | char dev[8], fsid[17]; | ||
1360 | |||
1361 | /* display header on line 1 */ | ||
1362 | if (v == SEQ_START_TOKEN) { | ||
1363 | seq_puts(m, "NV SERVER PORT DEV FSID\n"); | ||
1364 | return 0; | ||
1365 | } | ||
1366 | /* display one transport per line on subsequent lines */ | ||
1367 | server = list_entry(v, struct nfs_server, master_link); | ||
1368 | clp = server->nfs_client; | ||
1369 | |||
1370 | snprintf(dev, 8, "%u:%u", | ||
1371 | MAJOR(server->s_dev), MINOR(server->s_dev)); | ||
1372 | |||
1373 | snprintf(fsid, 17, "%llx:%llx", | ||
1374 | server->fsid.major, server->fsid.minor); | ||
1375 | |||
1376 | seq_printf(m, "v%d %02x%02x%02x%02x %4hx %-7s %-17s\n", | ||
1377 | clp->cl_nfsversion, | ||
1378 | NIPQUAD(clp->cl_addr.sin_addr), | ||
1379 | ntohs(clp->cl_addr.sin_port), | ||
1380 | dev, | ||
1381 | fsid); | ||
1382 | |||
1383 | return 0; | ||
1384 | } | ||
1385 | |||
1386 | /* | ||
1387 | * initialise the /proc/fs/nfsfs/ directory | ||
1388 | */ | ||
1389 | int __init nfs_fs_proc_init(void) | ||
1390 | { | ||
1391 | struct proc_dir_entry *p; | ||
1392 | |||
1393 | proc_fs_nfs = proc_mkdir("nfsfs", proc_root_fs); | ||
1394 | if (!proc_fs_nfs) | ||
1395 | goto error_0; | ||
1396 | |||
1397 | proc_fs_nfs->owner = THIS_MODULE; | ||
1398 | |||
1399 | /* a file of servers with which we're dealing */ | ||
1400 | p = create_proc_entry("servers", S_IFREG|S_IRUGO, proc_fs_nfs); | ||
1401 | if (!p) | ||
1402 | goto error_1; | ||
1403 | |||
1404 | p->proc_fops = &nfs_server_list_fops; | ||
1405 | p->owner = THIS_MODULE; | ||
1406 | |||
1407 | /* a file of volumes that we have mounted */ | ||
1408 | p = create_proc_entry("volumes", S_IFREG|S_IRUGO, proc_fs_nfs); | ||
1409 | if (!p) | ||
1410 | goto error_2; | ||
1411 | |||
1412 | p->proc_fops = &nfs_volume_list_fops; | ||
1413 | p->owner = THIS_MODULE; | ||
1414 | return 0; | ||
1415 | |||
1416 | error_2: | ||
1417 | remove_proc_entry("servers", proc_fs_nfs); | ||
1418 | error_1: | ||
1419 | remove_proc_entry("nfsfs", proc_root_fs); | ||
1420 | error_0: | ||
1421 | return -ENOMEM; | ||
1422 | } | ||
1423 | |||
1424 | /* | ||
1425 | * clean up the /proc/fs/nfsfs/ directory | ||
1426 | */ | ||
1427 | void nfs_fs_proc_exit(void) | ||
1428 | { | ||
1429 | remove_proc_entry("volumes", proc_fs_nfs); | ||
1430 | remove_proc_entry("servers", proc_fs_nfs); | ||
1431 | remove_proc_entry("nfsfs", proc_root_fs); | ||
1432 | } | ||
1433 | |||
1434 | #endif /* CONFIG_PROC_FS */ | ||