179 lines
4.0 KiB
C
179 lines
4.0 KiB
C
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
/*
|
|
* Copyright (C) 2018 HUAWEI, Inc.
|
|
* https://www.huawei.com/
|
|
*/
|
|
#ifndef __EROFS_FS_ZDATA_H
|
|
#define __EROFS_FS_ZDATA_H
|
|
|
|
#include "internal.h"
|
|
#include "tagptr.h"
|
|
|
|
#define Z_EROFS_PCLUSTER_MAX_PAGES (Z_EROFS_PCLUSTER_MAX_SIZE / PAGE_SIZE)
|
|
#define Z_EROFS_INLINE_BVECS 2
|
|
|
|
/*
|
|
* let's leave a type here in case of introducing
|
|
* another tagged pointer later.
|
|
*/
|
|
typedef void *z_erofs_next_pcluster_t;
|
|
|
|
struct z_erofs_bvec {
|
|
struct page *page;
|
|
int offset;
|
|
unsigned int end;
|
|
};
|
|
|
|
#define __Z_EROFS_BVSET(name, total) \
|
|
struct name { \
|
|
/* point to the next page which contains the following bvecs */ \
|
|
struct page *nextpage; \
|
|
struct z_erofs_bvec bvec[total]; \
|
|
}
|
|
__Z_EROFS_BVSET(z_erofs_bvset,);
|
|
__Z_EROFS_BVSET(z_erofs_bvset_inline, Z_EROFS_INLINE_BVECS);
|
|
|
|
/*
|
|
* Structure fields follow one of the following exclusion rules.
|
|
*
|
|
* I: Modifiable by initialization/destruction paths and read-only
|
|
* for everyone else;
|
|
*
|
|
* L: Field should be protected by the pcluster lock;
|
|
*
|
|
* A: Field should be accessed / updated in atomic for parallelized code.
|
|
*/
|
|
struct z_erofs_pcluster {
|
|
struct erofs_workgroup obj;
|
|
struct mutex lock;
|
|
|
|
/* A: point to next chained pcluster or TAILs */
|
|
z_erofs_next_pcluster_t next;
|
|
|
|
/* L: the maximum decompression size of this round */
|
|
unsigned int length;
|
|
|
|
/* L: total number of bvecs */
|
|
unsigned int vcnt;
|
|
|
|
/* I: page offset of start position of decompression */
|
|
unsigned short pageofs_out;
|
|
|
|
/* I: page offset of inline compressed data */
|
|
unsigned short pageofs_in;
|
|
|
|
union {
|
|
/* L: inline a certain number of bvec for bootstrap */
|
|
struct z_erofs_bvset_inline bvset;
|
|
|
|
/* I: can be used to free the pcluster by RCU. */
|
|
struct rcu_head rcu;
|
|
};
|
|
|
|
union {
|
|
/* I: physical cluster size in pages */
|
|
unsigned short pclusterpages;
|
|
|
|
/* I: tailpacking inline compressed size */
|
|
unsigned short tailpacking_size;
|
|
};
|
|
|
|
/* I: compression algorithm format */
|
|
unsigned char algorithmformat;
|
|
|
|
/* L: whether partial decompression or not */
|
|
bool partial;
|
|
|
|
/* L: indicate several pageofs_outs or not */
|
|
bool multibases;
|
|
|
|
/* A: compressed bvecs (can be cached or inplaced pages) */
|
|
struct z_erofs_bvec compressed_bvecs[];
|
|
};
|
|
|
|
/* let's avoid the valid 32-bit kernel addresses */
|
|
|
|
/* the chained workgroup has't submitted io (still open) */
|
|
#define Z_EROFS_PCLUSTER_TAIL ((void *)0x5F0ECAFE)
|
|
/* the chained workgroup has already submitted io */
|
|
#define Z_EROFS_PCLUSTER_TAIL_CLOSED ((void *)0x5F0EDEAD)
|
|
|
|
#define Z_EROFS_PCLUSTER_NIL (NULL)
|
|
|
|
struct z_erofs_decompressqueue {
|
|
struct super_block *sb;
|
|
atomic_t pending_bios;
|
|
z_erofs_next_pcluster_t head;
|
|
|
|
union {
|
|
struct completion done;
|
|
struct work_struct work;
|
|
} u;
|
|
|
|
bool eio;
|
|
};
|
|
|
|
static inline bool z_erofs_is_inline_pcluster(struct z_erofs_pcluster *pcl)
|
|
{
|
|
return !pcl->obj.index;
|
|
}
|
|
|
|
static inline unsigned int z_erofs_pclusterpages(struct z_erofs_pcluster *pcl)
|
|
{
|
|
if (z_erofs_is_inline_pcluster(pcl))
|
|
return 1;
|
|
return pcl->pclusterpages;
|
|
}
|
|
|
|
/*
|
|
* bit 30: I/O error occurred on this page
|
|
* bit 0 - 29: remaining parts to complete this page
|
|
*/
|
|
#define Z_EROFS_PAGE_EIO (1 << 30)
|
|
|
|
static inline void z_erofs_onlinepage_init(struct page *page)
|
|
{
|
|
union {
|
|
atomic_t o;
|
|
unsigned long v;
|
|
} u = { .o = ATOMIC_INIT(1) };
|
|
|
|
set_page_private(page, u.v);
|
|
smp_wmb();
|
|
SetPagePrivate(page);
|
|
}
|
|
|
|
static inline void z_erofs_onlinepage_split(struct page *page)
|
|
{
|
|
atomic_inc((atomic_t *)&page->private);
|
|
}
|
|
|
|
static inline void z_erofs_page_mark_eio(struct page *page)
|
|
{
|
|
int orig;
|
|
|
|
do {
|
|
orig = atomic_read((atomic_t *)&page->private);
|
|
} while (atomic_cmpxchg((atomic_t *)&page->private, orig,
|
|
orig | Z_EROFS_PAGE_EIO) != orig);
|
|
}
|
|
|
|
static inline void z_erofs_onlinepage_endio(struct page *page)
|
|
{
|
|
unsigned int v;
|
|
|
|
DBG_BUGON(!PagePrivate(page));
|
|
v = atomic_dec_return((atomic_t *)&page->private);
|
|
if (!(v & ~Z_EROFS_PAGE_EIO)) {
|
|
set_page_private(page, 0);
|
|
ClearPagePrivate(page);
|
|
if (!(v & Z_EROFS_PAGE_EIO))
|
|
SetPageUptodate(page);
|
|
unlock_page(page);
|
|
}
|
|
}
|
|
|
|
#define Z_EROFS_ONSTACK_PAGES 32
|
|
|
|
#endif
|