1 /* AFS filesystem directory editing
3 * Copyright (C) 2018 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
12 #include <linux/kernel.h>
14 #include <linux/namei.h>
15 #include <linux/pagemap.h>
16 #include <linux/iversion.h>
21 * Find a number of contiguous clear bits in a directory block bitmask.
23 * There are 64 slots, which means we can load the entire bitmap into a
24 * variable. The first bit doesn't count as it corresponds to the block header
25 * slot. nr_slots is between 1 and 9.
27 static int afs_find_contig_bits(union afs_xdr_dir_block
*block
, unsigned int nr_slots
)
33 bitmap
= (u64
)block
->hdr
.bitmap
[0] << 0 * 8;
34 bitmap
|= (u64
)block
->hdr
.bitmap
[1] << 1 * 8;
35 bitmap
|= (u64
)block
->hdr
.bitmap
[2] << 2 * 8;
36 bitmap
|= (u64
)block
->hdr
.bitmap
[3] << 3 * 8;
37 bitmap
|= (u64
)block
->hdr
.bitmap
[4] << 4 * 8;
38 bitmap
|= (u64
)block
->hdr
.bitmap
[5] << 5 * 8;
39 bitmap
|= (u64
)block
->hdr
.bitmap
[6] << 6 * 8;
40 bitmap
|= (u64
)block
->hdr
.bitmap
[7] << 7 * 8;
41 bitmap
>>= 1; /* The first entry is metadata */
43 mask
= (1 << nr_slots
) - 1;
46 if (sizeof(unsigned long) == 8)
49 n
= ((u32
)bitmap
) != 0 ?
51 ffz((u32
)(bitmap
>> 32)) + 32;
55 if ((bitmap
& mask
) == 0) {
56 if (bit
> 64 - nr_slots
)
70 * Set a number of contiguous bits in the directory block bitmap.
72 static void afs_set_contig_bits(union afs_xdr_dir_block
*block
,
73 int bit
, unsigned int nr_slots
)
75 u64 mask
, before
, after
;
77 mask
= (1 << nr_slots
) - 1;
80 before
= *(u64
*)block
->hdr
.bitmap
;
82 block
->hdr
.bitmap
[0] |= (u8
)(mask
>> 0 * 8);
83 block
->hdr
.bitmap
[1] |= (u8
)(mask
>> 1 * 8);
84 block
->hdr
.bitmap
[2] |= (u8
)(mask
>> 2 * 8);
85 block
->hdr
.bitmap
[3] |= (u8
)(mask
>> 3 * 8);
86 block
->hdr
.bitmap
[4] |= (u8
)(mask
>> 4 * 8);
87 block
->hdr
.bitmap
[5] |= (u8
)(mask
>> 5 * 8);
88 block
->hdr
.bitmap
[6] |= (u8
)(mask
>> 6 * 8);
89 block
->hdr
.bitmap
[7] |= (u8
)(mask
>> 7 * 8);
91 after
= *(u64
*)block
->hdr
.bitmap
;
95 * Clear a number of contiguous bits in the directory block bitmap.
97 static void afs_clear_contig_bits(union afs_xdr_dir_block
*block
,
98 int bit
, unsigned int nr_slots
)
100 u64 mask
, before
, after
;
102 mask
= (1 << nr_slots
) - 1;
105 before
= *(u64
*)block
->hdr
.bitmap
;
107 block
->hdr
.bitmap
[0] &= ~(u8
)(mask
>> 0 * 8);
108 block
->hdr
.bitmap
[1] &= ~(u8
)(mask
>> 1 * 8);
109 block
->hdr
.bitmap
[2] &= ~(u8
)(mask
>> 2 * 8);
110 block
->hdr
.bitmap
[3] &= ~(u8
)(mask
>> 3 * 8);
111 block
->hdr
.bitmap
[4] &= ~(u8
)(mask
>> 4 * 8);
112 block
->hdr
.bitmap
[5] &= ~(u8
)(mask
>> 5 * 8);
113 block
->hdr
.bitmap
[6] &= ~(u8
)(mask
>> 6 * 8);
114 block
->hdr
.bitmap
[7] &= ~(u8
)(mask
>> 7 * 8);
116 after
= *(u64
*)block
->hdr
.bitmap
;
120 * Scan a directory block looking for a dirent of the right name.
122 static int afs_dir_scan_block(union afs_xdr_dir_block
*block
, struct qstr
*name
,
123 unsigned int blocknum
)
125 union afs_xdr_dirent
*de
;
131 bitmap
= (u64
)block
->hdr
.bitmap
[0] << 0 * 8;
132 bitmap
|= (u64
)block
->hdr
.bitmap
[1] << 1 * 8;
133 bitmap
|= (u64
)block
->hdr
.bitmap
[2] << 2 * 8;
134 bitmap
|= (u64
)block
->hdr
.bitmap
[3] << 3 * 8;
135 bitmap
|= (u64
)block
->hdr
.bitmap
[4] << 4 * 8;
136 bitmap
|= (u64
)block
->hdr
.bitmap
[5] << 5 * 8;
137 bitmap
|= (u64
)block
->hdr
.bitmap
[6] << 6 * 8;
138 bitmap
|= (u64
)block
->hdr
.bitmap
[7] << 7 * 8;
140 for (d
= (blocknum
== 0 ? AFS_DIR_RESV_BLOCKS0
: AFS_DIR_RESV_BLOCKS
);
141 d
< AFS_DIR_SLOTS_PER_BLOCK
;
143 if (!((bitmap
>> d
) & 1))
145 de
= &block
->dirents
[d
];
146 if (de
->u
.valid
!= 1)
149 /* The block was NUL-terminated by afs_dir_check_page(). */
150 len
= strlen(de
->u
.name
);
151 if (len
== name
->len
&&
152 memcmp(de
->u
.name
, name
->name
, name
->len
) == 0)
155 n
= round_up(12 + len
+ 1 + 4, AFS_DIR_DIRENT_SIZE
);
156 n
/= AFS_DIR_DIRENT_SIZE
;
164 * Initialise a new directory block. Note that block 0 is special and contains
165 * some extra metadata.
167 static void afs_edit_init_block(union afs_xdr_dir_block
*meta
,
168 union afs_xdr_dir_block
*block
, int block_num
)
170 memset(block
, 0, sizeof(*block
));
171 block
->hdr
.npages
= htons(1);
172 block
->hdr
.magic
= AFS_DIR_MAGIC
;
173 block
->hdr
.bitmap
[0] = 1;
175 if (block_num
== 0) {
176 block
->hdr
.bitmap
[0] = 0xff;
177 block
->hdr
.bitmap
[1] = 0x1f;
178 memset(block
->meta
.alloc_ctrs
,
179 AFS_DIR_SLOTS_PER_BLOCK
,
180 sizeof(block
->meta
.alloc_ctrs
));
181 meta
->meta
.alloc_ctrs
[0] =
182 AFS_DIR_SLOTS_PER_BLOCK
- AFS_DIR_RESV_BLOCKS0
;
185 if (block_num
< AFS_DIR_BLOCKS_WITH_CTR
)
186 meta
->meta
.alloc_ctrs
[block_num
] =
187 AFS_DIR_SLOTS_PER_BLOCK
- AFS_DIR_RESV_BLOCKS
;
191 * Edit a directory's file data to add a new directory entry. Doing this after
192 * create, mkdir, symlink, link or rename if the data version number is
193 * incremented by exactly one avoids the need to re-download the entire
194 * directory contents.
196 * The caller must hold the inode locked.
198 void afs_edit_dir_add(struct afs_vnode
*vnode
,
199 struct qstr
*name
, struct afs_fid
*new_fid
,
200 enum afs_edit_dir_reason why
)
202 union afs_xdr_dir_block
*meta
, *block
;
203 struct afs_xdr_dir_page
*meta_page
, *dir_page
;
204 union afs_xdr_dirent
*de
;
205 struct page
*page0
, *page
;
206 unsigned int need_slots
, nr_blocks
, b
;
212 _enter(",,{%d,%s},", name
->len
, name
->name
);
214 i_size
= i_size_read(&vnode
->vfs_inode
);
215 if (i_size
> AFS_DIR_BLOCK_SIZE
* AFS_DIR_MAX_BLOCKS
||
216 (i_size
& (AFS_DIR_BLOCK_SIZE
- 1))) {
217 clear_bit(AFS_VNODE_DIR_VALID
, &vnode
->flags
);
221 gfp
= vnode
->vfs_inode
.i_mapping
->gfp_mask
;
222 page0
= find_or_create_page(vnode
->vfs_inode
.i_mapping
, 0, gfp
);
224 clear_bit(AFS_VNODE_DIR_VALID
, &vnode
->flags
);
229 /* Work out how many slots we're going to need. */
230 need_slots
= round_up(12 + name
->len
+ 1 + 4, AFS_DIR_DIRENT_SIZE
);
231 need_slots
/= AFS_DIR_DIRENT_SIZE
;
233 meta_page
= kmap(page0
);
234 meta
= &meta_page
->blocks
[0];
237 nr_blocks
= i_size
/ AFS_DIR_BLOCK_SIZE
;
239 /* Find a block that has sufficient slots available. Each VM page
240 * contains two or more directory blocks.
242 for (b
= 0; b
< nr_blocks
+ 1; b
++) {
243 /* If the directory extended into a new page, then we need to
244 * tack a new page on the end.
246 index
= b
/ AFS_DIR_BLOCKS_PER_PAGE
;
249 dir_page
= meta_page
;
251 if (nr_blocks
>= AFS_DIR_MAX_BLOCKS
)
253 gfp
= vnode
->vfs_inode
.i_mapping
->gfp_mask
;
254 page
= find_or_create_page(vnode
->vfs_inode
.i_mapping
,
258 if (!PagePrivate(page
)) {
259 set_page_private(page
, 1);
260 SetPagePrivate(page
);
262 dir_page
= kmap(page
);
265 /* Abandon the edit if we got a callback break. */
266 if (!test_bit(AFS_VNODE_DIR_VALID
, &vnode
->flags
))
269 block
= &dir_page
->blocks
[b
% AFS_DIR_BLOCKS_PER_PAGE
];
271 _debug("block %u: %2u %3u %u",
273 (b
< AFS_DIR_BLOCKS_WITH_CTR
) ? meta
->meta
.alloc_ctrs
[b
] : 99,
274 ntohs(block
->hdr
.npages
),
275 ntohs(block
->hdr
.magic
));
277 /* Initialise the block if necessary. */
278 if (b
== nr_blocks
) {
279 _debug("init %u", b
);
280 afs_edit_init_block(meta
, block
, b
);
281 i_size_write(&vnode
->vfs_inode
, (b
+ 1) * AFS_DIR_BLOCK_SIZE
);
284 /* Only lower dir pages have a counter in the header. */
285 if (b
>= AFS_DIR_BLOCKS_WITH_CTR
||
286 meta
->meta
.alloc_ctrs
[b
] >= need_slots
) {
287 /* We need to try and find one or more consecutive
288 * slots to hold the entry.
290 slot
= afs_find_contig_bits(block
, need_slots
);
292 _debug("slot %u", slot
);
304 /* There are no spare slots of sufficient size, yet the operation
305 * succeeded. Download the directory again.
307 trace_afs_edit_dir(vnode
, why
, afs_edit_dir_create_nospc
, 0, 0, 0, 0, name
->name
);
308 clear_bit(AFS_VNODE_DIR_VALID
, &vnode
->flags
);
312 afs_edit_init_block(meta
, meta
, 0);
313 i_size
= AFS_DIR_BLOCK_SIZE
;
314 i_size_write(&vnode
->vfs_inode
, i_size
);
315 slot
= AFS_DIR_RESV_BLOCKS0
;
322 /* Set the dirent slot. */
323 trace_afs_edit_dir(vnode
, why
, afs_edit_dir_create
, b
, slot
,
324 new_fid
->vnode
, new_fid
->unique
, name
->name
);
325 de
= &block
->dirents
[slot
];
328 de
->u
.hash_next
= 0; // TODO: Really need to maintain this
329 de
->u
.vnode
= htonl(new_fid
->vnode
);
330 de
->u
.unique
= htonl(new_fid
->unique
);
331 memcpy(de
->u
.name
, name
->name
, name
->len
+ 1);
332 de
->u
.name
[name
->len
] = 0;
334 /* Adjust the bitmap. */
335 afs_set_contig_bits(block
, slot
, need_slots
);
342 /* Adjust the allocation counter. */
343 if (b
< AFS_DIR_BLOCKS_WITH_CTR
)
344 meta
->meta
.alloc_ctrs
[b
] -= need_slots
;
346 inode_inc_iversion_raw(&vnode
->vfs_inode
);
347 afs_stat_v(vnode
, n_dir_cr
);
348 _debug("Insert %s in %u[%u]", name
->name
, b
, slot
);
358 trace_afs_edit_dir(vnode
, why
, afs_edit_dir_create_inval
, 0, 0, 0, 0, name
->name
);
359 clear_bit(AFS_VNODE_DIR_VALID
, &vnode
->flags
);
367 trace_afs_edit_dir(vnode
, why
, afs_edit_dir_create_error
, 0, 0, 0, 0, name
->name
);
368 clear_bit(AFS_VNODE_DIR_VALID
, &vnode
->flags
);
373 * Edit a directory's file data to remove a new directory entry. Doing this
374 * after unlink, rmdir or rename if the data version number is incremented by
375 * exactly one avoids the need to re-download the entire directory contents.
377 * The caller must hold the inode locked.
379 void afs_edit_dir_remove(struct afs_vnode
*vnode
,
380 struct qstr
*name
, enum afs_edit_dir_reason why
)
382 struct afs_xdr_dir_page
*meta_page
, *dir_page
;
383 union afs_xdr_dir_block
*meta
, *block
;
384 union afs_xdr_dirent
*de
;
385 struct page
*page0
, *page
;
386 unsigned int need_slots
, nr_blocks
, b
;
391 _enter(",,{%d,%s},", name
->len
, name
->name
);
393 i_size
= i_size_read(&vnode
->vfs_inode
);
394 if (i_size
< AFS_DIR_BLOCK_SIZE
||
395 i_size
> AFS_DIR_BLOCK_SIZE
* AFS_DIR_MAX_BLOCKS
||
396 (i_size
& (AFS_DIR_BLOCK_SIZE
- 1))) {
397 clear_bit(AFS_VNODE_DIR_VALID
, &vnode
->flags
);
400 nr_blocks
= i_size
/ AFS_DIR_BLOCK_SIZE
;
402 page0
= find_lock_page(vnode
->vfs_inode
.i_mapping
, 0);
404 clear_bit(AFS_VNODE_DIR_VALID
, &vnode
->flags
);
409 /* Work out how many slots we're going to discard. */
410 need_slots
= round_up(12 + name
->len
+ 1 + 4, AFS_DIR_DIRENT_SIZE
);
411 need_slots
/= AFS_DIR_DIRENT_SIZE
;
413 meta_page
= kmap(page0
);
414 meta
= &meta_page
->blocks
[0];
416 /* Find a page that has sufficient slots available. Each VM page
417 * contains two or more directory blocks.
419 for (b
= 0; b
< nr_blocks
; b
++) {
420 index
= b
/ AFS_DIR_BLOCKS_PER_PAGE
;
422 page
= find_lock_page(vnode
->vfs_inode
.i_mapping
, index
);
425 dir_page
= kmap(page
);
428 dir_page
= meta_page
;
431 /* Abandon the edit if we got a callback break. */
432 if (!test_bit(AFS_VNODE_DIR_VALID
, &vnode
->flags
))
435 block
= &dir_page
->blocks
[b
% AFS_DIR_BLOCKS_PER_PAGE
];
437 if (b
> AFS_DIR_BLOCKS_WITH_CTR
||
438 meta
->meta
.alloc_ctrs
[b
] <= AFS_DIR_SLOTS_PER_BLOCK
- 1 - need_slots
) {
439 slot
= afs_dir_scan_block(block
, name
, b
);
451 /* Didn't find the dirent to clobber. Download the directory again. */
452 trace_afs_edit_dir(vnode
, why
, afs_edit_dir_delete_noent
,
453 0, 0, 0, 0, name
->name
);
454 clear_bit(AFS_VNODE_DIR_VALID
, &vnode
->flags
);
458 de
= &block
->dirents
[slot
];
460 trace_afs_edit_dir(vnode
, why
, afs_edit_dir_delete
, b
, slot
,
461 ntohl(de
->u
.vnode
), ntohl(de
->u
.unique
),
464 memset(de
, 0, sizeof(*de
) * need_slots
);
466 /* Adjust the bitmap. */
467 afs_clear_contig_bits(block
, slot
, need_slots
);
474 /* Adjust the allocation counter. */
475 if (b
< AFS_DIR_BLOCKS_WITH_CTR
)
476 meta
->meta
.alloc_ctrs
[b
] += need_slots
;
478 inode_set_iversion_raw(&vnode
->vfs_inode
, vnode
->status
.data_version
);
479 afs_stat_v(vnode
, n_dir_rm
);
480 _debug("Remove %s from %u[%u]", name
->name
, b
, slot
);
490 trace_afs_edit_dir(vnode
, why
, afs_edit_dir_delete_inval
,
491 0, 0, 0, 0, name
->name
);
492 clear_bit(AFS_VNODE_DIR_VALID
, &vnode
->flags
);
501 trace_afs_edit_dir(vnode
, why
, afs_edit_dir_delete_error
,
502 0, 0, 0, 0, name
->name
);
503 clear_bit(AFS_VNODE_DIR_VALID
, &vnode
->flags
);