aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--fs/nfs/client.c284
-rw-r--r--fs/nfs/inode.c7
-rw-r--r--fs/nfs/internal.h12
3 files changed, 303 insertions, 0 deletions
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index dafba608c0a0..27f64781444a 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 */
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index a547c58a83e6..cb5c65f0bc12 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -1141,6 +1141,10 @@ static int __init init_nfs_fs(void)
1141{ 1141{
1142 int err; 1142 int err;
1143 1143
1144 err = nfs_fs_proc_init();
1145 if (err)
1146 goto out5;
1147
1144 err = nfs_init_nfspagecache(); 1148 err = nfs_init_nfspagecache();
1145 if (err) 1149 if (err)
1146 goto out4; 1150 goto out4;
@@ -1181,6 +1185,8 @@ out2:
1181out3: 1185out3:
1182 nfs_destroy_nfspagecache(); 1186 nfs_destroy_nfspagecache();
1183out4: 1187out4:
1188 nfs_fs_proc_exit();
1189out5:
1184 return err; 1190 return err;
1185} 1191}
1186 1192
@@ -1195,6 +1201,7 @@ static void __exit exit_nfs_fs(void)
1195 rpc_proc_unregister("nfs"); 1201 rpc_proc_unregister("nfs");
1196#endif 1202#endif
1197 unregister_nfs_fs(); 1203 unregister_nfs_fs();
1204 nfs_fs_proc_exit();
1198} 1205}
1199 1206
1200/* Not quite true; I just maintain it */ 1207/* Not quite true; I just maintain it */
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index e73ba4f1052a..bea0b016bd70 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -47,6 +47,18 @@ extern void nfs_free_server(struct nfs_server *server);
47extern struct nfs_server *nfs_clone_server(struct nfs_server *, 47extern struct nfs_server *nfs_clone_server(struct nfs_server *,
48 struct nfs_fh *, 48 struct nfs_fh *,
49 struct nfs_fattr *); 49 struct nfs_fattr *);
50#ifdef CONFIG_PROC_FS
51extern int __init nfs_fs_proc_init(void);
52extern void nfs_fs_proc_exit(void);
53#else
54static inline int nfs_fs_proc_init(void)
55{
56 return 0;
57}
58static inline void nfs_fs_proc_exit(void)
59{
60}
61#endif
50 62
51/* nfs4namespace.c */ 63/* nfs4namespace.c */
52#ifdef CONFIG_NFS_V4 64#ifdef CONFIG_NFS_V4