aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/client.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2006-08-22 20:06:13 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2006-09-22 23:24:37 -0400
commit6aaca566503296a73f956908ec98173946134fe2 (patch)
tree7625bbfa14cddd93ed3e2afa03caf4b553116f76 /fs/nfs/client.c
parent54ceac4515986030c2502960be620198dd8fe25b (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.c284
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
1153static struct proc_dir_entry *proc_fs_nfs;
1154
1155static int nfs_server_list_open(struct inode *inode, struct file *file);
1156static void *nfs_server_list_start(struct seq_file *p, loff_t *pos);
1157static void *nfs_server_list_next(struct seq_file *p, void *v, loff_t *pos);
1158static void nfs_server_list_stop(struct seq_file *p, void *v);
1159static int nfs_server_list_show(struct seq_file *m, void *v);
1160
1161static 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
1168static 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
1175static int nfs_volume_list_open(struct inode *inode, struct file *file);
1176static void *nfs_volume_list_start(struct seq_file *p, loff_t *pos);
1177static void *nfs_volume_list_next(struct seq_file *p, void *v, loff_t *pos);
1178static void nfs_volume_list_stop(struct seq_file *p, void *v);
1179static int nfs_volume_list_show(struct seq_file *m, void *v);
1180
1181static 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
1188static 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 */
1199static 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 */
1217static 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 */
1241static 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 */
1256static 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 */
1264static 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 */
1290static 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 */
1308static 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 */
1332static 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 */
1347static 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 */
1355static 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 */
1389int __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
1416error_2:
1417 remove_proc_entry("servers", proc_fs_nfs);
1418error_1:
1419 remove_proc_entry("nfsfs", proc_root_fs);
1420error_0:
1421 return -ENOMEM;
1422}
1423
1424/*
1425 * clean up the /proc/fs/nfsfs/ directory
1426 */
1427void 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 */