text: /*
   * GPL HEADER START
   *
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 only,
   * as published by the Free Software Foundation.
   *
   * This program is distributed in the hope that it will be useful, but
   * WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   * General Public License version 2 for more details (a copy is included
   * in the LICENSE file that accompanied this code).
   *
   * You should have received a copy of the GNU General Public License
   * version 2 along with this program; If not, see
   * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
   *
   * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   * CA 95054 USA or visit www.sun.com if you need additional information or
   * have any questions.
   *
   * GPL HEADER END
   */
  /*
   * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
   * Use is subject to license terms.
   *
   * Copyright (c) 2011, 2012, Intel Corporation.
   */
  /*
   * This file is part of Lustre, http://www.lustre.org/
   * Lustre is a trademark of Sun Microsystems, Inc.
   *
   * libcfs/include/libcfs/libcfs_private.h
   *
   * Various defines for libcfs.
   *
   */
  
  #ifndef __LIBCFS_PRIVATE_H__
  #define __LIBCFS_PRIVATE_H__
  
  #ifndef DEBUG_SUBSYSTEM
  # define DEBUG_SUBSYSTEM S_UNDEFINED
  #endif
  
  /*
   * When this is on, LASSERT macro includes check for assignment used instead
   * of equality check, but doesn't have unlikely(). Turn this on from time to
   * time to make test-builds. This shouldn't be on for production release.
   */
  #define LASSERT_CHECKED (0)
  
  #define LASSERTF(cond, fmt, ...)					\
  do {									\
  	if (unlikely(!(cond))) {					\
  		LIBCFS_DEBUG_MSG_DATA_DECL(__msg_data, D_EMERG, NULL);	\
  		libcfs_debug_msg(&__msg_data,				\
  				 "ASSERTION( %s ) failed: " fmt, #cond,	\
  				 ## __VA_ARGS__);			\
  		lbug_with_loc(&__msg_data);				\
  	}								\
  } while (0)
  
  #define LASSERT(cond) LASSERTF(cond, "\n")
  
  #ifdef CONFIG_LUSTRE_DEBUG_EXPENSIVE_CHECK
  /**
   * This is for more expensive checks that one doesn't want to be enabled all
   * the time. LINVRNT() has to be explicitly enabled by
   * CONFIG_LUSTRE_DEBUG_EXPENSIVE_CHECK option.
   */
  # define LINVRNT(exp) LASSERT(exp)
  #else
  # define LINVRNT(exp) ((void)sizeof !!(exp))
  #endif
  
  #define KLASSERT(e) LASSERT(e)
  
  void __noreturn lbug_with_loc(struct libcfs_debug_msg_data *);
  
  #define LBUG()							  \
  do {								    \
  	LIBCFS_DEBUG_MSG_DATA_DECL(msgdata, D_EMERG, NULL);	     \
  	lbug_with_loc(&msgdata);					\
  } while (0)
  
  #ifndef LIBCFS_VMALLOC_SIZE
  #define LIBCFS_VMALLOC_SIZE	(2 << PAGE_CACHE_SHIFT) /* 2 pages */
  #endif
  
  #define LIBCFS_ALLOC_PRE(size, mask)					    \
  do {									    \
  	LASSERT(!in_interrupt() ||					    \
  		((size) <= LIBCFS_VMALLOC_SIZE &&			    \
  		 !gfpflags_allow_blocking(mask)));			    \
  } while (0)
  
  #define LIBCFS_ALLOC_POST(ptr, size)					    \
  do {									    \
  	if (unlikely((ptr) == NULL)) {					    \
  		CERROR("LNET: out of memory at %s:%d (tried to alloc '"	    \
  		       #ptr "' = %d)\n", __FILE__, __LINE__, (int)(size));  \
  	} else {							    \
  		memset((ptr), 0, (size));				    \
  	}								    \
  } while (0)
  
  /**
   * allocate memory with GFP flags @mask
   */
  #define LIBCFS_ALLOC_GFP(ptr, size, mask)				    \
  do {									    \
  	LIBCFS_ALLOC_PRE((size), (mask));				    \
  	(ptr) = (size) <= LIBCFS_VMALLOC_SIZE ?				    \
  		kmalloc((size), (mask)) : vmalloc(size);	    \
  	LIBCFS_ALLOC_POST((ptr), (size));				    \
  } while (0)
  
  /**
   * default allocator
   */
  #define LIBCFS_ALLOC(ptr, size) \
  	LIBCFS_ALLOC_GFP(ptr, size, GFP_NOFS)
  
  /**
   * non-sleeping allocator
   */
  #define LIBCFS_ALLOC_ATOMIC(ptr, size) \
  	LIBCFS_ALLOC_GFP(ptr, size, GFP_ATOMIC)
  
  /**
   * allocate memory for specified CPU partition
   *   \a cptab != NULL, \a cpt is CPU partition id of \a cptab
   *   \a cptab == NULL, \a cpt is HW NUMA node id
   */
  #define LIBCFS_CPT_ALLOC_GFP(ptr, cptab, cpt, size, mask)		    \
  do {									    \
  	LIBCFS_ALLOC_PRE((size), (mask));				    \
  	(ptr) = (size) <= LIBCFS_VMALLOC_SIZE ?				    \
  		kmalloc_node((size), (mask), cfs_cpt_spread_node(cptab, cpt)) :\
  		vmalloc_node(size, cfs_cpt_spread_node(cptab, cpt));	    \
  	LIBCFS_ALLOC_POST((ptr), (size));				    \
  } while (0)
  
  /** default numa allocator */
  #define LIBCFS_CPT_ALLOC(ptr, cptab, cpt, size)				    \
  	LIBCFS_CPT_ALLOC_GFP(ptr, cptab, cpt, size, GFP_NOFS)
  
  #define LIBCFS_FREE(ptr, size)					  \
  do {								    \
  	if (unlikely((ptr) == NULL)) {				  \
  		CERROR("LIBCFS: free NULL '" #ptr "' (%d bytes) at "    \
  		       "%s:%d\n", (int)(size), __FILE__, __LINE__);	\
  		break;						  \
  	}							       \
  	kvfree(ptr);					  \
  } while (0)
  
  /******************************************************************************/
  
  /* htonl hack - either this, or compile with -O2. Stupid byteorder/generic.h */
  #if defined(__GNUC__) && (__GNUC__ >= 2) && !defined(__OPTIMIZE__)
  #define ___htonl(x) __cpu_to_be32(x)
  #define ___htons(x) __cpu_to_be16(x)
  #define ___ntohl(x) __be32_to_cpu(x)
  #define ___ntohs(x) __be16_to_cpu(x)
  #define htonl(x) ___htonl(x)
  #define ntohl(x) ___ntohl(x)
  #define htons(x) ___htons(x)
  #define ntohs(x) ___ntohs(x)
  #endif
  
  void libcfs_run_upcall(char **argv);
  void libcfs_run_lbug_upcall(struct libcfs_debug_msg_data *);
  void libcfs_debug_dumplog(void);
  int libcfs_debug_init(unsigned long bufsize);
  int libcfs_debug_cleanup(void);
  int libcfs_debug_clear_buffer(void);
  int libcfs_debug_mark_buffer(const char *text);
  
  /*
   * allocate per-cpu-partition data, returned value is an array of pointers,
   * variable can be indexed by CPU ID.
   *	cptable != NULL: size of array is number of CPU partitions
   *	cptable == NULL: size of array is number of HW cores
   */
  void *cfs_percpt_alloc(struct cfs_cpt_table *cptab, unsigned int size);
  /*
   * destroy per-cpu-partition variable
   */
  void  cfs_percpt_free(void *vars);
  int   cfs_percpt_number(void *vars);
  void *cfs_percpt_current(void *vars);
  void *cfs_percpt_index(void *vars, int idx);
  
  #define cfs_percpt_for_each(var, i, vars)		\
  	for (i = 0; i < cfs_percpt_number(vars) &&	\
  		    ((var) = (vars)[i]) != NULL; i++)
  
  /*
   * allocate a variable array, returned value is an array of pointers.
   * Caller can specify length of array by count.
   */
  void *cfs_array_alloc(int count, unsigned int size);
  void  cfs_array_free(void *vars);
  
  #define LASSERT_ATOMIC_ENABLED	  (1)
  
  #if LASSERT_ATOMIC_ENABLED
  
  /** assert value of @a is equal to @v */
  #define LASSERT_ATOMIC_EQ(a, v)				 \
  do {							    \
  	LASSERTF(atomic_read(a) == v,		       \
  		 "value: %d\n", atomic_read((a)));	  \
  } while (0)
  
  /** assert value of @a is unequal to @v */
  #define LASSERT_ATOMIC_NE(a, v)				 \
  do {							    \
  	LASSERTF(atomic_read(a) != v,		       \
  		 "value: %d\n", atomic_read((a)));	  \
  } while (0)
  
  /** assert value of @a is little than @v */
  #define LASSERT_ATOMIC_LT(a, v)				 \
  do {							    \
  	LASSERTF(atomic_read(a) < v,			\
  		 "value: %d\n", atomic_read((a)));	  \
  } while (0)
  
  /** assert value of @a is little/equal to @v */
  #define LASSERT_ATOMIC_LE(a, v)				 \
  do {							    \
  	LASSERTF(atomic_read(a) <= v,		       \
  		 "value: %d\n", atomic_read((a)));	  \
  } while (0)
  
  /** assert value of @a is great than @v */
  #define LASSERT_ATOMIC_GT(a, v)				 \
  do {							    \
  	LASSERTF(atomic_read(a) > v,			\
  		 "value: %d\n", atomic_read((a)));	  \
  } while (0)
  
  /** assert value of @a is great/equal to @v */
  #define LASSERT_ATOMIC_GE(a, v)				 \
  do {							    \
  	LASSERTF(atomic_read(a) >= v,		       \
  		 "value: %d\n", atomic_read((a)));	  \
  } while (0)
  
  /** assert value of @a is great than @v1 and little than @v2 */
  #define LASSERT_ATOMIC_GT_LT(a, v1, v2)			 \
  do {							    \
  	int __v = atomic_read(a);			   \
  	LASSERTF(__v > v1 && __v < v2, "value: %d\n", __v);     \
  } while (0)
  
  /** assert value of @a is great than @v1 and little/equal to @v2 */
  #define LASSERT_ATOMIC_GT_LE(a, v1, v2)			 \
  do {							    \
  	int __v = atomic_read(a);			   \
  	LASSERTF(__v > v1 && __v <= v2, "value: %d\n", __v);    \
  } while (0)
  
  /** assert value of @a is great/equal to @v1 and little than @v2 */
  #define LASSERT_ATOMIC_GE_LT(a, v1, v2)			 \
  do {							    \
  	int __v = atomic_read(a);			   \
  	LASSERTF(__v >= v1 && __v < v2, "value: %d\n", __v);    \
  } while (0)
  
  /** assert value of @a is great/equal to @v1 and little/equal to @v2 */
  #define LASSERT_ATOMIC_GE_LE(a, v1, v2)			 \
  do {							    \
  	int __v = atomic_read(a);			   \
  	LASSERTF(__v >= v1 && __v <= v2, "value: %d\n", __v);   \
  } while (0)
  
  #else /* !LASSERT_ATOMIC_ENABLED */
  
  #define LASSERT_ATOMIC_EQ(a, v)		 do {} while (0)
  #define LASSERT_ATOMIC_NE(a, v)		 do {} while (0)
  #define LASSERT_ATOMIC_LT(a, v)		 do {} while (0)
  #define LASSERT_ATOMIC_LE(a, v)		 do {} while (0)
  #define LASSERT_ATOMIC_GT(a, v)		 do {} while (0)
  #define LASSERT_ATOMIC_GE(a, v)		 do {} while (0)
  #define LASSERT_ATOMIC_GT_LT(a, v1, v2)	 do {} while (0)
  #define LASSERT_ATOMIC_GT_LE(a, v1, v2)	 do {} while (0)
  #define LASSERT_ATOMIC_GE_LT(a, v1, v2)	 do {} while (0)
  #define LASSERT_ATOMIC_GE_LE(a, v1, v2)	 do {} while (0)
  
  #endif /* LASSERT_ATOMIC_ENABLED */
  
  #define LASSERT_ATOMIC_ZERO(a)		  LASSERT_ATOMIC_EQ(a, 0)
  #define LASSERT_ATOMIC_POS(a)		   LASSERT_ATOMIC_GT(a, 0)
  
  #define CFS_ALLOC_PTR(ptr)      LIBCFS_ALLOC(ptr, sizeof(*(ptr)))
  #define CFS_FREE_PTR(ptr)       LIBCFS_FREE(ptr, sizeof(*(ptr)))
  
  /*
   * percpu partition lock
   *
   * There are some use-cases like this in Lustre:
   * . each CPU partition has it's own private data which is frequently changed,
   *   and mostly by the local CPU partition.
   * . all CPU partitions share some global data, these data are rarely changed.
   *
   * LNet is typical example.
   * CPU partition lock is designed for this kind of use-cases:
   * . each CPU partition has it's own private lock
   * . change on private data just needs to take the private lock
   * . read on shared data just needs to take _any_ of private locks
   * . change on shared data needs to take _all_ private locks,
   *   which is slow and should be really rare.
   */
  
  enum {
  	CFS_PERCPT_LOCK_EX	= -1, /* negative */
  };
  
  struct cfs_percpt_lock {
  	/* cpu-partition-table for this lock */
  	struct cfs_cpt_table	*pcl_cptab;
  	/* exclusively locked */
  	unsigned int		pcl_locked;
  	/* private lock table */
  	spinlock_t		**pcl_locks;
  };
  
  /* return number of private locks */
  static inline int
  cfs_percpt_lock_num(struct cfs_percpt_lock *pcl)
  {
  	return cfs_cpt_number(pcl->pcl_cptab);
  }
  
  /*
   * create a cpu-partition lock based on CPU partition table \a cptab,
   * each private lock has extra \a psize bytes padding data
   */
  struct cfs_percpt_lock *cfs_percpt_lock_alloc(struct cfs_cpt_table *cptab);
  /* destroy a cpu-partition lock */
  void cfs_percpt_lock_free(struct cfs_percpt_lock *pcl);
  
  /* lock private lock \a index of \a pcl */
  void cfs_percpt_lock(struct cfs_percpt_lock *pcl, int index);
  /* unlock private lock \a index of \a pcl */
  void cfs_percpt_unlock(struct cfs_percpt_lock *pcl, int index);
  /* create percpt (atomic) refcount based on @cptab */
  atomic_t **cfs_percpt_atomic_alloc(struct cfs_cpt_table *cptab, int val);
  /* destroy percpt refcount */
  void cfs_percpt_atomic_free(atomic_t **refs);
  /* return sum of all percpu refs */
  int cfs_percpt_atomic_summary(atomic_t **refs);
  
  /** Compile-time assertion.
  
   * Check an invariant described by a constant expression at compile time by
   * forcing a compiler error if it does not hold.  \a cond must be a constant
   * expression as defined by the ISO C Standard:
   *
   *       6.8.4.2  The switch statement
   *       ....
   *       [#3] The expression of each case label shall be  an  integer
   *       constant   expression  and  no  two  of  the  case  constant
   *       expressions in the same switch statement shall have the same
   *       value  after  conversion...
   *
   */
  #define CLASSERT(cond) do {switch (42) {case (cond): case 0: break; } } while (0)
  
  /* max value for numeric network address */
  #define MAX_NUMERIC_VALUE 0xffffffff
  
  /* implication */
  #define ergo(a, b) (!(a) || (b))
  /* logical equivalence */
  #define equi(a, b) (!!(a) == !!(b))
  
  /* --------------------------------------------------------------------
   * Light-weight trace
   * Support for temporary event tracing with minimal Heisenberg effect.
   * -------------------------------------------------------------------- */
  
  struct libcfs_device_userstate {
  	int	   ldu_memhog_pages;
  	struct page   *ldu_memhog_root_page;
  };
  
  #define MKSTR(ptr) ((ptr)) ? (ptr) : ""
  
  static inline int cfs_size_round4(int val)
  {
  	return (val + 3) & (~0x3);
  }
  
  #ifndef HAVE_CFS_SIZE_ROUND
  static inline int cfs_size_round(int val)
  {
  	return (val + 7) & (~0x7);
  }
  
  #define HAVE_CFS_SIZE_ROUND
  #endif
  
  static inline int cfs_size_round16(int val)
  {
  	return (val + 0xf) & (~0xf);
  }
  
  static inline int cfs_size_round32(int val)
  {
  	return (val + 0x1f) & (~0x1f);
  }
  
  static inline int cfs_size_round0(int val)
  {
  	if (!val)
  		return 0;
  	return (val + 1 + 7) & (~0x7);
  }
  
  static inline size_t cfs_round_strlen(char *fset)
  {
  	return (size_t)cfs_size_round((int)strlen(fset) + 1);
  }
  
  #define LOGL(var, len, ptr)				       \
  do {							    \
  	if (var)						\
  		memcpy((char *)ptr, (const char *)var, len);    \
  	ptr += cfs_size_round(len);			     \
  } while (0)
  
  #define LOGU(var, len, ptr)				       \
  do {							    \
  	if (var)						\
  		memcpy((char *)var, (const char *)ptr, len);    \
  	ptr += cfs_size_round(len);			     \
  } while (0)
  
  #define LOGL0(var, len, ptr)			      \
  do {						    \
  	if (!len)				       \
  		break;				  \
  	memcpy((char *)ptr, (const char *)var, len);    \
  	*((char *)(ptr) + len) = 0;		     \
  	ptr += cfs_size_round(len + 1);		 \
  } while (0)
  
  #endif
  