apfs: begin work on common xfield code

Define apfs_find_xfield() in the new xfield.c file; use it to replace
the ad hoc code that finds extended fields in inodes and dentries.
Creation of xfields will soon be moved to common code as well.

Signed-off-by: Ernesto A. Fernández <ernesto.mnd.fernandez@gmail.com>
This commit is contained in:
Ernesto A. Fernández committed 2019-10-18 23:23:32 -03:00
1 parent 4e12c07a30
commit b4a2effba1
6 files changed
+149 -98

No files matched your search

+1 -1
View File
@@ -7,4 +7,4 @@ obj-$(CONFIG_APFS_FS) += apfs.o
apfs-y := btree.o dir.o extents.o file.o inode.o key.o message.o namei.o \
node.o object.o spaceman.o super.o symlink.o transaction.o \
unicode.o xattr.o
unicode.o xattr.o xfield.o
+8 -11
View File
@@ -16,6 +16,7 @@
#include "node.h"
#include "super.h"
#include "transaction.h"
#include "xfield.h"
/**
* apfs_drec_from_query - Read the directory record found by a successful query
@@ -36,6 +37,8 @@ static int apfs_drec_from_query(struct apfs_query *query,
struct apfs_drec_hashed_key *de_key;
struct apfs_drec_val *de;
int namelen = query->key_len - sizeof(*de_key);
char *xval = NULL;
int xlen;
if (namelen < 1)
return -EFSCORRUPTED;
@@ -54,18 +57,12 @@ static int apfs_drec_from_query(struct apfs_query *query,
return -EFSCORRUPTED;
/* The dentry may have at most one xfield: the sibling id */
if (query->len == sizeof(*de)) {
drec->sibling_id = 0;
} else {
int x_meta_len;
__le64 *sib_id;
drec->sibling_id = 0;
xlen = apfs_find_xfield(de->xfields, query->len - sizeof(*de),
APFS_DREC_EXT_TYPE_SIBLING_ID, &xval);
if (xlen >= sizeof(__le64)) {
__le64 *sib_id = (__le64 *)xval;
x_meta_len = sizeof(struct apfs_xf_blob) +
sizeof(struct apfs_x_field);
if (query->len != sizeof(*de) + x_meta_len + sizeof(*sib_id))
return -EFSCORRUPTED;
sib_id = (void *)de->xfields + x_meta_len;
drec->sibling_id = le64_to_cpup(sib_id);
}
+20 -40
View File
@@ -18,6 +18,7 @@
#include "node.h"
#include "super.h"
#include "xattr.h"
#include "xfield.h"
static int apfs_readpage(struct file *file, struct page *page)
{
@@ -84,11 +85,9 @@ static int apfs_inode_from_query(struct apfs_query *query, struct inode *inode)
{
struct apfs_inode_info *ai = APFS_I(inode);
struct apfs_inode_val *inode_val;
struct apfs_dstream *dstream = NULL;
struct apfs_xf_blob *xblob;
struct apfs_x_field *xfield;
char *raw = query->node->object.bh->b_data;
int rest, i;
char *xval = NULL;
int xlen;
u32 rdev = 0;
if (query->len < sizeof(*inode_val))
@@ -121,45 +120,26 @@ static int apfs_inode_from_query(struct apfs_query *query, struct inode *inode)
inode->i_mtime = apfs_timespec(inode_val->mod_time);
ai->i_crtime = apfs_timespec(inode_val->create_time);
xblob = (struct apfs_xf_blob *) inode_val->xfields;
xfield = (struct apfs_x_field *) xblob->xf_data;
rest = query->len - (sizeof(*inode_val) + sizeof(*xblob));
rest -= le16_to_cpu(xblob->xf_num_exts) * sizeof(xfield[0]);
if (rest < 0)
goto corrupted;
for (i = 0; i < le16_to_cpu(xblob->xf_num_exts); ++i) {
int attrlen;
inode->i_size = inode->i_blocks = 0; /* TODO: compressed inodes */
xlen = apfs_find_xfield(inode_val->xfields,
query->len - sizeof(*inode_val),
APFS_INO_EXT_TYPE_DSTREAM, &xval);
if (xlen >= sizeof(struct apfs_dstream)) {
struct apfs_dstream *dstream = (struct apfs_dstream *)xval;
/* Attribute length is padded to a multiple of 8 */
attrlen = round_up(le16_to_cpu(xfield[i].x_size), 8);
if (attrlen > rest)
break;
/* These are the only xfields we care about, for now */
if (xfield[i].x_type == APFS_INO_EXT_TYPE_DSTREAM) {
dstream = (struct apfs_dstream *)
((char *)inode_val + query->len - rest);
break;
}
if (xfield[i].x_type == APFS_INO_EXT_TYPE_RDEV) {
__le32 *rdev_p = (void *)inode_val + query->len - rest;
rdev = le32_to_cpu(*rdev_p);
}
rest -= attrlen;
}
if (dstream) {
inode->i_size = le64_to_cpu(dstream->size);
inode->i_blocks = le64_to_cpu(dstream->alloced_size) >> 9;
} else {
/*
* This inode is "empty", but it may actually hold compressed
* data in the named attribute com.apple.decmpfs, and sometimes
* in com.apple.ResourceFork
*/
inode->i_size = inode->i_blocks = 0;
}
xval = NULL;
rdev = 0;
xlen = apfs_find_xfield(inode_val->xfields,
query->len - sizeof(*inode_val),
APFS_INO_EXT_TYPE_RDEV, &xval);
if (xlen >= sizeof(__le32)) {
__le32 *rdev_p = (__le32 *)xval;
rdev = le32_to_cpup(rdev_p);
}
apfs_inode_set_ops(inode, rdev);
-46
View File
@@ -49,52 +49,6 @@ struct apfs_inode_val {
/*5C*/ u8 xfields[];
} __packed;
/* Extended field types */
#define APFS_DREC_EXT_TYPE_SIBLING_ID 1
#define APFS_INO_EXT_TYPE_SNAP_XID 1
#define APFS_INO_EXT_TYPE_DELTA_TREE_OID 2
#define APFS_INO_EXT_TYPE_DOCUMENT_ID 3
#define APFS_INO_EXT_TYPE_NAME 4
#define APFS_INO_EXT_TYPE_PREV_FSIZE 5
#define APFS_INO_EXT_TYPE_RESERVED_6 6
#define APFS_INO_EXT_TYPE_FINDER_INFO 7
#define APFS_INO_EXT_TYPE_DSTREAM 8
#define APFS_INO_EXT_TYPE_RESERVED_9 9
#define APFS_INO_EXT_TYPE_DIR_STATS_KEY 10
#define APFS_INO_EXT_TYPE_FS_UUID 11
#define APFS_INO_EXT_TYPE_RESERVED_12 12
#define APFS_INO_EXT_TYPE_SPARSE_BYTES 13
#define APFS_INO_EXT_TYPE_RDEV 14
/* Extended field flags */
#define APFS_XF_DATA_DEPENDENT 0x01
#define APFS_XF_DO_NOT_COPY 0x02
#define APFS_XF_RESERVED_4 0x04
#define APFS_XF_CHILDREN_INHERIT 0x08
#define APFS_XF_USER_FIELD 0x10
#define APFS_XF_SYSTEM_FIELD 0x20
#define APFS_XF_RESERVED_40 0x40
#define APFS_XF_RESERVED_80 0x80
/*
* Structure used to store the number and size of extended fields of an inode
*/
struct apfs_xf_blob {
__le16 xf_num_exts;
__le16 xf_used_data;
u8 xf_data[];
} __packed;
/*
* Structure used to store an inode's extended field
*/
struct apfs_x_field {
u8 x_type;
u8 x_flags;
__le16 x_size;
} __packed;
/*
* Structure of a data stream record
*/
+58
View File
@@ -0,0 +1,58 @@
// SPDX-License-Identifier: GPL-2.0
/*
* linux/fs/apfs/xfield.c
*
* Copyright (C) 2019 Ernesto A. Fernández <ernesto.mnd.fernandez@gmail.com>
*/
#include <linux/kernel.h>
#include "xfield.h"
/**
* apfs_find_xfield - Find an extended field value in an inode or dentry record
* @xfields: pointer to the on-disk xfield collection for the record
* @len: length of the collection
* @xtype: type of the xfield to retrieve
* @xval: on return, a pointer to the wanted on-disk xfield value
*
* Returns the length of @xval on success, or 0 if no matching xfield was found;
* the caller must check that the expected structures fit before casting @xval.
*/
int apfs_find_xfield(u8 *xfields, int len, u8 xtype, char **xval)
{
struct apfs_xf_blob *blob;
struct apfs_x_field *xfield;
int count;
int rest = len;
int i;
if (!len)
return 0; /* No xfield data */
rest -= sizeof(*blob);
if (rest < 0)
return 0; /* Corruption */
blob = (struct apfs_xf_blob *)xfields;
count = le16_to_cpu(blob->xf_num_exts);
rest -= count * sizeof(*xfield);
if (rest < 0)
return 0; /* Corruption */
xfield = (struct apfs_x_field *)blob->xf_data;
for (i = 0; i < count; ++i) {
int xlen;
/* Attribute length is padded to a multiple of 8 */
xlen = round_up(le16_to_cpu(xfield[i].x_size), 8);
if (xlen > rest)
return 0; /* Corruption */
if (xfield[i].x_type == xtype) {
*xval = (char *)xfields + len - rest;
return xlen;
}
rest -= xlen;
}
return 0;
}
+62
View File
@@ -0,0 +1,62 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* linux/fs/apfs/xfield.h
*
* Copyright (C) 2019 Ernesto A. Fernández <ernesto.mnd.fernandez@gmail.com>
*/
#ifndef _APFS_XFIELD_H
#define _APFS_XFIELD_H
#include <linux/types.h>
/* Extended field types for dentries */
#define APFS_DREC_EXT_TYPE_SIBLING_ID 1
/* Extended field types for inodes */
#define APFS_INO_EXT_TYPE_SNAP_XID 1
#define APFS_INO_EXT_TYPE_DELTA_TREE_OID 2
#define APFS_INO_EXT_TYPE_DOCUMENT_ID 3
#define APFS_INO_EXT_TYPE_NAME 4
#define APFS_INO_EXT_TYPE_PREV_FSIZE 5
#define APFS_INO_EXT_TYPE_RESERVED_6 6
#define APFS_INO_EXT_TYPE_FINDER_INFO 7
#define APFS_INO_EXT_TYPE_DSTREAM 8
#define APFS_INO_EXT_TYPE_RESERVED_9 9
#define APFS_INO_EXT_TYPE_DIR_STATS_KEY 10
#define APFS_INO_EXT_TYPE_FS_UUID 11
#define APFS_INO_EXT_TYPE_RESERVED_12 12
#define APFS_INO_EXT_TYPE_SPARSE_BYTES 13
#define APFS_INO_EXT_TYPE_RDEV 14
/* Extended field flags */
#define APFS_XF_DATA_DEPENDENT 0x01
#define APFS_XF_DO_NOT_COPY 0x02
#define APFS_XF_RESERVED_4 0x04
#define APFS_XF_CHILDREN_INHERIT 0x08
#define APFS_XF_USER_FIELD 0x10
#define APFS_XF_SYSTEM_FIELD 0x20
#define APFS_XF_RESERVED_40 0x40
#define APFS_XF_RESERVED_80 0x80
/*
* Structure used to store the number and size of an xfield collection
*/
struct apfs_xf_blob {
__le16 xf_num_exts;
__le16 xf_used_data;
u8 xf_data[];
} __packed;
/*
* Structure used to describe an extended field
*/
struct apfs_x_field {
u8 x_type;
u8 x_flags;
__le16 x_size;
} __packed;
extern int apfs_find_xfield(u8 *xfields, int len, u8 xtype, char **xval);
#endif /* _APFS_XFIELD_H */