Whamcloud - gitweb
don't confuse mds_finish_transno() with PTR_ERR(-ENOENT)
[fs/lustre-release.git] / lustre / mds / lproc_mds.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * GPL HEADER START
5  *
6  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 only,
10  * as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License version 2 for more details (a copy is included
16  * in the LICENSE file that accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License
19  * version 2 along with this program; If not, see
20  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
21  *
22  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23  * CA 95054 USA or visit www.sun.com if you need additional information or
24  * have any questions.
25  *
26  * GPL HEADER END
27  */
28 /*
29  * Copyright  2008 Sun Microsystems, Inc. All rights reserved
30  * Use is subject to license terms.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  */
36 #define DEBUG_SUBSYSTEM S_CLASS
37
38 #include <linux/version.h>
39 #include <asm/statfs.h>
40 #include <obd.h>
41 #include <obd_class.h>
42 #include <lprocfs_status.h>
43 #include "mds_internal.h"
44
45 #ifdef LPROCFS
46 static int lprocfs_mds_rd_mntdev(char *page, char **start, off_t off, int count,
47                                  int *eof, void *data)
48 {
49         struct obd_device* obd = (struct obd_device *)data;
50
51         LASSERT(obd != NULL);
52         LASSERT(obd->u.mds.mds_vfsmnt->mnt_devname);
53         *eof = 1;
54
55         return snprintf(page, count, "%s\n",obd->u.mds.mds_vfsmnt->mnt_devname);
56 }
57
58 static int lprocfs_mds_rd_evictostnids(char *page, char **start, off_t off,
59                                        int count, int *eof, void *data)
60 {
61         struct obd_device* obd = (struct obd_device *)data;
62
63         LASSERT(obd != NULL);
64
65         return snprintf(page, count, "%d\n", obd->u.mds.mds_evict_ost_nids);
66 }
67
68 static int lprocfs_mds_wr_evictostnids(struct file *file, const char *buffer,
69                                        unsigned long count, void *data)
70 {
71         struct obd_device *obd = data;
72         int val, rc;
73
74         rc = lprocfs_write_helper(buffer, count, &val);
75         if (rc)
76                 return rc;
77
78         obd->u.mds.mds_evict_ost_nids = !!val;
79
80         return count;
81 }
82
83 static int lprocfs_mds_wr_evict_client(struct file *file, const char *buffer,
84                                        unsigned long count, void *data)
85 {
86         struct obd_device *obd = data;
87         struct mds_obd *mds = &obd->u.mds;
88         char tmpbuf[sizeof(struct obd_uuid)];
89         struct ptlrpc_request_set *set;
90         int rc;
91
92         sscanf(buffer, "%40s", tmpbuf);
93
94         if (strncmp(tmpbuf, "nid:", 4) != 0)
95                 return lprocfs_wr_evict_client(file, buffer, count, data);
96
97         set = ptlrpc_prep_set();
98         if (!set)
99                 return -ENOMEM;
100
101         if (obd->u.mds.mds_evict_ost_nids) {
102                 rc = obd_set_info_async(mds->mds_osc_exp,sizeof(KEY_EVICT_BY_NID),
103                                         KEY_EVICT_BY_NID, strlen(tmpbuf + 4) + 1,
104                                         tmpbuf + 4, set);
105                 if (rc)
106                         CERROR("Failed to evict nid %s from OSTs: rc %d\n",
107                                tmpbuf + 4, rc);
108                 ptlrpc_check_set(set);
109         }
110
111         /* See the comments in function lprocfs_wr_evict_client()
112          * in ptlrpc/lproc_ptlrpc.c for details. - jay */
113         class_incref(obd);
114         LPROCFS_EXIT();
115
116         obd_export_evict_by_nid(obd, tmpbuf+4);
117
118
119         rc = ptlrpc_set_wait(set);
120         if (rc)
121                 CERROR("Failed to evict nid %s from OSTs: rc %d\n", tmpbuf + 4,
122                        rc);
123
124         LPROCFS_ENTRY();
125         class_decref(obd);
126
127         ptlrpc_set_destroy(set);
128         return count;
129 }
130
131 static int lprocfs_wr_group_info(struct file *file, const char *buffer,
132                                  unsigned long count, void *data)
133 {
134         struct obd_device *obd = data;
135         struct mds_obd *mds = &obd->u.mds;
136         struct mds_grp_downcall_data sparam, *param = &sparam;
137         int size = 0, rc = count;
138
139         if (count < sizeof(param)) {
140                 CERROR("%s: invalid data size %lu\n", obd->obd_name, count);
141                 return count;
142         }
143
144         if (copy_from_user(param, buffer, sizeof(*param)) ||
145             param->mgd_magic != MDS_GRP_DOWNCALL_MAGIC) {
146                 CERROR("%s: MDS group downcall bad params\n", obd->obd_name);
147                 return count;
148         }
149
150         if (param->mgd_ngroups > NGROUPS_MAX) {
151                 CWARN("%s: uid %u groups %d more than maximum %d\n",
152                       obd->obd_name, param->mgd_uid, param->mgd_ngroups,
153                       NGROUPS_MAX);
154                 param->mgd_ngroups = NGROUPS_MAX;
155         }
156
157         if (param->mgd_ngroups > 0) {
158                 size = offsetof(struct mds_grp_downcall_data,
159                                 mgd_groups[param->mgd_ngroups]);
160                 OBD_ALLOC(param, size);
161                 if (!param) {
162                         CERROR("%s: fail to alloc %d bytes for uid %u"
163                                " with %d groups\n", obd->obd_name, size,
164                                sparam.mgd_uid, sparam.mgd_ngroups);
165                         param = &sparam;
166                         param->mgd_ngroups = 0;
167                 } else if (copy_from_user(param, buffer, size)) {
168                         CERROR("%s: uid %u bad supplementary group data\n",
169                                obd->obd_name, sparam.mgd_uid);
170                         OBD_FREE(param, size);
171                         param = &sparam;
172                         param->mgd_ngroups = 0;
173                 }
174         }
175         rc = upcall_cache_downcall(mds->mds_group_hash, param->mgd_err,
176                                    param->mgd_uid, param->mgd_gid,
177                                    param->mgd_ngroups, param->mgd_groups);
178
179         if (param && param != &sparam)
180                 OBD_FREE(param, size);
181
182         return rc;
183 }
184
185 static int lprocfs_rd_group_expire(char *page, char **start, off_t off,
186                                    int count, int *eof, void *data)
187 {
188         struct obd_device *obd = data;
189
190         *eof = 1;
191         return snprintf(page, count, "%lu\n",
192                         obd->u.mds.mds_group_hash->uc_entry_expire / HZ);
193 }
194
195 static int lprocfs_wr_group_expire(struct file *file, const char *buffer,
196                                    unsigned long count, void *data)
197 {
198         struct obd_device *obd = data;
199         int val, rc;
200
201         rc = lprocfs_write_helper(buffer, count, &val);
202         if (rc)
203                 return rc;
204
205         if (val > 5)
206                 obd->u.mds.mds_group_hash->uc_entry_expire = val * HZ;
207         else
208                 CERROR("invalid expire time %u for group cache\n", val);
209
210         return count;
211 }
212
213 static int lprocfs_rd_group_acquire_expire(char *page, char **start, off_t off,
214                                            int count, int *eof, void *data)
215 {
216         struct obd_device *obd = data;
217
218         *eof = 1;
219         return snprintf(page, count, "%lu\n",
220                         obd->u.mds.mds_group_hash->uc_acquire_expire / HZ);
221 }
222
223 static int lprocfs_wr_group_acquire_expire(struct file *file,const char *buffer,
224                                            unsigned long count, void *data)
225 {
226         struct obd_device *obd = data;
227         int val, rc = 0;
228
229         rc = lprocfs_write_helper(buffer, count, &val);
230         if (rc)
231                 return rc;
232
233         if (val > 2)
234                 obd->u.mds.mds_group_hash->uc_acquire_expire = val * HZ;
235
236         return count;
237 }
238
239 static int lprocfs_rd_group_upcall(char *page, char **start, off_t off,
240                                    int count, int *eof, void *data)
241 {
242         struct obd_device *obd = data;
243
244         *eof = 1;
245         return snprintf(page, count, "%s\n",
246                         obd->u.mds.mds_group_hash->uc_upcall);
247 }
248
249 static int lprocfs_wr_group_upcall(struct file *file, const char *buffer,
250                                    unsigned long count, void *data)
251 {
252         struct obd_device *obd = data;
253         struct upcall_cache *hash = obd->u.mds.mds_group_hash;
254         char kernbuf[UC_CACHE_UPCALL_MAXPATH] = { '\0' };
255
256         if (count >= UC_CACHE_UPCALL_MAXPATH) {
257                 CERROR("%s: group upcall too long\n", obd->obd_name);
258                 return -EINVAL;
259         }
260
261         if (copy_from_user(kernbuf, buffer,
262                            min(count, UC_CACHE_UPCALL_MAXPATH - 1)))
263                 return -EFAULT;
264
265         /* Remove any extraneous bits from the upcall (e.g. linefeeds) */
266         sscanf(kernbuf, "%s", hash->uc_upcall);
267
268         if (strcmp(hash->uc_name, obd->obd_name) != 0)
269                 CWARN("%s: write to upcall name %s for MDS %s\n",
270                       obd->obd_name, hash->uc_upcall, obd->obd_name);
271         CWARN("%s: group upcall set to %s\n", obd->obd_name, hash->uc_upcall);
272
273         return count;
274 }
275
276 static int lprocfs_wr_group_flush(struct file *file, const char *buffer,
277                                   unsigned long count, void *data)
278 {
279         struct obd_device *obd = data;
280
281         upcall_cache_flush_idle(obd->u.mds.mds_group_hash);
282         return count;
283 }
284
285 static int lprocfs_wr_atime_diff(struct file *file, const char *buffer,
286                                  unsigned long count, void *data)
287 {
288         struct obd_device *obd = data;
289         struct mds_obd *mds = &obd->u.mds;
290         char kernbuf[20], *end;
291         unsigned long diff = 0;
292
293         if (count > (sizeof(kernbuf) - 1))
294                 return -EINVAL;
295
296         if (copy_from_user(kernbuf, buffer, count))
297                 return -EFAULT;
298
299         kernbuf[count] = '\0';
300
301         diff = simple_strtoul(kernbuf, &end, 0);
302         if (kernbuf == end)
303                 return -EINVAL;
304
305         mds->mds_atime_diff = diff;
306         return count;
307 }
308
309 static int lprocfs_rd_atime_diff(char *page, char **start, off_t off,
310                                  int count, int *eof, void *data)
311 {
312         struct obd_device *obd = data;
313         struct mds_obd *mds = &obd->u.mds;
314
315         *eof = 1;
316         return snprintf(page, count, "%lu\n", mds->mds_atime_diff);
317 }
318
319 static int lprocfs_wr_rootsquash(struct file *file, const char *buffer,
320                                  unsigned long count, void *data)
321 {
322         struct obd_device *obd = data;
323         struct mds_obd *mds = &obd->u.mds;
324         char kernbuf[50], *tmp, *end;
325         unsigned long uid, gid;
326
327         if (count > (sizeof(kernbuf) - 1))
328                 return -EINVAL;
329
330         if (copy_from_user(kernbuf, buffer, count))
331                 return -EFAULT;
332
333         kernbuf[count] = '\0';
334
335         uid = simple_strtoul(kernbuf, &tmp, 0);
336         if (kernbuf == tmp) {
337                 if (tmp[0] != ':')
338                         return -EINVAL;
339                 uid = mds->mds_squash_uid;
340         }
341         /* skip ':' */
342         tmp++;
343         gid = simple_strtoul(tmp, &end, 0);
344         if (tmp == end)
345                 gid = mds->mds_squash_gid;
346
347         mds->mds_squash_uid = uid;
348         mds->mds_squash_gid = gid;
349         return count;
350 }
351
352 static int lprocfs_rd_rootsquash(char *page, char **start, off_t off,
353                                  int count, int *eof, void *data)
354 {
355         struct obd_device *obd = data;
356         struct mds_obd *mds = &obd->u.mds;
357
358         *eof = 1;
359         return snprintf(page, count, "%lu:%lu\n",
360                         (unsigned long)mds->mds_squash_uid,
361                         (unsigned long)mds->mds_squash_gid);
362 }
363
364 static int lprocfs_wr_nosquash_nid(struct file *file, const char *buffer,
365                                    unsigned long count, void *data)
366 {
367         struct obd_device *obd = data;
368         struct mds_obd *mds = &obd->u.mds;
369         char kernbuf[30], *start, *end;
370
371         if (count > (sizeof(kernbuf) - 1))
372                 return -EINVAL;
373
374         if (copy_from_user(kernbuf, buffer, count))
375                 return -EFAULT;
376         kernbuf[count] = '\0';
377
378         /* strip frontal whitespaces */
379         start = kernbuf;
380         while (*start && isspace(*start))
381                 start++;
382         /* EOL - string doesn't contain NID */
383         if (*start == '\0')
384                 return -EINVAL;
385         /* strip backward whitespaces */
386         end = kernbuf + count - 1;
387         while (*end && isspace(*end))
388                 end--;
389         *(end + 1) = '\0';
390
391         mds->mds_nosquash_nid = libcfs_str2nid(start);
392         return count;
393 }
394
395 static int lprocfs_rd_nosquash_nid(char *page, char **start, off_t off,
396                                    int count, int *eof, void *data)
397 {
398         struct obd_device *obd = data;
399         struct mds_obd *mds = &obd->u.mds;
400
401         *eof = 1;
402         return snprintf(page, count, "%s\n",
403                         libcfs_nid2str(mds->mds_nosquash_nid));
404 }
405
406 static int lprocfs_mds_rd_sync_perm(char *page, char **start, off_t off,
407                                     int count, int *eof, void *data)
408 {
409         struct obd_device* obd = (struct obd_device *)data;
410
411         LASSERT(obd != NULL);
412
413         return snprintf(page, count, "%d\n", obd->u.mds.mds_sync_permission);
414 }
415
416 static int lprocfs_mds_wr_sync_perm(struct file *file, const char *buffer,
417                                     unsigned long count, void *data)
418 {
419         struct obd_device *obd = data;
420         int val, rc;
421
422         rc = lprocfs_write_helper(buffer, count, &val);
423         if (rc)
424                 return rc;
425
426         obd->u.mds.mds_sync_permission = !!val;
427
428         return count;
429 }
430
431 struct lprocfs_vars lprocfs_mds_obd_vars[] = {
432         { "uuid",            lprocfs_rd_uuid,        0, 0 },
433         { "blocksize",       lprocfs_rd_blksize,     0, 0 },
434         { "kbytestotal",     lprocfs_rd_kbytestotal, 0, 0 },
435         { "kbytesfree",      lprocfs_rd_kbytesfree,  0, 0 },
436         { "kbytesavail",     lprocfs_rd_kbytesavail, 0, 0 },
437         { "filestotal",      lprocfs_rd_filestotal,  0, 0 },
438         { "filesfree",       lprocfs_rd_filesfree,   0, 0 },
439         { "fstype",          lprocfs_rd_fstype,      0, 0 },
440         { "mntdev",          lprocfs_mds_rd_mntdev,  0, 0 },
441         { "recovery_status", lprocfs_obd_rd_recovery_status, 0, 0 },
442         { "hash_stats",      lprocfs_obd_rd_hash,    0, 0 },
443         { "evict_client",    0,                lprocfs_mds_wr_evict_client, 0 },
444         { "evict_ost_nids",  lprocfs_mds_rd_evictostnids,
445                                                lprocfs_mds_wr_evictostnids, 0 },
446         { "num_exports",     lprocfs_rd_num_exports, 0, 0 },
447 #ifdef HAVE_QUOTA_SUPPORT
448         { "quota_bunit_sz",  lprocfs_quota_rd_bunit, lprocfs_quota_wr_bunit, 0 },
449         { "quota_btune_sz",  lprocfs_quota_rd_btune, lprocfs_quota_wr_btune, 0 },
450         { "quota_iunit_sz",  lprocfs_quota_rd_iunit, lprocfs_quota_wr_iunit, 0 },
451         { "quota_itune_sz",  lprocfs_quota_rd_itune, lprocfs_quota_wr_itune, 0 },
452         { "quota_type",      lprocfs_quota_rd_type,  lprocfs_quota_wr_type, 0 },
453         { "quota_switch_qs", lprocfs_quota_rd_switch_qs,
454                              lprocfs_quota_wr_switch_qs, 0 },
455         { "quota_boundary_factor", lprocfs_quota_rd_boundary_factor,
456                                    lprocfs_quota_wr_boundary_factor, 0 },
457         { "quota_least_bunit", lprocfs_quota_rd_least_bunit,
458                                lprocfs_quota_wr_least_bunit, 0 },
459         { "quota_least_iunit", lprocfs_quota_rd_least_iunit,
460                                lprocfs_quota_wr_least_iunit, 0 },
461         { "quota_qs_factor",   lprocfs_quota_rd_qs_factor,
462                                lprocfs_quota_wr_qs_factor, 0 },
463         { "quota_switch_seconds",  lprocfs_quota_rd_switch_seconds,
464                                    lprocfs_quota_wr_switch_seconds, 0 },
465 #endif
466         { "group_expire_interval", lprocfs_rd_group_expire,
467                              lprocfs_wr_group_expire, 0},
468         { "group_acquire_expire", lprocfs_rd_group_acquire_expire,
469                              lprocfs_wr_group_acquire_expire, 0},
470         { "group_upcall",    lprocfs_rd_group_upcall,
471                              lprocfs_wr_group_upcall, 0},
472         { "group_flush",     0, lprocfs_wr_group_flush, 0},
473         { "group_info",      0, lprocfs_wr_group_info, 0 },
474         { "atime_diff",      lprocfs_rd_atime_diff, lprocfs_wr_atime_diff, 0 },
475         { "rootsquash",      lprocfs_rd_rootsquash,
476                              lprocfs_wr_rootsquash, 0 },
477         { "nosquash_nid",    lprocfs_rd_nosquash_nid,
478                              lprocfs_wr_nosquash_nid, 0 },
479         { "sync_permission", lprocfs_mds_rd_sync_perm,
480                              lprocfs_mds_wr_sync_perm, 0 },
481 #ifdef HAVE_DELAYED_RECOVERY
482         { "stale_export_age", lprocfs_obd_rd_stale_export_age,
483                               lprocfs_obd_wr_stale_export_age, 0},
484         { "flush_stale_exports", 0, lprocfs_obd_wr_flush_stale_exports, 0 },
485 #endif
486         { 0 }
487 };
488
489 struct lprocfs_vars lprocfs_mds_module_vars[] = {
490         { "num_refs",     lprocfs_rd_numrefs,     0, 0 },
491         { 0 }
492 };
493
494 struct lprocfs_vars lprocfs_mdt_obd_vars[] = {
495         { "uuid",         lprocfs_rd_uuid,        0, 0 },
496         { 0 }
497 };
498
499 struct lprocfs_vars lprocfs_mdt_module_vars[] = {
500         { "num_refs",     lprocfs_rd_numrefs,     0, 0 },
501         { 0 }
502 };
503
504 void mds_counter_incr(struct obd_export *exp, int opcode)
505 {
506         if (exp->exp_obd && exp->exp_obd->obd_stats)
507                 lprocfs_counter_incr(exp->exp_obd->obd_stats, opcode);
508         if (exp->exp_nid_stats && exp->exp_nid_stats->nid_stats != NULL)
509                 lprocfs_counter_incr(exp->exp_nid_stats->nid_stats, opcode);
510
511 }
512
513 void mds_stats_counter_init(struct lprocfs_stats *stats)
514 {
515         lprocfs_counter_init(stats, LPROC_MDS_OPEN, 0, "open", "reqs");
516         lprocfs_counter_init(stats, LPROC_MDS_CLOSE, 0, "close", "reqs");
517         lprocfs_counter_init(stats, LPROC_MDS_MKNOD, 0, "mknod", "reqs");
518         lprocfs_counter_init(stats, LPROC_MDS_LINK, 0, "link", "reqs");
519         lprocfs_counter_init(stats, LPROC_MDS_UNLINK, 0, "unlink", "reqs");
520         lprocfs_counter_init(stats, LPROC_MDS_MKDIR, 0, "mkdir", "reqs");
521         lprocfs_counter_init(stats, LPROC_MDS_RMDIR, 0, "rmdir", "reqs");
522         lprocfs_counter_init(stats, LPROC_MDS_RENAME, 0, "rename", "reqs");
523         lprocfs_counter_init(stats, LPROC_MDS_GETXATTR, 0, "getxattr", "reqs");
524         lprocfs_counter_init(stats, LPROC_MDS_SETXATTR, 0, "setxattr", "reqs");
525 }
526
527 void lprocfs_mds_init_vars(struct lprocfs_static_vars *lvars)
528 {
529     lvars->module_vars = lprocfs_mds_module_vars;
530     lvars->obd_vars = lprocfs_mds_obd_vars;
531 }
532
533 void lprocfs_mdt_init_vars(struct lprocfs_static_vars *lvars)
534 {
535     lvars->module_vars = lprocfs_mdt_module_vars;
536     lvars->obd_vars = lprocfs_mdt_obd_vars;
537 }
538 #endif