1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
4 * Object Devices Class Driver
6 * Copyright (C) 2001-2003 Cluster File Systems, Inc.
8 * This file is part of Lustre, http://www.lustre.org.
10 * Lustre is free software; you can redistribute it and/or
11 * modify it under the terms of version 2 of the GNU General Public
12 * License as published by the Free Software Foundation.
14 * Lustre is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with Lustre; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 * These are the only exported functions, they provide some generic
24 * infrastructure for managing object devices
26 #define DEBUG_SUBSYSTEM S_CLASS
28 # define EXPORT_SYMTAB
32 #include <linux/config.h> /* for CONFIG_PROC_FS */
33 #include <linux/module.h>
34 #include <linux/errno.h>
35 #include <linux/kernel.h>
36 #include <linux/major.h>
37 #include <linux/sched.h>
39 #include <linux/slab.h>
40 #include <linux/ioport.h>
41 #include <linux/fcntl.h>
42 #include <linux/delay.h>
43 #include <linux/skbuff.h>
44 #include <linux/proc_fs.h>
46 #include <linux/poll.h>
47 #include <linux/init.h>
48 #include <linux/list.h>
49 #include <linux/highmem.h>
51 #include <asm/ioctls.h>
52 #include <asm/system.h>
54 #include <asm/uaccess.h>
55 #include <linux/miscdevice.h>
56 #include <linux/smp_lock.h>
57 #include <linux/seq_file.h>
59 # include <liblustre.h>
62 #include <libcfs/libcfs.h>
63 #include <obd_support.h>
64 #include <obd_class.h>
65 #include <lprocfs_status.h>
67 #include <linux/lustre_build_version.h>
68 #include <linux/lustre_version.h>
72 /* buffer MUST be at least the size of obd_ioctl_hdr */
73 int obd_ioctl_getdata(char **buf, int *len, void *arg)
75 struct obd_ioctl_hdr hdr;
76 struct obd_ioctl_data *data;
81 err = copy_from_user(&hdr, (void *)arg, sizeof(hdr));
85 if (hdr.ioc_version != OBD_IOCTL_VERSION) {
86 CERROR("Version mismatch kernel vs application\n");
90 if (hdr.ioc_len > OBD_MAX_IOCTL_BUFFER) {
91 CERROR("User buffer len %d exceeds %d max buffer\n",
92 hdr.ioc_len, OBD_MAX_IOCTL_BUFFER);
96 if (hdr.ioc_len < sizeof(struct obd_ioctl_data)) {
97 CERROR("User buffer too small for ioctl (%d)\n", hdr.ioc_len);
101 /* XXX allocate this more intelligently, using kmalloc when
103 OBD_VMALLOC(*buf, hdr.ioc_len);
105 CERROR("Cannot allocate control buffer of len %d\n",
110 data = (struct obd_ioctl_data *)*buf;
112 err = copy_from_user(*buf, (void *)arg, hdr.ioc_len);
114 OBD_VFREE(*buf, hdr.ioc_len);
118 if (obd_ioctl_is_invalid(data)) {
119 CERROR("ioctl not correctly formatted\n");
120 OBD_VFREE(*buf, hdr.ioc_len);
124 if (data->ioc_inllen1) {
125 data->ioc_inlbuf1 = &data->ioc_bulk[0];
126 offset += size_round(data->ioc_inllen1);
129 if (data->ioc_inllen2) {
130 data->ioc_inlbuf2 = &data->ioc_bulk[0] + offset;
131 offset += size_round(data->ioc_inllen2);
134 if (data->ioc_inllen3) {
135 data->ioc_inlbuf3 = &data->ioc_bulk[0] + offset;
136 offset += size_round(data->ioc_inllen3);
139 if (data->ioc_inllen4) {
140 data->ioc_inlbuf4 = &data->ioc_bulk[0] + offset;
147 int obd_ioctl_popdata(void *arg, void *data, int len)
151 err = copy_to_user(arg, data, len);
157 EXPORT_SYMBOL(obd_ioctl_getdata);
158 EXPORT_SYMBOL(obd_ioctl_popdata);
160 #define OBD_MINOR 241
161 extern struct cfs_psdev_ops obd_psdev_ops;
163 /* opening /dev/obd */
164 static int obd_class_open(struct inode * inode, struct file * file)
166 if (obd_psdev_ops.p_open != NULL)
167 return obd_psdev_ops.p_open(0, NULL);
171 /* closing /dev/obd */
172 static int obd_class_release(struct inode * inode, struct file * file)
174 if (obd_psdev_ops.p_close != NULL)
175 return obd_psdev_ops.p_close(0, NULL);
179 /* to control /dev/obd */
180 static int obd_class_ioctl(struct inode *inode, struct file *filp,
181 unsigned int cmd, unsigned long arg)
186 if (current->fsuid != 0)
187 RETURN(err = -EACCES);
188 if ((cmd & 0xffffff00) == ((int)'T') << 8) /* ignore all tty ioctls */
189 RETURN(err = -ENOTTY);
191 if (obd_psdev_ops.p_ioctl != NULL)
192 err = obd_psdev_ops.p_ioctl(NULL, cmd, (void *)arg);
199 /* declare character device */
200 static struct file_operations obd_psdev_fops = {
201 .owner = THIS_MODULE,
202 .ioctl = obd_class_ioctl, /* ioctl */
203 .open = obd_class_open, /* open */
204 .release = obd_class_release, /* release */
208 cfs_psdev_t obd_psdev = {
211 .fops = &obd_psdev_fops,
217 int obd_proc_read_version(char *page, char **start, off_t off, int count,
218 int *eof, void *data)
221 return snprintf(page, count, "%s\n", BUILD_VERSION);
224 int obd_proc_read_kernel_version(char *page, char **start, off_t off, int count,
225 int *eof, void *data)
228 return snprintf(page, count, "%u\n", LUSTRE_KERNEL_VERSION);
231 int obd_proc_read_pinger(char *page, char **start, off_t off, int count,
232 int *eof, void *data)
235 return snprintf(page, count, "%s\n",
244 static int obd_proc_read_health(char *page, char **start, off_t off,
245 int count, int *eof, void *data)
250 if (libcfs_catastrophe)
251 rc += snprintf(page + rc, count - rc, "LBUG\n");
253 spin_lock(&obd_dev_lock);
254 for (i = 0; i < MAX_OBD_DEVICES; i++) {
255 struct obd_device *obd;
258 if (obd->obd_type == NULL)
262 spin_unlock(&obd_dev_lock);
264 if (obd_health_check(obd)) {
265 rc += snprintf(page + rc, count - rc,
266 "device %s reported unhealthy\n",
270 spin_lock(&obd_dev_lock);
272 spin_unlock(&obd_dev_lock);
275 return snprintf(page, count, "healthy\n");
277 rc += snprintf(page + rc, count - rc, "NOT HEALTHY\n");
281 static int obd_proc_rd_health_timeout(char *page, char **start, off_t off,
282 int count, int *eof, void *data)
285 return snprintf(page, count, "%d\n", obd_health_check_timeout);
288 static int obd_proc_wr_health_timeout(struct file *file, const char *buffer,
289 unsigned long count, void *data)
293 rc = lprocfs_write_helper(buffer, count, &val);
297 obd_health_check_timeout = val;
302 /* Root for /proc/fs/lustre */
303 struct proc_dir_entry *proc_lustre_root = NULL;
305 struct lprocfs_vars lprocfs_base[] = {
306 { "version", obd_proc_read_version, NULL, NULL },
307 { "kernel_version", obd_proc_read_kernel_version, NULL, NULL },
308 { "pinger", obd_proc_read_pinger, NULL, NULL },
309 { "health_check", obd_proc_read_health, NULL, NULL },
310 { "health_check_timeout", obd_proc_rd_health_timeout,
311 obd_proc_wr_health_timeout, NULL },
315 #define lprocfs_base NULL
319 static void *obd_device_list_seq_start(struct seq_file *p, loff_t*pos)
321 if (*pos >= MAX_OBD_DEVICES)
323 return &obd_dev[*pos];
326 static void obd_device_list_seq_stop(struct seq_file *p, void *v)
330 static void *obd_device_list_seq_next(struct seq_file *p, void *v, loff_t *pos)
333 if (*pos >= MAX_OBD_DEVICES)
335 return &obd_dev[*pos];
338 static int obd_device_list_seq_show(struct seq_file *p, void *v)
340 struct obd_device *obd = (struct obd_device *)v;
341 int index = obd - &obd_dev[0];
346 if (obd->obd_stopping)
348 else if (obd->obd_set_up)
350 else if (obd->obd_attached)
355 return seq_printf(p, "%3d %s %s %s %s %d\n",
356 (int)index, status, obd->obd_type->typ_name,
357 obd->obd_name, obd->obd_uuid.uuid,
358 atomic_read(&obd->obd_refcount));
361 struct seq_operations obd_device_list_sops = {
362 .start = obd_device_list_seq_start,
363 .stop = obd_device_list_seq_stop,
364 .next = obd_device_list_seq_next,
365 .show = obd_device_list_seq_show,
368 static int obd_device_list_open(struct inode *inode, struct file *file)
370 struct proc_dir_entry *dp = PDE(inode);
371 struct seq_file *seq;
372 int rc = seq_open(file, &obd_device_list_sops);
377 seq = file->private_data;
378 seq->private = dp->data;
383 struct file_operations obd_device_list_fops = {
384 .owner = THIS_MODULE,
385 .open = obd_device_list_open,
388 .release = seq_release,
392 int class_procfs_init(void)
395 struct proc_dir_entry *entry;
399 proc_lustre_root = proc_mkdir("lustre", proc_root_fs);
400 if (!proc_lustre_root) {
402 "LustreError: error registering /proc/fs/lustre\n");
405 proc_version = lprocfs_add_vars(proc_lustre_root, lprocfs_base, NULL);
406 entry = create_proc_entry("devices", 0444, proc_lustre_root);
408 CERROR("error registering /proc/fs/lustre/devices\n");
409 lprocfs_remove(proc_lustre_root);
412 entry->proc_fops = &obd_device_list_fops;
420 int class_procfs_clean(void)
423 if (proc_lustre_root) {
424 lprocfs_remove(proc_lustre_root);
425 proc_lustre_root = NULL;
431 /* Check that we're building against the appropriate version of the Lustre
433 #include <linux/lustre_version.h>
434 #define LUSTRE_MIN_VERSION 37
435 #define LUSTRE_MAX_VERSION 47
436 #if (LUSTRE_KERNEL_VERSION < LUSTRE_MIN_VERSION)
437 # error Cannot continue: Your Lustre kernel patch is older than the sources
438 #elif (LUSTRE_KERNEL_VERSION > LUSTRE_MAX_VERSION)
439 # error Cannot continue: Your Lustre sources are older than the kernel patch