+/*
+ * If the given index is behind of statahead window more than
+ * SA_OMITTED_ENTRY_MAX, then it is old.
+ */
+static inline int is_omitted_entry(struct ll_statahead_info *sai, __u64 index)
+{
+ return ((__u64)sai->sai_max + index + SA_OMITTED_ENTRY_MAX <
+ sai->sai_index);
+}
+
+/*
+ * Insert it into sai_entries_sent tail when init.
+ */
+static struct ll_sa_entry *
+ll_sa_entry_alloc(struct ll_statahead_info *sai, __u64 index,
+ const char *name, int len)
+{
+ struct ll_inode_info *lli;
+ struct ll_sa_entry *entry;
+ int entry_size;
+ char *dname;
+ ENTRY;
+
+ entry_size = sizeof(struct ll_sa_entry) + (len & ~3) + 4;
+ OBD_ALLOC(entry, entry_size);
+ if (unlikely(entry == NULL))
+ RETURN(ERR_PTR(-ENOMEM));
+
+ CDEBUG(D_READA, "alloc sai entry %.*s(%p) index "LPU64"\n",
+ len, name, entry, index);
+
+ entry->se_index = index;
+
+ /*
+ * Statahead entry reference rules:
+ *
+ * 1) When statahead entry is initialized, its reference is set as 2.
+ * One reference is used by the directory scanner. When the scanner
+ * searches the statahead cache for the given name, it can perform
+ * lockless hash lookup (only the scanner can remove entry from hash
+ * list), and once found, it needn't to call "atomic_inc()" for the
+ * entry reference. So the performance is improved. After using the
+ * statahead entry, the scanner will call "atomic_dec()" to drop the
+ * reference held when initialization. If it is the last reference,
+ * the statahead entry will be freed.
+ *
+ * 2) All other threads, including statahead thread and ptlrpcd thread,
+ * when they process the statahead entry, the reference for target
+ * should be held to guarantee the entry will not be released by the
+ * directory scanner. After processing the entry, these threads will
+ * drop the entry reference. If it is the last reference, the entry
+ * will be freed.
+ *
+ * The second reference when initializes the statahead entry is used
+ * by the statahead thread, following the rule 2).
+ */
+ cfs_atomic_set(&entry->se_refcount, 2);
+ entry->se_stat = SA_ENTRY_INIT;
+ entry->se_size = entry_size;
+ dname = (char *)entry + sizeof(struct ll_sa_entry);
+ memcpy(dname, name, len);
+ dname[len] = 0;
+ entry->se_qstr.hash = full_name_hash(name, len);
+ entry->se_qstr.len = len;
+ entry->se_qstr.name = dname;
+
+ lli = ll_i2info(sai->sai_inode);
+ cfs_spin_lock(&lli->lli_sa_lock);
+ cfs_list_add_tail(&entry->se_list, &sai->sai_entries_sent);
+ cfs_spin_unlock(&lli->lli_sa_lock);
+
+ cfs_atomic_inc(&sai->sai_cache_count);
+ ll_sa_entry_enhash(sai, entry);
+
+ RETURN(entry);
+}
+
+/*
+ * Used by the directory scanner to search entry with name.
+ *
+ * Only the caller can remove the entry from hash, so it is unnecessary to hold
+ * hash lock. It is caller's duty to release the init refcount on the entry, so
+ * it is also unnecessary to increase refcount on the entry.