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