-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinode.h
397 lines (318 loc) · 10.4 KB
/
inode.h
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
#ifndef __INODE_H
#define __INODE_H
struct nova_inode_info_header;
struct nova_inode;
#include "super.h"
#include "log.h"
enum nova_new_inode_type {
TYPE_CREATE = 0,
TYPE_MKNOD,
TYPE_SYMLINK,
TYPE_MKDIR
};
/*
* Structure of an inode in PMEM
* Keep the inode size to within 120 bytes: We use the last eight bytes
* as inode table tail pointer.
*/
struct nova_inode {
/* first 40 bytes */
u8 i_rsvd; /* reserved. used to be checksum */
u8 valid; /* Is this inode valid? */
u8 deleted; /* Is this inode deleted? */
u8 i_blk_type; /* data block size this inode uses */
__le32 i_flags; /* Inode flags */
__le64 i_size; /* Size of data in bytes */
__le32 i_ctime; /* Inode modification time */
__le32 i_mtime; /* Inode b-tree Modification time */
__le32 i_atime; /* Access time */
__le16 i_mode; /* File mode */
__le16 i_links_count; /* Links count */
__le64 i_xattr; /* Extended attribute block */
/* second 40 bytes */
__le32 i_uid; /* Owner Uid */
__le32 i_gid; /* Group Id */
__le32 i_generation; /* File version (for NFS) */
__le32 i_create_time; /* Create time */
__le64 nova_ino; /* nova inode number */
__le64 log_head; /* Log head pointer */
__le64 log_tail; /* Log tail pointer */
/* last 40 bytes */
__le64 alter_log_head; /* Alternate log head pointer */
__le64 alter_log_tail; /* Alternate log tail pointer */
__le64 create_epoch_id; /* Transaction ID when create */
__le64 delete_epoch_id; /* Transaction ID when deleted */
struct {
__le32 rdev; /* major/minor # */
} dev; /* device inode */
__le32 csum; /* CRC32 checksum */
/* Leave 8 bytes for inode table tail pointer */
} __attribute((__packed__));
/*
* Inode table. It's a linked list of pages.
*/
struct inode_table {
__le64 log_head;
};
/*
* NOVA-specific inode state kept in DRAM
*/
struct nova_inode_info_header {
/* Map from file offsets to write log entries. */
struct radix_tree_root tree;
struct rb_root rb_tree; /* RB tree for directory */
struct rb_root vma_tree; /* Write vmas */
struct list_head list; /* SB list of mmap sih */
int num_vmas;
unsigned short i_mode; /* Dir or file? */
unsigned int i_flags;
unsigned long log_pages; /* Num of log pages */
unsigned long i_size;
unsigned long i_blocks;
unsigned long ino;
unsigned long pi_addr;
unsigned long alter_pi_addr;
unsigned long valid_entries; /* For thorough GC */
unsigned long num_entries; /* For thorough GC */
u64 last_setattr; /* Last setattr entry */
u64 last_link_change; /* Last link change entry */
u64 last_dentry; /* Last updated dentry */
u64 trans_id; /* Transaction ID */
u64 log_head; /* Log head pointer */
u64 log_tail; /* Log tail pointer */
u64 alter_log_head; /* Alternate log head pointer */
u64 alter_log_tail; /* Alternate log tail pointer */
u8 i_blk_type;
bool set_advise; /* Set file advise */
};
/* For rebuild purpose, temporarily store pi infomation */
struct nova_inode_rebuild {
u64 i_size;
u32 i_flags; /* Inode flags */
u32 i_ctime; /* Inode modification time */
u32 i_mtime; /* Inode b-tree Modification time */
u32 i_atime; /* Access time */
u32 i_uid; /* Owner Uid */
u32 i_gid; /* Group Id */
u32 i_generation; /* File version (for NFS) */
u16 i_links_count; /* Links count */
u16 i_mode; /* File mode */
u64 trans_id;
};
/*
* DRAM state for inodes
*/
struct nova_inode_info {
struct nova_inode_info_header header;
struct inode vfs_inode;
};
static inline struct nova_inode_info *NOVA_I(struct inode *inode)
{
return container_of(inode, struct nova_inode_info, vfs_inode);
}
static inline struct nova_inode_info_header *NOVA_IH(struct inode *inode)
{
struct nova_inode_info *si = NOVA_I(inode);
return &si->header;
}
static inline struct nova_inode *nova_get_alter_inode(struct super_block *sb,
struct inode *inode)
{
struct nova_inode_info *si = NOVA_I(inode);
struct nova_inode_info_header *sih = &si->header;
struct nova_inode fake_pi;
void *addr;
int rc;
if (metadata_csum == 0)
return NULL;
addr = nova_get_block(sb, sih->alter_pi_addr);
rc = memcpy_mcsafe(&fake_pi, addr, sizeof(struct nova_inode));
if (rc)
return NULL;
return (struct nova_inode *)addr;
}
static inline int nova_update_alter_inode(struct super_block *sb,
struct inode *inode, struct nova_inode *pi)
{
struct nova_inode *alter_pi;
if (metadata_csum == 0)
return 0;
alter_pi = nova_get_alter_inode(sb, inode);
if (!alter_pi)
return -EINVAL;
memcpy_to_pmem_nocache(alter_pi, pi, sizeof(struct nova_inode));
return 0;
}
static inline int nova_update_inode_checksum(struct nova_inode *pi)
{
u32 crc = 0;
if (metadata_csum == 0)
goto out;
crc = nova_crc32c(~0, (__u8 *)pi,
(sizeof(struct nova_inode) - sizeof(__le32)));
pi->csum = crc;
persist:
nova_flush_buffer(pi, sizeof(struct nova_inode), 1);
out:
return 0;
}
static inline int nova_check_inode_checksum(struct nova_inode *pi)
{
u32 crc = 0;
if (metadata_csum == 0)
return 0;
crc = nova_crc32c(~0, (__u8 *)pi,
(sizeof(struct nova_inode) - sizeof(__le32)));
if (pi->csum == cpu_to_le32(crc))
return 0;
else
return 1;
}
static inline void nova_update_tail(struct nova_inode *pi, u64 new_tail)
{
INIT_TIMING(update_time);
NOVA_START_TIMING(update_tail_t, update_time);
PERSISTENT_BARRIER();
pi->log_tail = new_tail;
nova_flush_buffer(&pi->log_tail, CACHELINE_SIZE, 1);
NOVA_END_TIMING(update_tail_t, update_time);
}
static inline void nova_update_alter_tail(struct nova_inode *pi, u64 new_tail)
{
INIT_TIMING(update_time);
if (metadata_csum == 0)
return;
NOVA_START_TIMING(update_tail_t, update_time);
PERSISTENT_BARRIER();
pi->alter_log_tail = new_tail;
nova_flush_buffer(&pi->alter_log_tail, CACHELINE_SIZE, 1);
NOVA_END_TIMING(update_tail_t, update_time);
}
/* Update inode tails and checksums */
static inline void nova_update_inode(struct super_block *sb,
struct inode *inode, struct nova_inode *pi,
struct nova_inode_update *update, int update_alter)
{
struct nova_inode_info *si = NOVA_I(inode);
struct nova_inode_info_header *sih = &si->header;
sih->log_tail = update->tail;
sih->alter_log_tail = update->alter_tail;
nova_update_tail(pi, update->tail);
if (metadata_csum)
nova_update_alter_tail(pi, update->alter_tail);
nova_update_inode_checksum(pi);
if (inode && update_alter)
nova_update_alter_inode(sb, inode, pi);
}
static inline
struct inode_table *nova_get_inode_table(struct super_block *sb,
int version, int cpu)
{
struct nova_sb_info *sbi = NOVA_SB(sb);
int table_start;
if (cpu >= sbi->cpus)
return NULL;
if ((version & 0x1) == 0)
table_start = INODE_TABLE0_START;
else
table_start = INODE_TABLE1_START;
return (struct inode_table *)((char *)nova_get_block(sb,
NOVA_DEF_BLOCK_SIZE_4K * table_start) +
cpu * CACHELINE_SIZE);
}
static inline unsigned int
nova_inode_blk_shift(struct nova_inode_info_header *sih)
{
return blk_type_to_shift[sih->i_blk_type];
}
static inline uint32_t nova_inode_blk_size(struct nova_inode_info_header *sih)
{
return blk_type_to_size[sih->i_blk_type];
}
static inline u64 nova_get_reserved_inode_addr(struct super_block *sb,
u64 inode_number)
{
return (NOVA_DEF_BLOCK_SIZE_4K * RESERVE_INODE_START) +
inode_number * NOVA_INODE_SIZE;
}
static inline u64 nova_get_alter_reserved_inode_addr(struct super_block *sb,
u64 inode_number)
{
struct nova_sb_info *sbi = NOVA_SB(sb);
return nova_get_addr_off(sbi, sbi->replica_reserved_inodes_addr) +
inode_number * NOVA_INODE_SIZE;
}
static inline struct nova_inode *nova_get_reserved_inode(struct super_block *sb,
u64 inode_number)
{
struct nova_sb_info *sbi = NOVA_SB(sb);
u64 addr;
addr = nova_get_reserved_inode_addr(sb, inode_number);
return (struct nova_inode *)(sbi->virt_addr + addr);
}
static inline struct nova_inode *
nova_get_alter_reserved_inode(struct super_block *sb,
u64 inode_number)
{
struct nova_sb_info *sbi = NOVA_SB(sb);
u64 addr;
addr = nova_get_alter_reserved_inode_addr(sb, inode_number);
return (struct nova_inode *)(sbi->virt_addr + addr);
}
/* If this is part of a read-modify-write of the inode metadata,
* nova_memunlock_inode() before calling!
*/
static inline struct nova_inode *nova_get_inode_by_ino(struct super_block *sb,
u64 ino)
{
if (ino == 0 || ino >= NOVA_NORMAL_INODE_START)
return NULL;
return nova_get_reserved_inode(sb, ino);
}
static inline struct nova_inode *nova_get_inode(struct super_block *sb,
struct inode *inode)
{
struct nova_inode_info *si = NOVA_I(inode);
struct nova_inode_info_header *sih = &si->header;
struct nova_inode fake_pi;
void *addr;
int rc;
addr = nova_get_block(sb, sih->pi_addr);
rc = memcpy_mcsafe(&fake_pi, addr, sizeof(struct nova_inode));
if (rc)
return NULL;
return (struct nova_inode *)addr;
}
extern const struct address_space_operations nova_aops_dax;
int nova_init_inode_inuse_list(struct super_block *sb);
extern int nova_init_inode_table(struct super_block *sb);
int nova_get_alter_inode_address(struct super_block *sb, u64 ino,
u64 *alter_pi_addr);
unsigned long nova_get_last_blocknr(struct super_block *sb,
struct nova_inode_info_header *sih);
int nova_get_inode_address(struct super_block *sb, u64 ino, int version,
u64 *pi_addr, int extendable, int extend_alternate);
int nova_set_blocksize_hint(struct super_block *sb, struct inode *inode,
struct nova_inode *pi, loff_t new_size);
extern struct inode *nova_iget(struct super_block *sb, unsigned long ino);
extern void nova_evict_inode(struct inode *inode);
extern int nova_write_inode(struct inode *inode, struct writeback_control *wbc);
extern void nova_dirty_inode(struct inode *inode, int flags);
extern int nova_notify_change(struct dentry *dentry, struct iattr *attr);
extern int nova_getattr(const struct path *path, struct kstat *stat,
u32 request_mask, unsigned int query_flags);
extern void nova_set_inode_flags(struct inode *inode, struct nova_inode *pi,
unsigned int flags);
extern unsigned long nova_find_region(struct inode *inode, loff_t *offset,
int hole);
int nova_delete_file_tree(struct super_block *sb,
struct nova_inode_info_header *sih, unsigned long start_blocknr,
unsigned long last_blocknr, bool delete_nvmm,
bool delete_dead, u64 trasn_id);
void nova_truncate_file_blocks(struct inode *inode, loff_t start,
loff_t end, u64 epoch_id);
u64 nova_new_nova_inode(struct super_block *sb, u64 *pi_addr);
extern struct inode *nova_new_vfs_inode(enum nova_new_inode_type,
struct inode *dir, u64 pi_addr, u64 ino, umode_t mode,
size_t size, dev_t rdev, const struct qstr *qstr, u64 epoch_id);
#endif