Whamcloud - gitweb
LU-16977 utils: access_log_reader accesses beyond batch array
[fs/lustre-release.git] / lustre / utils / ofd_access_batch.c
index 75cd43e..0138ad0 100644 (file)
 #include <linux/lustre/lustre_idl.h>
 #include <libcfs/util/hash.h>
 #include <libcfs/util/list.h>
+#include <lustre/lustreapi.h>
 #include "lstddef.h"
 #include "ofd_access_batch.h"
 
-/* XXX Weird param order to be consistent with list_replace_init(). */
-static inline void list_replace_init(struct list_head *old_node,
-                               struct list_head *new_node)
-{
-       list_add(new_node, old_node);
-       list_del_init(old_node);
-}
-
 struct fid_hash_node {
        struct list_head fhn_node;
        struct lu_fid fhn_fid;
@@ -63,62 +56,6 @@ static inline bool fid_eq(const struct lu_fid *f1, const struct lu_fid *f2)
               f1->f_ver == f2->f_ver;
 }
 
-static inline __u64 fid_flatten(const struct lu_fid *fid)
-{
-       __u64 ino;
-       __u64 seq;
-
-       if (fid_is_igif(fid)) {
-               ino = lu_igif_ino(fid);
-               return ino;
-       }
-
-       seq = fid_seq(fid);
-
-       ino = (seq << 24) + ((seq >> 24) & 0xffffff0000ULL) + fid_oid(fid);
-
-       return ino != 0 ? ino : fid_oid(fid);
-}
-
-/**
- * map fid to 32 bit value for ino on 32bit systems.
- */
-static inline __u32 fid_flatten32(const struct lu_fid *fid)
-{
-       __u32 ino;
-       __u64 seq;
-
-       if (fid_is_igif(fid)) {
-               ino = lu_igif_ino(fid);
-               return ino;
-       }
-
-       seq = fid_seq(fid) - FID_SEQ_START;
-
-       /* Map the high bits of the OID into higher bits of the inode number so
-        * that inodes generated at about the same time have a reduced chance
-        * of collisions. This will give a period of 2^12 = 1024 unique clients
-        * (from SEQ) and up to min(LUSTRE_SEQ_MAX_WIDTH, 2^20) = 128k objects
-        * (from OID), or up to 128M inodes without collisions for new files.
-        */
-       ino = ((seq & 0x000fffffULL) << 12) + ((seq >> 8) & 0xfffff000) +
-             (seq >> (64 - (40-8)) & 0xffffff00) +
-             (fid_oid(fid) & 0xff000fff) + ((fid_oid(fid) & 0x00fff000) << 8);
-
-       return ino != 0 ? ino : fid_oid(fid);
-}
-
-static unsigned long fid_hash(const struct lu_fid *f, unsigned int shift)
-{
-#if __BITS_PER_LONG == 32
-       return hash_long(fid_flatten32(f), shift);
-#elif __BITS_PER_LONG == 64
-       return hash_long(fid_flatten(f), shift);
-#else
-# error "Wordsize not 32 or 64"
-#endif
-}
-
 static void fhn_init(struct fid_hash_node *fhn, const struct lu_fid *fid)
 {
        INIT_LIST_HEAD(&fhn->fhn_node);
@@ -148,7 +85,7 @@ void fid_hash_add(struct list_head *head, unsigned int shift,
 {
        assert(!fhn_is_hashed(fhn));
 
-       list_add(&fhn->fhn_node, &head[fid_hash(&fhn->fhn_fid, shift)]);
+       list_add(&fhn->fhn_node, &head[llapi_fid_hash(&fhn->fhn_fid, shift)]);
 }
 
 struct fid_hash_node *
@@ -157,7 +94,7 @@ fid_hash_find(struct list_head *head, unsigned int shift, const struct lu_fid *f
        struct list_head *hash_list;
        struct fid_hash_node *fhn, *next;
 
-       hash_list = &head[fid_hash(fid, shift)];
+       hash_list = &head[llapi_fid_hash(fid, shift)];
        list_for_each_entry_safe(fhn, next, hash_list, fhn_node) {
                assert(fhn_is_hashed(fhn));
 
@@ -174,7 +111,7 @@ fid_hash_insert(struct list_head *head, unsigned int shift, struct fid_hash_node
        struct list_head *list;
        struct fid_hash_node *old_fhn, *next;
 
-       list = &head[fid_hash(&new_fhn->fhn_fid, shift)];
+       list = &head[llapi_fid_hash(&new_fhn->fhn_fid, shift)];
        list_for_each_entry_safe(old_fhn, next, list, fhn_node) {
                assert(fhn_is_hashed(old_fhn));
 
@@ -235,20 +172,21 @@ int fid_hash_resize(struct list_head **phead, unsigned int *pshift, unsigned int
        return 0;
 }
 
-enum {
+enum alr_rw {
        ALR_READ = 0,
        ALR_WRITE = 1,
+       ALR_RW_MAX
 };
 
 /* Entry in the batching hash. */
 struct alr_entry {
        struct fid_hash_node alre_fid_hash_node;
-       time_t alre_time[2]; /* Not strictly needed. */
-       __u64 alre_begin[2];
-       __u64 alre_end[2];
-       __u64 alre_size[2];
-       __u64 alre_segment_count[2];
-       __u64 alre_count[2];
+       time_t alre_time[ALR_RW_MAX]; /* Not strictly needed. */
+       __u64 alre_begin[ALR_RW_MAX];
+       __u64 alre_end[ALR_RW_MAX];
+       __u64 alre_size[ALR_RW_MAX];
+       __u64 alre_segment_count[ALR_RW_MAX];
+       __u64 alre_count[ALR_RW_MAX];
        char alre_obd_name[];
 };
 
@@ -271,7 +209,7 @@ static void alre_del_init(struct alr_entry *alre)
 static void alre_update(struct alr_entry *alre, time_t time, __u64 begin,
                        __u64 end, __u32 size, __u32 segment_count, __u32 flags)
 {
-       unsigned int d = (flags & OFD_ACCESS_READ) ? ALR_READ : ALR_WRITE;
+       enum alr_rw d = (flags & OFD_ACCESS_READ) ? ALR_READ : ALR_WRITE;
 
        alre->alre_time[d] = max_t(time_t, alre->alre_time[d], time);
        alre->alre_begin[d] = min_t(__u64, alre->alre_begin[d], begin);
@@ -332,7 +270,7 @@ int sort_compare(const void *a1, const void *a2)
        return 0;
 }
 
-static void alre_printf(FILE *f, struct alr_entry *alre, int d)
+static void alre_printf(FILE *f, struct alr_entry *alre, enum alr_rw d)
 {
        fprintf(f, "o=%s f="DFID" t=%lld b=%llu e=%llu s=%llu g=%llu n=%llu d=%c\n",
                alre->alre_obd_name,
@@ -353,19 +291,21 @@ struct alr_thread_arg {
        pthread_mutex_t *file_mutex;
 };
 
-void *alr_sort_and_print_thread(void *arg)
+/* Fraction < 100 */
+static void *alr_sort_and_print_thread(void *arg)
 {
        struct alr_entry *alre, *next;
        struct alr_thread_arg *aa = arg;
        struct list_head *tmp = &aa->list;
        int *sa = NULL;
-       int rc, d, i, nr = 0;
+       int rc, i, nr = 0;
+       enum alr_rw d;
        unsigned long cut;
 
        list_for_each_entry(alre, tmp, alre_fid_hash_node.fhn_node) {
-               if (alre->alre_count[0] > 0)
+               if (alre->alre_count[ALR_READ] > 0)
                        nr++;
-               if (alre->alre_count[1] > 0)
+               if (alre->alre_count[ALR_WRITE] > 0)
                        nr++;
        }
 
@@ -380,14 +320,15 @@ void *alr_sort_and_print_thread(void *arg)
 
        i = 0;
        list_for_each_entry(alre, tmp, alre_fid_hash_node.fhn_node) {
-               if (alre->alre_count[0] > 0)
-                       sa[i++] = alre->alre_count[0];
-               if (alre->alre_count[1] > 0)
-                       sa[i++] = alre->alre_count[1];
+               if (alre->alre_count[ALR_READ] > 0)
+                       sa[i++] = alre->alre_count[ALR_READ];
+               if (alre->alre_count[ALR_WRITE] > 0)
+                       sa[i++] = alre->alre_count[ALR_WRITE];
        }
 
        qsort(sa, nr, sizeof(*sa), sort_compare);
        i = nr * aa->fraction / 100;
+
        cut = sa[i];
        if (cut < 1)
                cut = 1;
@@ -408,7 +349,7 @@ void *alr_sort_and_print_thread(void *arg)
         * XXX: possible optimization - move items=@cut to another list, so
         * that 2nd pass takes < O(n) */
        list_for_each_entry(alre, tmp, alre_fid_hash_node.fhn_node) {
-               for (d = 0; d < 2; d++) {
+               for (d = 0; d < ALR_RW_MAX; d++) {
                        if (alre->alre_count[d] <= cut)
                                continue;
                        alre_printf(aa->file, alre, d);
@@ -417,7 +358,7 @@ void *alr_sort_and_print_thread(void *arg)
        }
 
        list_for_each_entry(alre, tmp, alre_fid_hash_node.fhn_node) {
-               for (d = 0; d < 2 && i > 0; d++) {
+               for (d = 0; d < ALR_RW_MAX && i > 0; d++) {
                        if (alre->alre_count[d] != cut)
                                continue;
                        alre_printf(aa->file, alre, d);
@@ -445,6 +386,48 @@ out:
        return NULL;
 }
 
+/* Fraction == 100 */
+static void *alr_print_thread_fraction_100(void *arg)
+{
+       struct alr_entry *alre, *next;
+       struct alr_thread_arg *aa = arg;
+       int rc;
+
+       /* Prevent jumbled output from multiple concurrent sort and
+        * print threads. */
+       rc = pthread_mutex_lock(aa->file_mutex);
+       if (rc != 0) {
+               fprintf(stderr, "cannot lock batch file: %s\n", strerror(rc));
+               exit(1);
+       }
+
+       list_for_each_entry(alre, &aa->list, alre_fid_hash_node.fhn_node) {
+               enum alr_rw d;
+
+               for (d = 0; d < ALR_RW_MAX; d++) {
+                       if (alre->alre_count[d] != 0)
+                               alre_printf(aa->file, alre, d);
+               }
+       }
+
+       rc = pthread_mutex_unlock(aa->file_mutex);
+       if (rc != 0) {
+               fprintf(stderr, "cannot unlock batch file: %s\n", strerror(rc));
+               exit(1);
+       }
+
+       fflush(aa->file);
+
+       list_for_each_entry_safe(alre, next, &aa->list, alre_fid_hash_node.fhn_node) {
+               alre_del_init(alre);
+               free(alre);
+       }
+
+       free(aa);
+
+       return NULL;
+}
+
 /* Print, clear, and resize the batch. */
 int alr_batch_print(struct alr_batch *alrb, FILE *file,
                    pthread_mutex_t *file_mutex, int fraction)
@@ -486,7 +469,11 @@ int alr_batch_print(struct alr_batch *alrb, FILE *file,
 
        /* as sorting may take time and we don't want to lose access
         * records we better do sorting and printing in a different thread */
-       rc = pthread_create(&pid, pattr, &alr_sort_and_print_thread, aa);
+
+       if (fraction >= 100) /* Print all 100% records */
+               rc = pthread_create(&pid, pattr, &alr_print_thread_fraction_100, aa);
+       else
+               rc = pthread_create(&pid, pattr, &alr_sort_and_print_thread, aa);
        if (rc != 0)
                goto out;