1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
|
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2022-2024 Oracle.
* All rights reserved.
*/
#include "xfs.h"
#include "xfs_fs.h"
#include "xfs_format.h"
#include "xfs_da_format.h"
#include "xfs_log_format.h"
#include "xfs_shared.h"
#include "xfs_trans_resv.h"
#include "xfs_mount.h"
#include "xfs_bmap_btree.h"
#include "xfs_inode.h"
#include "xfs_error.h"
#include "xfs_trace.h"
#include "xfs_trans.h"
#include "xfs_da_btree.h"
#include "xfs_attr.h"
#include "xfs_dir2.h"
#include "xfs_dir2_priv.h"
#include "xfs_attr_sf.h"
#include "xfs_bmap.h"
#include "xfs_defer.h"
#include "xfs_log.h"
#include "xfs_xattr.h"
#include "xfs_parent.h"
#include "xfs_trans_space.h"
/*
* Parent pointer attribute handling.
*
* Because the attribute name is a filename component, it will never be longer
* than 255 bytes and must not contain nulls or slashes. These are roughly the
* same constraints that apply to attribute names.
*
* The attribute value must always be a struct xfs_parent_rec. This means the
* attribute will never be in remote format because 12 bytes is nowhere near
* xfs_attr_leaf_entsize_local_max() (~75% of block size).
*
* Creating a new parent attribute will always create a new attribute - there
* should never, ever be an existing attribute in the tree for a new inode.
* ENOSPC behavior is problematic - creating the inode without the parent
* pointer is effectively a corruption, so we allow parent attribute creation
* to dip into the reserve block pool to avoid unexpected ENOSPC errors from
* occurring.
*/
/* Return true if parent pointer attr name is valid. */
bool
xfs_parent_namecheck(
unsigned int attr_flags,
const void *name,
size_t length)
{
/*
* Parent pointers always use logged operations, so there should never
* be incomplete xattrs.
*/
if (attr_flags & XFS_ATTR_INCOMPLETE)
return false;
return xfs_dir2_namecheck(name, length);
}
/* Return true if parent pointer attr value is valid. */
bool
xfs_parent_valuecheck(
struct xfs_mount *mp,
const void *value,
size_t valuelen)
{
const struct xfs_parent_rec *rec = value;
if (!xfs_has_parent(mp))
return false;
/* The xattr value must be a parent record. */
if (valuelen != sizeof(struct xfs_parent_rec))
return false;
/* The parent record must be local. */
if (value == NULL)
return false;
/* The parent inumber must be valid. */
if (!xfs_verify_dir_ino(mp, be64_to_cpu(rec->p_ino)))
return false;
return true;
}
/* Compute the attribute name hash for a parent pointer. */
xfs_dahash_t
xfs_parent_hashval(
struct xfs_mount *mp,
const uint8_t *name,
int namelen,
xfs_ino_t parent_ino)
{
struct xfs_name xname = {
.name = name,
.len = namelen,
};
/*
* Use the same dirent name hash as would be used on the directory, but
* mix in the parent inode number to avoid collisions on hardlinked
* files with identical names but different parents.
*/
return xfs_dir2_hashname(mp, &xname) ^
upper_32_bits(parent_ino) ^ lower_32_bits(parent_ino);
}
/* Compute the attribute name hash from the xattr components. */
xfs_dahash_t
xfs_parent_hashattr(
struct xfs_mount *mp,
const uint8_t *name,
int namelen,
const void *value,
int valuelen)
{
const struct xfs_parent_rec *rec = value;
/* Requires a local attr value in xfs_parent_rec format */
if (valuelen != sizeof(struct xfs_parent_rec)) {
ASSERT(valuelen == sizeof(struct xfs_parent_rec));
return 0;
}
if (!value) {
ASSERT(value != NULL);
return 0;
}
return xfs_parent_hashval(mp, name, namelen, be64_to_cpu(rec->p_ino));
}
|