#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;
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);
{
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 *
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));
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));
static void alre_printf(FILE *f, struct alr_entry *alre, int d)
{
- fprintf(f, "%s "DFID" %lld %llu %llu %llu %llu %llu %c\n",
+ 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,
PFID(&alre->alre_fid_hash_node.fhn_fid),
(long long)alre->alre_time[d],
struct list_head list;
int fraction;
FILE *file;
+ pthread_mutex_t *file_mutex;
};
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, d, i, nr = 0;
+ int *sa = NULL;
+ int rc, d, i, nr = 0;
unsigned long cut;
list_for_each_entry(alre, tmp, alre_fid_hash_node.fhn_node) {
if (alre->alre_count[1] > 0)
nr++;
}
- if (nr) {
- sa = calloc(sizeof(int), nr);
- if (!sa) {
- fprintf(stderr, "cannot allocate memory for sorting\n");
- exit(1);
- }
- 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];
- }
- qsort(sa, nr, sizeof(int), sort_compare);
- i = nr * aa->fraction / 100;
- if (i > 0)
+
+ if (nr == 0)
+ goto out;
+
+ sa = calloc(nr, sizeof(*sa));
+ if (!sa) {
+ fprintf(stderr, "cannot allocate memory for sorting\n");
+ exit(1);
+ }
+
+ 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];
+ }
+
+ qsort(sa, nr, sizeof(*sa), sort_compare);
+ i = nr * aa->fraction / 100;
+ cut = sa[i];
+ if (cut < 1)
+ cut = 1;
+ free(sa);
+
+ /* 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);
+ }
+
+ /* there might be lots of items at @cut, but we want to limit total
+ * output. so the first loop dumps all items > @cut and the second
+ * loop dumps items=@cut so that total number (@i) is not exceeeded.
+ * 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++) {
+ if (alre->alre_count[d] <= cut)
+ continue;
+ alre_printf(aa->file, alre, d);
i--;
- cut = sa[i];
- if (cut < 1)
- cut = 1;
- free(sa);
-
- /* there might be lots of items at @cut, but we want to limit total
- * output. so the first loop dumps all items > @cut and the second
- * loop dumps items=@cut so that total number (@i) is not exceeeded.
- * XXX: possible optimization - move items=@cut to another list, so
- * that 2nd pass takes < O(n) */
- list_for_each_entry_safe(alre, next, tmp, alre_fid_hash_node.fhn_node) {
- for (d = 0; d < 2; d++) {
- if (alre->alre_count[d] <= cut)
- continue;
- alre_printf(aa->file, alre, d);
- i--;
- }
}
- list_for_each_entry_safe(alre, next, tmp, alre_fid_hash_node.fhn_node) {
- for (d = 0; d < 2 && i > 0; d++) {
- if (alre->alre_count[d] != cut)
- continue;
- alre_printf(aa->file, alre, d);
- i--;
- }
- alre_del_init(alre);
- free(alre);
+ }
+
+ list_for_each_entry(alre, tmp, alre_fid_hash_node.fhn_node) {
+ for (d = 0; d < 2 && i > 0; d++) {
+ if (alre->alre_count[d] != cut)
+ continue;
+ alre_printf(aa->file, alre, d);
+ i--;
}
}
+ rc = pthread_mutex_unlock(aa->file_mutex);
+ if (rc != 0) {
+ fprintf(stderr, "cannot unlock batch file: %s\n",
+ strerror(rc));
+ exit(1);
+ }
+
+out:
+ fflush(aa->file);
+
+ list_for_each_entry_safe(alre, next, tmp, alre_fid_hash_node.fhn_node) {
+ alre_del_init(alre);
+ free(alre);
+ }
+
free(aa);
- pthread_exit((void *)0);
- return 0;
+ return NULL;
}
/* Print, clear, and resize the batch. */
-int alr_batch_print(struct alr_batch *alrb, FILE *file, int fraction)
+int alr_batch_print(struct alr_batch *alrb, FILE *file,
+ pthread_mutex_t *file_mutex, int fraction)
{
unsigned int new_hash_shift;
- struct alr_thread_arg *aa;
+ pthread_attr_t attr, *pattr = NULL;
+ struct alr_thread_arg *aa = NULL;
pthread_t pid;
int i, rc;
if (alrb == NULL)
return 0;
- aa = malloc(sizeof(*aa));
- if (!aa)
+ aa = calloc(1, sizeof(*aa));
+ if (aa == NULL)
return -ENOMEM;
/* move all collected items to the temp list */
INIT_LIST_HEAD(&alrb->alrb_hash[i]);
}
aa->file = file;
+ aa->file_mutex = file_mutex;
aa->fraction = fraction;
+ rc = pthread_attr_init(&attr);
+ if (rc != 0)
+ goto out;
+
+ pattr = &attr;
+
+ rc = pthread_attr_setdetachstate(pattr, PTHREAD_CREATE_DETACHED);
+ if (rc != 0)
+ goto out;
+
/* 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, NULL, alr_sort_and_print_thread, aa);
+ rc = pthread_create(&pid, pattr, &alr_sort_and_print_thread, aa);
+ if (rc != 0)
+ goto out;
+ aa = NULL; /* Sort and print thread owns it now. */
+out:
/* Resize hash based on previous count. */
new_hash_shift = alrb->alrb_hash_shift;
alrb->alrb_count = 0;
+ if (pattr != NULL)
+ pthread_attr_destroy(pattr);
+
+ if (aa != NULL) {
+ struct alr_entry *alre, *next;
+
+ list_for_each_entry_safe(alre, next, &aa->list,
+ alre_fid_hash_node.fhn_node) {
+ alre_del_init(alre);
+ free(alre);
+ }
+ }
+
+ free(aa);
+
+ if (rc > 0)
+ rc = -rc; /* Fixup pthread return conventions. */
+
return rc;
}