typedef int filler_t(void *, struct page *);
+pgoff_t page_cache_next_hole(struct address_space *mapping,
+ pgoff_t index, unsigned long max_scan);
+
extern struct page * find_get_page(struct address_space *mapping,
pgoff_t index);
extern struct page * find_lock_page(struct address_space *mapping,
return 0;
}
-/*
+/*
* Wait for a page to be unlocked.
*
* This must be called with the caller "holding" the page,
wait_on_page_bit(page, PG_locked);
}
-/*
+/*
* Wait for a page to complete writeback
*/
static inline void wait_on_page_writeback(struct page *page)
TP_ARGS(page)
);
+DECLARE_EVENT_CLASS(mm_filemap_find_page_cache_miss,
+
+ TP_PROTO(struct file *file, loff_t pos, size_t count, int read),
+
+ TP_ARGS(file, pos, count, read),
+
+ TP_STRUCT__entry(
+ __array(char, path, MAX_FILTER_STR_VAL)
+ __field(char *, path_name)
+ __field(loff_t, pos)
+ __field(size_t, count)
+ __field(int, miss)
+ ),
+
+ TP_fast_assign(
+ __entry->path_name = d_path(&file->f_path, __entry->path, MAX_FILTER_STR_VAL);
+ __entry->pos = pos;
+ __entry->count = count;
+ __entry->miss = 0;
+ if ((pos & ~PAGE_CACHE_MASK) || (count % PAGE_SIZE) || read) {
+ unsigned long ret;
+ rcu_read_lock();
+ ret = (count ? page_cache_next_hole(file->f_mapping,
+ (pos >> PAGE_CACHE_SHIFT), ((count - 1) >> PAGE_CACHE_SHIFT) + 1) : 0);
+ rcu_read_unlock();
+ __entry->miss = (ret >= (pos >> PAGE_CACHE_SHIFT) &&
+ ret <= ((pos + count - 1) >> PAGE_CACHE_SHIFT));
+ }
+ ),
+
+ TP_printk("path_name %s pos %lld count %lu miss %s",
+ __entry->path_name,
+ __entry->pos, __entry->count,
+ (__entry->miss ? "yes" : "no"))
+);
+
+DEFINE_EVENT(mm_filemap_find_page_cache_miss, mm_filemap_do_generic_file_read,
+ TP_PROTO(struct file *file, loff_t pos, size_t count, int read),
+ TP_ARGS(file, pos, count, read)
+ );
+
+DEFINE_EVENT(mm_filemap_find_page_cache_miss, mm_filemap_generic_perform_write,
+ TP_PROTO(struct file *file, loff_t pos, size_t count, int read),
+ TP_ARGS(file, pos, count, read)
+ );
+
#endif /* _TRACE_FILEMAP_H */
/* This part must be outside protection */
}
}
+/**
+ * page_cache_next_hole - find the next hole (not-present entry)
+ * @mapping: mapping
+ * @index: index
+ * @max_scan: maximum range to search
+ *
+ * Search the set [index, min(index+max_scan-1, MAX_INDEX)] for the
+ * lowest indexed hole.
+ *
+ * Returns: the index of the hole if found, otherwise returns an index
+ * outside of the set specified (in which case 'return - index >=
+ * max_scan' will be true). In rare cases of index wrap-around, 0 will
+ * be returned.
+ *
+ * page_cache_next_hole may be called under rcu_read_lock. However,
+ * like radix_tree_gang_lookup, this will not atomically search a
+ * snapshot of the tree at a single point in time. For example, if a
+ * hole is created at index 5, then subsequently a hole is created at
+ * index 10, page_cache_next_hole covering both indexes may return 10
+ * if called under rcu_read_lock.
+ */
+pgoff_t page_cache_next_hole(struct address_space *mapping,
+ pgoff_t index, unsigned long max_scan)
+{
+ unsigned long i;
+
+ for (i = 0; i < max_scan; i++) {
+ struct page *page;
+
+ page = radix_tree_lookup(&mapping->page_tree, index);
+ if (!page || radix_tree_exceptional_entry(page))
+ break;
+ index++;
+ if (index == 0)
+ break;
+ }
+
+ return index;
+}
+EXPORT_SYMBOL(page_cache_next_hole);
+
/**
* find_get_page - find and get a page reference
* @mapping: the address_space to search
unsigned int prev_offset;
int error;
+ trace_mm_filemap_do_generic_file_read(filp, *ppos, desc->count, 1);
+
index = *ppos >> PAGE_CACHE_SHIFT;
prev_index = ra->prev_pos >> PAGE_CACHE_SHIFT;
prev_offset = ra->prev_pos & (PAGE_CACHE_SIZE-1);
static int page_cache_read(struct file *file, pgoff_t offset)
{
struct address_space *mapping = file->f_mapping;
- struct page *page;
+ struct page *page;
int ret;
do {
page_cache_release(page);
} while (ret == AOP_TRUNCATED_PAGE);
-
+
return ret;
}
ssize_t written = 0;
unsigned int flags = 0;
+ trace_mm_filemap_generic_perform_write(file, pos, iov_iter_count(i), 0);
+
/*
* Copies from kernel address space cannot fail (NFSD is a big user).
*/
written += status;
*ppos = pos + status;
}
-
+
return written ? written : status;
}
EXPORT_SYMBOL(generic_file_buffered_write);