Whamcloud - gitweb
f27a49ba2afa4016a75dbdac0f82c2af31463039
[fs/lustre-release.git] / lustre / ofd / ofd_access_log.c
1 #include <linux/cdev.h>
2 #include <linux/circ_buf.h>
3 #include <linux/device.h>
4 #include <linux/fs.h>
5 #include <linux/kernel.h>
6 #include <linux/miscdevice.h>
7 #include <linux/module.h>
8 #include <linux/poll.h>
9 #include <linux/slab.h>
10 #include <linux/types.h>
11 #include <linux/uaccess.h>
12 #include <uapi/linux/lustre/lustre_idl.h>
13 #include <uapi/linux/lustre/lustre_access_log.h>
14 #include "ofd_internal.h"
15
16 /* OFD access logs: OST (OFD) RPC handlers log accesses by FID and
17  * PFID which are read from userspace through character device files
18  * (/dev/lustre-access-log/scratch-OST0000). Accesses are described by
19  * struct ofd_access_entry_v1. The char device implements read()
20  * (blocking and nonblocking) and poll(), along with an ioctl that
21  * returns diagnostic information on an oal device.
22  *
23  * A control device (/dev/lustre-access-log/control) supports an ioctl()
24  * plus poll() method to for oal discovery. See uses of
25  * oal_control_event_count and oal_control_wait_queue for details.
26  *
27  * oal log size and entry size are restricted to powers of 2 to
28  * support circ_buf methods. See Documentation/core-api/circular-buffers.rst
29  * in the linux tree for more information.
30  *
31  * The associated struct device (*oal_device) owns the oal. The
32  * release() method of oal_device frees the oal and releases its
33  * minor. This may seem slightly more complicated than necessary but
34  * it allows the OST to be unmounted while the oal still has open file
35  * descriptors.
36  */
37
38 enum {
39         OAL_DEV_COUNT = 1 << MINORBITS,
40 };
41
42 struct ofd_access_log {
43         char oal_name[128]; /* lustre-OST0000 */
44         struct device oal_device;
45         struct cdev oal_cdev;
46         struct rw_semaphore oal_buf_list_sem;
47         struct list_head oal_circ_buf_list;
48         unsigned int oal_is_closed;
49         unsigned int oal_log_size;
50         unsigned int oal_entry_size;
51 };
52
53 struct oal_circ_buf {
54         struct list_head ocb_list;
55         spinlock_t ocb_write_lock;
56         spinlock_t ocb_read_lock;
57         struct ofd_access_log *ocb_access_log;
58         __u32 ocb_filter;
59         wait_queue_head_t ocb_read_wait_queue;
60         unsigned int ocb_drop_count;
61         struct circ_buf ocb_circ;
62 };
63
64 static atomic_t oal_control_event_count = ATOMIC_INIT(0);
65 static DECLARE_WAIT_QUEUE_HEAD(oal_control_wait_queue);
66
67 static struct class *oal_log_class;
68 static unsigned int oal_log_major;
69 static DEFINE_IDR(oal_log_minor_idr); /* TODO Use ida instead. */
70 static DEFINE_SPINLOCK(oal_log_minor_lock);
71
72 bool ofd_access_log_size_is_valid(unsigned int size)
73 {
74         const unsigned int size_min = 2 * sizeof(struct ofd_access_entry_v1);
75         const unsigned int size_max = 1U << 30;
76
77         if (size == 0)
78                 return true;
79
80         return is_power_of_2(size) && size_min <= size && size <= size_max;
81 }
82
83 static void oal_control_event_inc(void)
84 {
85         atomic_inc(&oal_control_event_count);
86         wake_up(&oal_control_wait_queue);
87 }
88
89 static int oal_log_minor_alloc(int *pminor)
90 {
91         void *OAL_LOG_MINOR_ALLOCED = (void *)-1;
92         int minor;
93
94         idr_preload(GFP_KERNEL);
95         spin_lock(&oal_log_minor_lock);
96         minor = idr_alloc(&oal_log_minor_idr, OAL_LOG_MINOR_ALLOCED, 0,
97                         OAL_DEV_COUNT, GFP_NOWAIT);
98         spin_unlock(&oal_log_minor_lock);
99         idr_preload_end();
100
101         if (minor < 0)
102                 return minor;
103
104         *pminor = minor;
105
106         return 0;
107 }
108
109 static void oal_log_minor_free(int minor)
110 {
111         spin_lock(&oal_log_minor_lock);
112         idr_remove(&oal_log_minor_idr, minor);
113         spin_unlock(&oal_log_minor_lock);
114 }
115
116 static bool oal_is_empty(struct oal_circ_buf *ocb)
117 {
118         struct ofd_access_log *oal = ocb->ocb_access_log;
119
120         return CIRC_CNT(ocb->ocb_circ.head,
121                         ocb->ocb_circ.tail,
122                         oal->oal_log_size) < oal->oal_entry_size;
123 }
124
125 static ssize_t oal_write_entry(struct oal_circ_buf *ocb,
126                         const void *entry, size_t entry_size)
127 {
128         struct ofd_access_log *oal = ocb->ocb_access_log;
129         struct circ_buf *circ = &ocb->ocb_circ;
130         unsigned int head;
131         unsigned int tail;
132         ssize_t rc;
133
134         if (entry_size != oal->oal_entry_size)
135                 return -EINVAL;
136
137         spin_lock(&ocb->ocb_write_lock);
138         head = circ->head;
139         tail = READ_ONCE(circ->tail);
140
141         /* CIRC_SPACE() return space available, 0..oal_log_size -
142          * 1. It always leaves one free char, since a completely full
143          * buffer would have head == tail, which is the same as empty. */
144         if (CIRC_SPACE(head, tail, oal->oal_log_size) < oal->oal_entry_size) {
145                 ocb->ocb_drop_count++;
146                 rc = -EAGAIN;
147                 goto out_write_lock;
148         }
149
150         memcpy(&circ->buf[head], entry, entry_size);
151         rc = entry_size;
152
153         /* Ensure the entry is stored before we update the head. */
154         smp_store_release(&circ->head,
155                         (head + oal->oal_entry_size) & (oal->oal_log_size - 1));
156
157         wake_up(&ocb->ocb_read_wait_queue);
158 out_write_lock:
159         spin_unlock(&ocb->ocb_write_lock);
160
161         return rc;
162 }
163
164 /* Read one entry from the log and return its size. Non-blocking.
165  * When the log is empty we return -EAGAIN if the OST is still mounted
166  * and 0 otherwise.
167  */
168 static ssize_t oal_read_entry(struct oal_circ_buf *ocb,
169                         void *entry_buf, size_t entry_buf_size)
170 {
171         struct ofd_access_log *oal = ocb->ocb_access_log;
172         struct circ_buf *circ = &ocb->ocb_circ;
173         unsigned int head;
174         unsigned int tail;
175         ssize_t rc;
176
177         /* XXX This method may silently truncate entries when
178          * entry_buf_size is less than oal_entry_size. But that's OK
179          * because you know what you are doing. */
180         spin_lock(&ocb->ocb_read_lock);
181
182         /* Memory barrier usage follows circular-buffers.txt. */
183         head = smp_load_acquire(&circ->head);
184         tail = circ->tail;
185
186         if (!CIRC_CNT(head, tail, oal->oal_log_size)) {
187                 rc = oal->oal_is_closed ? 0 : -EAGAIN;
188                 goto out_read_lock;
189         }
190
191         BUG_ON(CIRC_CNT(head, tail, oal->oal_log_size) < oal->oal_entry_size);
192
193         /* Extract one entry from the buffer. */
194         rc = min_t(size_t, oal->oal_entry_size, entry_buf_size);
195         memcpy(entry_buf, &circ->buf[tail], rc);
196
197         /* Memory barrier usage follows circular-buffers.txt. */
198         smp_store_release(&circ->tail,
199                         (tail + oal->oal_entry_size) & (oal->oal_log_size - 1));
200
201 out_read_lock:
202         spin_unlock(&ocb->ocb_read_lock);
203
204         return rc;
205 }
206
207 static int oal_file_open(struct inode *inode, struct file *filp)
208 {
209         struct ofd_access_log *oal;
210         struct oal_circ_buf *ocb;
211
212         oal = container_of(inode->i_cdev, struct ofd_access_log, oal_cdev);
213
214         ocb = kzalloc(sizeof(*ocb), GFP_KERNEL);
215         if (!ocb)
216                 return -ENOMEM;
217         ocb->ocb_circ.buf = vmalloc(oal->oal_log_size);
218         if (!ocb->ocb_circ.buf) {
219                 kfree(ocb);
220                 return -ENOMEM;
221         }
222
223         spin_lock_init(&ocb->ocb_write_lock);
224         spin_lock_init(&ocb->ocb_read_lock);
225         ocb->ocb_access_log = oal;
226         init_waitqueue_head(&ocb->ocb_read_wait_queue);
227
228         down_write(&oal->oal_buf_list_sem);
229         list_add(&ocb->ocb_list, &oal->oal_circ_buf_list);
230         up_write(&oal->oal_buf_list_sem);
231
232         filp->private_data = ocb;
233
234         return nonseekable_open(inode, filp);
235 }
236
237 /* User buffer size must be a multiple of ofd access entry size. */
238 static ssize_t oal_file_read(struct file *filp, char __user *buf, size_t count,
239                         loff_t *ppos)
240 {
241         struct oal_circ_buf *ocb = filp->private_data;
242         struct ofd_access_log *oal = ocb->ocb_access_log;
243         void *entry;
244         size_t size = 0;
245         int rc = 0;
246
247         if (!count)
248                 return 0;
249
250         if (count & (oal->oal_entry_size - 1))
251                 return -EINVAL;
252
253         entry = kzalloc(oal->oal_entry_size, GFP_KERNEL);
254         if (!entry)
255                 return -ENOMEM;
256
257         while (size < count) {
258                 rc = oal_read_entry(ocb, entry, oal->oal_entry_size);
259                 if (rc == -EAGAIN) {
260                         if (filp->f_flags & O_NONBLOCK)
261                                 break;
262
263                         rc = wait_event_interruptible(ocb->ocb_read_wait_queue,
264                                 !oal_is_empty(ocb) || oal->oal_is_closed);
265                         if (rc)
266                                 break;
267                 } else if (rc <= 0) {
268                         break; /* cloed or error */
269                 } else {
270                         if (copy_to_user(buf, entry, oal->oal_entry_size)) {
271                                 rc = -EFAULT;
272                                 break;
273                         }
274
275                         buf += oal->oal_entry_size;
276                         size += oal->oal_entry_size;
277                 }
278         }
279
280         kfree(entry);
281
282         return size ? size : rc;
283 }
284
285 /* Included for test purposes. User buffer size must be a multiple of
286  * ofd access entry size. */
287 static ssize_t oal_file_write(struct file *filp, const char __user *buf,
288                         size_t count, loff_t *ppos)
289 {
290         struct oal_circ_buf *ocb = filp->private_data;
291         struct ofd_access_log *oal = ocb->ocb_access_log;
292         void *entry;
293         size_t size = 0;
294         ssize_t rc = 0;
295
296         if (!count)
297                 return 0;
298
299         if (count & (oal->oal_entry_size - 1))
300                 return -EINVAL;
301
302         entry = kzalloc(oal->oal_entry_size, GFP_KERNEL);
303         if (!entry)
304                 return -ENOMEM;
305
306         while (size < count) {
307                 if (copy_from_user(entry, buf, oal->oal_entry_size)) {
308                         rc = -EFAULT;
309                         break;
310                 }
311
312                 rc = oal_write_entry(ocb, entry, oal->oal_entry_size);
313                 if (rc <= 0)
314                         break;
315
316                 buf += oal->oal_entry_size;
317                 size += oal->oal_entry_size;
318         }
319
320         kfree(entry);
321
322         return size > 0 ? size : rc;
323 }
324
325 unsigned int oal_file_poll(struct file *filp, struct poll_table_struct *wait)
326 {
327         struct oal_circ_buf *ocb = filp->private_data;
328         struct ofd_access_log *oal = ocb->ocb_access_log;
329         unsigned int mask = 0;
330
331         poll_wait(filp, &ocb->ocb_read_wait_queue, wait);
332
333         spin_lock(&ocb->ocb_read_lock);
334
335         if (!oal_is_empty(ocb) || oal->oal_is_closed)
336                 mask |= POLLIN;
337
338         spin_unlock(&ocb->ocb_read_lock);
339
340         return mask;
341 }
342
343 static long oal_ioctl_info(struct oal_circ_buf *ocb, unsigned long arg)
344 {
345         struct ofd_access_log *oal = ocb->ocb_access_log;
346
347         struct lustre_access_log_info_v1 __user *lali;
348         u32 entry_count = CIRC_CNT(ocb->ocb_circ.head,
349                                 ocb->ocb_circ.tail,
350                                 oal->oal_log_size) / oal->oal_entry_size;
351         u32 entry_space = CIRC_SPACE(ocb->ocb_circ.head,
352                                 ocb->ocb_circ.tail,
353                                 oal->oal_log_size) / oal->oal_entry_size;
354
355         lali = (struct lustre_access_log_info_v1 __user *)arg;
356         BUILD_BUG_ON(sizeof(lali->lali_name) != sizeof(oal->oal_name));
357
358         if (put_user(LUSTRE_ACCESS_LOG_VERSION_1, &lali->lali_version))
359                 return -EFAULT;
360
361         if (put_user(LUSTRE_ACCESS_LOG_TYPE_OFD, &lali->lali_type))
362                 return -EFAULT;
363
364         if (copy_to_user(lali->lali_name, oal->oal_name, sizeof(oal->oal_name)))
365                 return -EFAULT;
366
367         if (put_user(oal->oal_log_size, &lali->lali_log_size))
368                 return -EFAULT;
369
370         if (put_user(oal->oal_entry_size, &lali->lali_entry_size))
371                 return -EFAULT;
372
373         if (put_user(ocb->ocb_circ.head, &lali->_lali_head))
374                 return -EFAULT;
375
376         if (put_user(ocb->ocb_circ.tail, &lali->_lali_tail))
377                 return -EFAULT;
378
379         if (put_user(entry_space, &lali->_lali_entry_space))
380                 return -EFAULT;
381
382         if (put_user(entry_count, &lali->_lali_entry_count))
383                 return -EFAULT;
384
385         if (put_user(ocb->ocb_drop_count, &lali->_lali_drop_count))
386                 return -EFAULT;
387
388         if (put_user(oal->oal_is_closed, &lali->_lali_is_closed))
389                 return -EFAULT;
390
391         return 0;
392 }
393
394 static long oal_file_ioctl(struct file *filp, unsigned int cmd,
395                         unsigned long arg)
396 {
397         struct oal_circ_buf *ocb = filp->private_data;
398
399         switch (cmd) {
400         case LUSTRE_ACCESS_LOG_IOCTL_VERSION:
401                 return LUSTRE_ACCESS_LOG_VERSION_1;
402         case LUSTRE_ACCESS_LOG_IOCTL_INFO:
403                 return oal_ioctl_info(ocb, arg);
404         case LUSTRE_ACCESS_LOG_IOCTL_FILTER:
405                 ocb->ocb_filter = arg;
406                 return 0;
407         default:
408                 return -ENOTTY;
409         }
410 }
411
412 static int oal_file_release(struct inode *inode, struct file *filp)
413 {
414         struct oal_circ_buf *ocb = filp->private_data;
415         struct ofd_access_log *oal = ocb->ocb_access_log;
416
417         down_write(&oal->oal_buf_list_sem);
418         list_del(&ocb->ocb_list);
419         up_write(&oal->oal_buf_list_sem);
420
421         vfree(ocb->ocb_circ.buf);
422         kfree(ocb);
423
424         return 0;
425 }
426
427 static const struct file_operations oal_fops = {
428         .owner = THIS_MODULE,
429         .open = &oal_file_open,
430         .release = &oal_file_release,
431         .unlocked_ioctl = &oal_file_ioctl,
432         .read = &oal_file_read,
433         .write = &oal_file_write,
434         .poll = &oal_file_poll,
435         .llseek = &no_llseek,
436 };
437
438 static void oal_device_release(struct device *dev)
439 {
440         struct ofd_access_log *oal = dev_get_drvdata(dev);
441
442         oal_log_minor_free(MINOR(oal->oal_device.devt));
443         BUG_ON(!list_empty(&oal->oal_circ_buf_list));
444         kfree(oal);
445 }
446
447 struct ofd_access_log *ofd_access_log_create(const char *ofd_name, size_t size)
448 {
449         const size_t entry_size = sizeof(struct ofd_access_entry_v1);
450         struct ofd_access_log *oal;
451         int minor;
452         int rc;
453
454         BUILD_BUG_ON(sizeof(oal->oal_name) != MAX_OBD_NAME);
455         BUILD_BUG_ON(!is_power_of_2(entry_size));
456
457         if (!size)
458                 return NULL;
459
460         if (!is_power_of_2(size) || (size & (entry_size - 1)) ||
461             (unsigned int)size != size)
462                 return ERR_PTR(-EINVAL);
463
464         oal = kzalloc(sizeof(*oal), GFP_KERNEL);
465         if (!oal)
466                 return ERR_PTR(-ENOMEM);
467
468         strlcpy(oal->oal_name, ofd_name, sizeof(oal->oal_name));
469         oal->oal_log_size = size;
470         oal->oal_entry_size = entry_size;
471         INIT_LIST_HEAD(&oal->oal_circ_buf_list);
472         init_rwsem(&oal->oal_buf_list_sem);
473
474         rc = oal_log_minor_alloc(&minor);
475         if (rc < 0)
476                 goto out_free;
477
478         device_initialize(&oal->oal_device);
479         oal->oal_device.devt = MKDEV(oal_log_major, minor);
480         oal->oal_device.class = oal_log_class;
481         oal->oal_device.release = &oal_device_release;
482         dev_set_drvdata(&oal->oal_device, oal);
483         rc = dev_set_name(&oal->oal_device,
484                         "%s!%s", LUSTRE_ACCESS_LOG_DIR_NAME, oal->oal_name);
485         if (rc < 0)
486                 goto out_minor;
487
488         cdev_init(&oal->oal_cdev, &oal_fops);
489         oal->oal_cdev.owner = THIS_MODULE;
490         rc = cdev_device_add(&oal->oal_cdev, &oal->oal_device);
491         if (rc < 0)
492                 goto out_device_name;
493
494         oal_control_event_inc();
495
496         return oal;
497
498 out_device_name:
499         kfree_const(oal->oal_device.kobj.name);
500 out_minor:
501         oal_log_minor_free(minor);
502 out_free:
503         kfree(oal);
504
505         return ERR_PTR(rc);
506 }
507
508 void ofd_access(const struct lu_env *env,
509                 struct ofd_device *m,
510                 const struct lu_fid *parent_fid,
511                 __u64 begin, __u64 end,
512                 unsigned int size,
513                 unsigned int segment_count,
514                 int rw)
515 {
516         unsigned int flags = (rw == READ) ? OFD_ACCESS_READ : OFD_ACCESS_WRITE;
517         struct ofd_access_log *oal = m->ofd_access_log;
518
519         /* obdfilter-survey does not set parent FIDs. */
520         if (fid_is_zero(parent_fid))
521                 return;
522
523         if (oal && (flags & m->ofd_access_log_mask)) {
524                 struct ofd_access_entry_v1 oae = {
525                         .oae_parent_fid = *parent_fid,
526                         .oae_begin = begin,
527                         .oae_end = end,
528                         .oae_time = ktime_get_real_seconds(),
529                         .oae_size = size,
530                         .oae_segment_count = segment_count,
531                         .oae_flags = flags,
532                 };
533                 struct lu_seq_range range = {
534                         .lsr_flags = LU_SEQ_RANGE_ANY,
535                 };
536                 struct oal_circ_buf *ocb;
537                 int rc;
538
539                 /* learn target MDT from FID's sequence */
540                 rc = fld_server_lookup(env, m->ofd_seq_site.ss_server_fld,
541                                        fid_seq(parent_fid), &range);
542                 if (unlikely(rc))
543                         CERROR("%s: can't resolve "DFID": rc=%d\n",
544                                ofd_name(m), PFID(parent_fid), rc);
545
546                 down_read(&oal->oal_buf_list_sem);
547                 list_for_each_entry(ocb, &oal->oal_circ_buf_list, ocb_list) {
548                         /* filter by MDT index if requested */
549                         if (ocb->ocb_filter == 0xffffffff ||
550                             range.lsr_index == ocb->ocb_filter)
551                                 oal_write_entry(ocb, &oae, sizeof(oae));
552                 }
553                 up_read(&oal->oal_buf_list_sem);
554         }
555 }
556
557 /* Called on OST umount to:
558  * - Close the write end of the oal. The wakes any tasks sleeping in
559  *   read or poll and makes all reads return zero once the log
560  *   becomes empty.
561  * - Delete the associated stuct device and cdev, preventing new
562  *   opens. Existing opens retain a reference on the oal through
563  *   their reference on oal_device.
564  * The oal will be freed when the last open file handle is closed. */
565 void ofd_access_log_delete(struct ofd_access_log *oal)
566 {
567         struct oal_circ_buf *ocb;
568
569         if (!oal)
570                 return;
571
572         oal->oal_is_closed = 1;
573         down_read(&oal->oal_buf_list_sem);
574         list_for_each_entry(ocb, &oal->oal_circ_buf_list, ocb_list)
575                 wake_up(&ocb->ocb_read_wait_queue);
576         up_read(&oal->oal_buf_list_sem);
577         cdev_device_del(&oal->oal_cdev, &oal->oal_device);
578 }
579
580 /* private_data for control device file. */
581 struct oal_control_file {
582         int ccf_event_count;
583 };
584
585 /* Control file usage:
586  * Open /dev/lustre-access-log/control.
587  * while (1)
588  *   Poll for readable on control FD.
589  *   Call ioctl(FD, LUSTRE_ACCESS_LOG_IOCTL_PRESCAN) to fetch event count.
590  *   Scan /dev/ or /sys/class/... for new devices.
591  */
592 static int oal_control_file_open(struct inode *inode, struct file *filp)
593 {
594         struct oal_control_file *ccf;
595         int rc;
596
597         rc = nonseekable_open(inode, filp);
598         if (rc)
599                 return rc;
600
601         /* ccf->ccf_event_count = 0 on open */
602         ccf = kzalloc(sizeof(*ccf), GFP_KERNEL);
603         if (!ccf)
604                 return -ENOMEM;
605
606         filp->private_data = ccf;
607
608         return 0;
609 }
610
611 static int oal_control_file_release(struct inode *inode, struct file *filp)
612 {
613         kfree(filp->private_data);
614         return 0;
615 }
616
617 static unsigned int oal_control_file_poll(struct file *filp, poll_table *wait)
618 {
619         struct oal_control_file *ccf = filp->private_data;
620         unsigned int mask = 0;
621
622         poll_wait(filp, &oal_control_wait_queue, wait);
623
624         if (atomic_read(&oal_control_event_count) != ccf->ccf_event_count)
625                 mask |= POLLIN;
626
627         return mask;
628 }
629
630 static long oal_control_file_ioctl(struct file *filp, unsigned int cmd,
631                                 unsigned long arg)
632 {
633         struct oal_control_file *ccf = filp->private_data;
634
635         switch (cmd) {
636         case LUSTRE_ACCESS_LOG_IOCTL_VERSION:
637                 return LUSTRE_ACCESS_LOG_VERSION_1;
638         case LUSTRE_ACCESS_LOG_IOCTL_MAJOR:
639                 return oal_log_major;
640         case LUSTRE_ACCESS_LOG_IOCTL_PRESCAN:
641                 ccf->ccf_event_count = atomic_read(&oal_control_event_count);
642                 return 0;
643         default:
644                 return -ENOTTY;
645         }
646 }
647
648 static const struct file_operations oal_control_fops = {
649         .owner = THIS_MODULE,
650         .open = &oal_control_file_open,
651         .release = &oal_control_file_release,
652         .poll = &oal_control_file_poll,
653         .unlocked_ioctl = &oal_control_file_ioctl,
654         .llseek = &noop_llseek,
655 };
656
657 static struct miscdevice oal_control_misc = {
658         .minor = MISC_DYNAMIC_MINOR,
659         .name = LUSTRE_ACCESS_LOG_DIR_NAME"!control",
660         .fops = &oal_control_fops,
661 };
662
663 int ofd_access_log_module_init(void)
664 {
665         dev_t dev;
666         int rc;
667
668         BUILD_BUG_ON(!is_power_of_2(sizeof(struct ofd_access_entry_v1)));
669
670         rc = misc_register(&oal_control_misc);
671         if (rc)
672                 return rc;
673
674         rc = alloc_chrdev_region(&dev, 0, OAL_DEV_COUNT,
675                                 LUSTRE_ACCESS_LOG_DIR_NAME);
676         if (rc)
677                 goto out_oal_control_misc;
678
679         oal_log_major = MAJOR(dev);
680
681         oal_log_class = class_create(THIS_MODULE, LUSTRE_ACCESS_LOG_DIR_NAME);
682         if (IS_ERR(oal_log_class)) {
683                 rc = PTR_ERR(oal_log_class);
684                 goto out_dev;
685         }
686
687         return 0;
688 out_dev:
689         unregister_chrdev_region(dev, OAL_DEV_COUNT);
690 out_oal_control_misc:
691         misc_deregister(&oal_control_misc);
692
693         return rc;
694 }
695
696 void ofd_access_log_module_exit(void)
697 {
698         class_destroy(oal_log_class);
699         unregister_chrdev_region(MKDEV(oal_log_major, 0), OAL_DEV_COUNT);
700         idr_destroy(&oal_log_minor_idr);
701         misc_deregister(&oal_control_misc);
702 }