1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* AFS filesystem directory editing
3 *
4 * Copyright (C) 2018 Red Hat, Inc. All Rights Reserved.
5 * Written by David Howells (dhowells@redhat.com)
6 */
7
8 #include <linux/kernel.h>
9 #include <linux/fs.h>
10 #include <linux/namei.h>
11 #include <linux/pagemap.h>
12 #include <linux/iversion.h>
13 #include <linux/folio_queue.h>
14 #include "internal.h"
15 #include "xdr_fs.h"
16
17 /*
18 * Find a number of contiguous clear bits in a directory block bitmask.
19 *
20 * There are 64 slots, which means we can load the entire bitmap into a
21 * variable. The first bit doesn't count as it corresponds to the block header
22 * slot. nr_slots is between 1 and 9.
23 */
afs_find_contig_bits(union afs_xdr_dir_block * block,unsigned int nr_slots)24 static int afs_find_contig_bits(union afs_xdr_dir_block *block, unsigned int nr_slots)
25 {
26 u64 bitmap;
27 u32 mask;
28 int bit, n;
29
30 bitmap = (u64)block->hdr.bitmap[0] << 0 * 8;
31 bitmap |= (u64)block->hdr.bitmap[1] << 1 * 8;
32 bitmap |= (u64)block->hdr.bitmap[2] << 2 * 8;
33 bitmap |= (u64)block->hdr.bitmap[3] << 3 * 8;
34 bitmap |= (u64)block->hdr.bitmap[4] << 4 * 8;
35 bitmap |= (u64)block->hdr.bitmap[5] << 5 * 8;
36 bitmap |= (u64)block->hdr.bitmap[6] << 6 * 8;
37 bitmap |= (u64)block->hdr.bitmap[7] << 7 * 8;
38 bitmap >>= 1; /* The first entry is metadata */
39 bit = 1;
40 mask = (1 << nr_slots) - 1;
41
42 do {
43 if (sizeof(unsigned long) == 8)
44 n = ffz(bitmap);
45 else
46 n = ((u32)bitmap) != 0 ?
47 ffz((u32)bitmap) :
48 ffz((u32)(bitmap >> 32)) + 32;
49 bitmap >>= n;
50 bit += n;
51
52 if ((bitmap & mask) == 0) {
53 if (bit > 64 - nr_slots)
54 return -1;
55 return bit;
56 }
57
58 n = __ffs(bitmap);
59 bitmap >>= n;
60 bit += n;
61 } while (bitmap);
62
63 return -1;
64 }
65
66 /*
67 * Set a number of contiguous bits in the directory block bitmap.
68 */
afs_set_contig_bits(union afs_xdr_dir_block * block,int bit,unsigned int nr_slots)69 static void afs_set_contig_bits(union afs_xdr_dir_block *block,
70 int bit, unsigned int nr_slots)
71 {
72 u64 mask;
73
74 mask = (1 << nr_slots) - 1;
75 mask <<= bit;
76
77 block->hdr.bitmap[0] |= (u8)(mask >> 0 * 8);
78 block->hdr.bitmap[1] |= (u8)(mask >> 1 * 8);
79 block->hdr.bitmap[2] |= (u8)(mask >> 2 * 8);
80 block->hdr.bitmap[3] |= (u8)(mask >> 3 * 8);
81 block->hdr.bitmap[4] |= (u8)(mask >> 4 * 8);
82 block->hdr.bitmap[5] |= (u8)(mask >> 5 * 8);
83 block->hdr.bitmap[6] |= (u8)(mask >> 6 * 8);
84 block->hdr.bitmap[7] |= (u8)(mask >> 7 * 8);
85 }
86
87 /*
88 * Clear a number of contiguous bits in the directory block bitmap.
89 */
afs_clear_contig_bits(union afs_xdr_dir_block * block,int bit,unsigned int nr_slots)90 static void afs_clear_contig_bits(union afs_xdr_dir_block *block,
91 int bit, unsigned int nr_slots)
92 {
93 u64 mask;
94
95 mask = (1 << nr_slots) - 1;
96 mask <<= bit;
97
98 block->hdr.bitmap[0] &= ~(u8)(mask >> 0 * 8);
99 block->hdr.bitmap[1] &= ~(u8)(mask >> 1 * 8);
100 block->hdr.bitmap[2] &= ~(u8)(mask >> 2 * 8);
101 block->hdr.bitmap[3] &= ~(u8)(mask >> 3 * 8);
102 block->hdr.bitmap[4] &= ~(u8)(mask >> 4 * 8);
103 block->hdr.bitmap[5] &= ~(u8)(mask >> 5 * 8);
104 block->hdr.bitmap[6] &= ~(u8)(mask >> 6 * 8);
105 block->hdr.bitmap[7] &= ~(u8)(mask >> 7 * 8);
106 }
107
108 /*
109 * Get a specific block, extending the directory storage to cover it as needed.
110 */
afs_dir_get_block(struct afs_dir_iter * iter,size_t block)111 static union afs_xdr_dir_block *afs_dir_get_block(struct afs_dir_iter *iter, size_t block)
112 {
113 struct folio_queue *fq;
114 struct afs_vnode *dvnode = iter->dvnode;
115 struct folio *folio;
116 size_t blpos = block * AFS_DIR_BLOCK_SIZE;
117 size_t blend = (block + 1) * AFS_DIR_BLOCK_SIZE, fpos = iter->fpos;
118 int ret;
119
120 if (dvnode->directory_size < blend) {
121 size_t cur_size = dvnode->directory_size;
122
123 ret = netfs_alloc_folioq_buffer(
124 NULL, &dvnode->directory, &cur_size, blend,
125 mapping_gfp_mask(dvnode->netfs.inode.i_mapping));
126 dvnode->directory_size = cur_size;
127 if (ret < 0)
128 goto fail;
129 }
130
131 fq = iter->fq;
132 if (!fq)
133 fq = dvnode->directory;
134
135 /* Search the folio queue for the folio containing the block... */
136 for (; fq; fq = fq->next) {
137 for (int s = iter->fq_slot; s < folioq_count(fq); s++) {
138 size_t fsize = folioq_folio_size(fq, s);
139
140 if (blend <= fpos + fsize) {
141 /* ... and then return the mapped block. */
142 folio = folioq_folio(fq, s);
143 if (WARN_ON_ONCE(folio_pos(folio) != fpos))
144 goto fail;
145 iter->fq = fq;
146 iter->fq_slot = s;
147 iter->fpos = fpos;
148 return kmap_local_folio(folio, blpos - fpos);
149 }
150 fpos += fsize;
151 }
152 iter->fq_slot = 0;
153 }
154
155 fail:
156 iter->fq = NULL;
157 iter->fq_slot = 0;
158 afs_invalidate_dir(dvnode, afs_dir_invalid_edit_get_block);
159 return NULL;
160 }
161
162 /*
163 * Scan a directory block looking for a dirent of the right name.
164 */
afs_dir_scan_block(const union afs_xdr_dir_block * block,const struct qstr * name,unsigned int blocknum)165 static int afs_dir_scan_block(const union afs_xdr_dir_block *block, const struct qstr *name,
166 unsigned int blocknum)
167 {
168 const union afs_xdr_dirent *de;
169 u64 bitmap;
170 int d, len, n;
171
172 _enter("");
173
174 bitmap = (u64)block->hdr.bitmap[0] << 0 * 8;
175 bitmap |= (u64)block->hdr.bitmap[1] << 1 * 8;
176 bitmap |= (u64)block->hdr.bitmap[2] << 2 * 8;
177 bitmap |= (u64)block->hdr.bitmap[3] << 3 * 8;
178 bitmap |= (u64)block->hdr.bitmap[4] << 4 * 8;
179 bitmap |= (u64)block->hdr.bitmap[5] << 5 * 8;
180 bitmap |= (u64)block->hdr.bitmap[6] << 6 * 8;
181 bitmap |= (u64)block->hdr.bitmap[7] << 7 * 8;
182
183 for (d = (blocknum == 0 ? AFS_DIR_RESV_BLOCKS0 : AFS_DIR_RESV_BLOCKS);
184 d < AFS_DIR_SLOTS_PER_BLOCK;
185 d++) {
186 if (!((bitmap >> d) & 1))
187 continue;
188 de = &block->dirents[d];
189 if (de->u.valid != 1)
190 continue;
191
192 /* The block was NUL-terminated by afs_dir_check_page(). */
193 len = strlen(de->u.name);
194 if (len == name->len &&
195 memcmp(de->u.name, name->name, name->len) == 0)
196 return d;
197
198 n = round_up(12 + len + 1 + 4, AFS_DIR_DIRENT_SIZE);
199 n /= AFS_DIR_DIRENT_SIZE;
200 d += n - 1;
201 }
202
203 return -1;
204 }
205
206 /*
207 * Initialise a new directory block. Note that block 0 is special and contains
208 * some extra metadata.
209 */
afs_edit_init_block(union afs_xdr_dir_block * meta,union afs_xdr_dir_block * block,int block_num)210 static void afs_edit_init_block(union afs_xdr_dir_block *meta,
211 union afs_xdr_dir_block *block, int block_num)
212 {
213 memset(block, 0, sizeof(*block));
214 block->hdr.npages = htons(1);
215 block->hdr.magic = AFS_DIR_MAGIC;
216 block->hdr.bitmap[0] = 1;
217
218 if (block_num == 0) {
219 block->hdr.bitmap[0] = 0xff;
220 block->hdr.bitmap[1] = 0x1f;
221 memset(block->meta.alloc_ctrs,
222 AFS_DIR_SLOTS_PER_BLOCK,
223 sizeof(block->meta.alloc_ctrs));
224 meta->meta.alloc_ctrs[0] =
225 AFS_DIR_SLOTS_PER_BLOCK - AFS_DIR_RESV_BLOCKS0;
226 }
227
228 if (block_num < AFS_DIR_BLOCKS_WITH_CTR)
229 meta->meta.alloc_ctrs[block_num] =
230 AFS_DIR_SLOTS_PER_BLOCK - AFS_DIR_RESV_BLOCKS;
231 }
232
233 /*
234 * Edit a directory's file data to add a new directory entry. Doing this after
235 * create, mkdir, symlink, link or rename if the data version number is
236 * incremented by exactly one avoids the need to re-download the entire
237 * directory contents.
238 *
239 * The caller must hold the inode locked.
240 */
afs_edit_dir_add(struct afs_vnode * vnode,struct qstr * name,struct afs_fid * new_fid,enum afs_edit_dir_reason why)241 void afs_edit_dir_add(struct afs_vnode *vnode,
242 struct qstr *name, struct afs_fid *new_fid,
243 enum afs_edit_dir_reason why)
244 {
245 union afs_xdr_dir_block *meta, *block;
246 union afs_xdr_dirent *de;
247 struct afs_dir_iter iter = { .dvnode = vnode };
248 unsigned int nr_blocks, b, entry;
249 loff_t i_size;
250 int slot;
251
252 _enter(",,{%d,%s},", name->len, name->name);
253
254 i_size = i_size_read(&vnode->netfs.inode);
255 if (i_size > AFS_DIR_BLOCK_SIZE * AFS_DIR_MAX_BLOCKS ||
256 (i_size & (AFS_DIR_BLOCK_SIZE - 1))) {
257 afs_invalidate_dir(vnode, afs_dir_invalid_edit_add_bad_size);
258 return;
259 }
260
261 meta = afs_dir_get_block(&iter, 0);
262 if (!meta)
263 return;
264
265 /* Work out how many slots we're going to need. */
266 iter.nr_slots = afs_dir_calc_slots(name->len);
267
268 if (i_size == 0)
269 goto new_directory;
270 nr_blocks = i_size / AFS_DIR_BLOCK_SIZE;
271
272 /* Find a block that has sufficient slots available. Each folio
273 * contains two or more directory blocks.
274 */
275 for (b = 0; b < nr_blocks + 1; b++) {
276 /* If the directory extended into a new folio, then we need to
277 * tack a new folio on the end.
278 */
279 if (nr_blocks >= AFS_DIR_MAX_BLOCKS)
280 goto error_too_many_blocks;
281
282 /* Lower dir blocks have a counter in the header we can check. */
283 if (b < AFS_DIR_BLOCKS_WITH_CTR &&
284 meta->meta.alloc_ctrs[b] < iter.nr_slots)
285 continue;
286
287 block = afs_dir_get_block(&iter, b);
288 if (!block)
289 goto error;
290
291 /* Abandon the edit if we got a callback break. */
292 if (!test_bit(AFS_VNODE_DIR_VALID, &vnode->flags))
293 goto already_invalidated;
294
295 _debug("block %u: %2u %3u %u",
296 b,
297 (b < AFS_DIR_BLOCKS_WITH_CTR) ? meta->meta.alloc_ctrs[b] : 99,
298 ntohs(block->hdr.npages),
299 ntohs(block->hdr.magic));
300
301 /* Initialise the block if necessary. */
302 if (b == nr_blocks) {
303 _debug("init %u", b);
304 afs_edit_init_block(meta, block, b);
305 afs_set_i_size(vnode, (b + 1) * AFS_DIR_BLOCK_SIZE);
306 }
307
308 /* We need to try and find one or more consecutive slots to
309 * hold the entry.
310 */
311 slot = afs_find_contig_bits(block, iter.nr_slots);
312 if (slot >= 0) {
313 _debug("slot %u", slot);
314 goto found_space;
315 }
316
317 kunmap_local(block);
318 }
319
320 /* There are no spare slots of sufficient size, yet the operation
321 * succeeded. Download the directory again.
322 */
323 trace_afs_edit_dir(vnode, why, afs_edit_dir_create_nospc, 0, 0, 0, 0, name->name);
324 afs_invalidate_dir(vnode, afs_dir_invalid_edit_add_no_slots);
325 goto out_unmap;
326
327 new_directory:
328 afs_edit_init_block(meta, meta, 0);
329 i_size = AFS_DIR_BLOCK_SIZE;
330 afs_set_i_size(vnode, i_size);
331 slot = AFS_DIR_RESV_BLOCKS0;
332 block = afs_dir_get_block(&iter, 0);
333 nr_blocks = 1;
334 b = 0;
335
336 found_space:
337 /* Set the dirent slot. */
338 trace_afs_edit_dir(vnode, why, afs_edit_dir_create, b, slot,
339 new_fid->vnode, new_fid->unique, name->name);
340 de = &block->dirents[slot];
341 de->u.valid = 1;
342 de->u.unused[0] = 0;
343 de->u.hash_next = 0; // TODO: Really need to maintain this
344 de->u.vnode = htonl(new_fid->vnode);
345 de->u.unique = htonl(new_fid->unique);
346 memcpy(de->u.name, name->name, name->len + 1);
347 de->u.name[name->len] = 0;
348
349 /* Adjust the bitmap. */
350 afs_set_contig_bits(block, slot, iter.nr_slots);
351
352 /* Adjust the allocation counter. */
353 if (b < AFS_DIR_BLOCKS_WITH_CTR)
354 meta->meta.alloc_ctrs[b] -= iter.nr_slots;
355
356 /* Adjust the hash chain. */
357 entry = b * AFS_DIR_SLOTS_PER_BLOCK + slot;
358 iter.bucket = afs_dir_hash_name(name);
359 de->u.hash_next = meta->meta.hashtable[iter.bucket];
360 meta->meta.hashtable[iter.bucket] = htons(entry);
361 kunmap_local(block);
362
363 inode_inc_iversion_raw(&vnode->netfs.inode);
364 afs_stat_v(vnode, n_dir_cr);
365 _debug("Insert %s in %u[%u]", name->name, b, slot);
366
367 netfs_single_mark_inode_dirty(&vnode->netfs.inode);
368
369 out_unmap:
370 kunmap_local(meta);
371 _leave("");
372 return;
373
374 already_invalidated:
375 trace_afs_edit_dir(vnode, why, afs_edit_dir_create_inval, 0, 0, 0, 0, name->name);
376 kunmap_local(block);
377 goto out_unmap;
378
379 error_too_many_blocks:
380 afs_invalidate_dir(vnode, afs_dir_invalid_edit_add_too_many_blocks);
381 error:
382 trace_afs_edit_dir(vnode, why, afs_edit_dir_create_error, 0, 0, 0, 0, name->name);
383 goto out_unmap;
384 }
385
386 /*
387 * Edit a directory's file data to remove a new directory entry. Doing this
388 * after unlink, rmdir or rename if the data version number is incremented by
389 * exactly one avoids the need to re-download the entire directory contents.
390 *
391 * The caller must hold the inode locked.
392 */
afs_edit_dir_remove(struct afs_vnode * vnode,struct qstr * name,enum afs_edit_dir_reason why)393 void afs_edit_dir_remove(struct afs_vnode *vnode,
394 struct qstr *name, enum afs_edit_dir_reason why)
395 {
396 union afs_xdr_dir_block *meta, *block, *pblock;
397 union afs_xdr_dirent *de, *pde;
398 struct afs_dir_iter iter = { .dvnode = vnode };
399 struct afs_fid fid;
400 unsigned int b, slot, entry;
401 loff_t i_size;
402 __be16 next;
403 int found;
404
405 _enter(",,{%d,%s},", name->len, name->name);
406
407 i_size = i_size_read(&vnode->netfs.inode);
408 if (i_size < AFS_DIR_BLOCK_SIZE ||
409 i_size > AFS_DIR_BLOCK_SIZE * AFS_DIR_MAX_BLOCKS ||
410 (i_size & (AFS_DIR_BLOCK_SIZE - 1))) {
411 afs_invalidate_dir(vnode, afs_dir_invalid_edit_rem_bad_size);
412 return;
413 }
414
415 if (!afs_dir_init_iter(&iter, name))
416 return;
417
418 meta = afs_dir_find_block(&iter, 0);
419 if (!meta)
420 return;
421
422 /* Find the entry in the blob. */
423 found = afs_dir_search_bucket(&iter, name, &fid);
424 if (found < 0) {
425 /* Didn't find the dirent to clobber. Re-download. */
426 trace_afs_edit_dir(vnode, why, afs_edit_dir_delete_noent,
427 0, 0, 0, 0, name->name);
428 afs_invalidate_dir(vnode, afs_dir_invalid_edit_rem_wrong_name);
429 goto out_unmap;
430 }
431
432 entry = found;
433 b = entry / AFS_DIR_SLOTS_PER_BLOCK;
434 slot = entry % AFS_DIR_SLOTS_PER_BLOCK;
435
436 block = afs_dir_find_block(&iter, b);
437 if (!block)
438 goto error;
439 if (!test_bit(AFS_VNODE_DIR_VALID, &vnode->flags))
440 goto already_invalidated;
441
442 /* Check and clear the entry. */
443 de = &block->dirents[slot];
444 if (de->u.valid != 1)
445 goto error_unmap;
446
447 trace_afs_edit_dir(vnode, why, afs_edit_dir_delete, b, slot,
448 ntohl(de->u.vnode), ntohl(de->u.unique),
449 name->name);
450
451 /* Adjust the bitmap. */
452 afs_clear_contig_bits(block, slot, iter.nr_slots);
453
454 /* Adjust the allocation counter. */
455 if (b < AFS_DIR_BLOCKS_WITH_CTR)
456 meta->meta.alloc_ctrs[b] += iter.nr_slots;
457
458 /* Clear the constituent entries. */
459 next = de->u.hash_next;
460 memset(de, 0, sizeof(*de) * iter.nr_slots);
461 kunmap_local(block);
462
463 /* Adjust the hash chain: if iter->prev_entry is 0, the hashtable head
464 * index is previous; otherwise it's slot number of the previous entry.
465 */
466 if (!iter.prev_entry) {
467 __be16 prev_next = meta->meta.hashtable[iter.bucket];
468
469 if (unlikely(prev_next != htons(entry))) {
470 pr_warn("%llx:%llx:%x: not head of chain b=%x p=%x,%x e=%x %*s",
471 vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique,
472 iter.bucket, iter.prev_entry, prev_next, entry,
473 name->len, name->name);
474 goto error;
475 }
476 meta->meta.hashtable[iter.bucket] = next;
477 } else {
478 unsigned int pb = iter.prev_entry / AFS_DIR_SLOTS_PER_BLOCK;
479 unsigned int ps = iter.prev_entry % AFS_DIR_SLOTS_PER_BLOCK;
480 __be16 prev_next;
481
482 pblock = afs_dir_find_block(&iter, pb);
483 if (!pblock)
484 goto error;
485 pde = &pblock->dirents[ps];
486 prev_next = pde->u.hash_next;
487 if (prev_next != htons(entry)) {
488 kunmap_local(pblock);
489 pr_warn("%llx:%llx:%x: not prev in chain b=%x p=%x,%x e=%x %*s",
490 vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique,
491 iter.bucket, iter.prev_entry, prev_next, entry,
492 name->len, name->name);
493 goto error;
494 }
495 pde->u.hash_next = next;
496 kunmap_local(pblock);
497 }
498
499 netfs_single_mark_inode_dirty(&vnode->netfs.inode);
500
501 inode_set_iversion_raw(&vnode->netfs.inode, vnode->status.data_version);
502 afs_stat_v(vnode, n_dir_rm);
503 _debug("Remove %s from %u[%u]", name->name, b, slot);
504
505 out_unmap:
506 kunmap_local(meta);
507 _leave("");
508 return;
509
510 already_invalidated:
511 kunmap_local(block);
512 trace_afs_edit_dir(vnode, why, afs_edit_dir_delete_inval,
513 0, 0, 0, 0, name->name);
514 goto out_unmap;
515
516 error_unmap:
517 kunmap_local(block);
518 error:
519 trace_afs_edit_dir(vnode, why, afs_edit_dir_delete_error,
520 0, 0, 0, 0, name->name);
521 goto out_unmap;
522 }
523
524 /*
525 * Edit a subdirectory that has been moved between directories to update the
526 * ".." entry.
527 */
afs_edit_dir_update_dotdot(struct afs_vnode * vnode,struct afs_vnode * new_dvnode,enum afs_edit_dir_reason why)528 void afs_edit_dir_update_dotdot(struct afs_vnode *vnode, struct afs_vnode *new_dvnode,
529 enum afs_edit_dir_reason why)
530 {
531 union afs_xdr_dir_block *block;
532 union afs_xdr_dirent *de;
533 struct afs_dir_iter iter = { .dvnode = vnode };
534 unsigned int nr_blocks, b;
535 loff_t i_size;
536 int slot;
537
538 _enter("");
539
540 i_size = i_size_read(&vnode->netfs.inode);
541 if (i_size < AFS_DIR_BLOCK_SIZE) {
542 afs_invalidate_dir(vnode, afs_dir_invalid_edit_upd_bad_size);
543 return;
544 }
545
546 nr_blocks = i_size / AFS_DIR_BLOCK_SIZE;
547
548 /* Find a block that has sufficient slots available. Each folio
549 * contains two or more directory blocks.
550 */
551 for (b = 0; b < nr_blocks; b++) {
552 block = afs_dir_get_block(&iter, b);
553 if (!block)
554 goto error;
555
556 /* Abandon the edit if we got a callback break. */
557 if (!test_bit(AFS_VNODE_DIR_VALID, &vnode->flags))
558 goto already_invalidated;
559
560 slot = afs_dir_scan_block(block, &dotdot_name, b);
561 if (slot >= 0)
562 goto found_dirent;
563
564 kunmap_local(block);
565 }
566
567 /* Didn't find the dirent to clobber. Download the directory again. */
568 trace_afs_edit_dir(vnode, why, afs_edit_dir_update_nodd,
569 0, 0, 0, 0, "..");
570 afs_invalidate_dir(vnode, afs_dir_invalid_edit_upd_no_dd);
571 goto out;
572
573 found_dirent:
574 de = &block->dirents[slot];
575 de->u.vnode = htonl(new_dvnode->fid.vnode);
576 de->u.unique = htonl(new_dvnode->fid.unique);
577
578 trace_afs_edit_dir(vnode, why, afs_edit_dir_update_dd, b, slot,
579 ntohl(de->u.vnode), ntohl(de->u.unique), "..");
580
581 kunmap_local(block);
582 netfs_single_mark_inode_dirty(&vnode->netfs.inode);
583 inode_set_iversion_raw(&vnode->netfs.inode, vnode->status.data_version);
584
585 out:
586 _leave("");
587 return;
588
589 already_invalidated:
590 kunmap_local(block);
591 trace_afs_edit_dir(vnode, why, afs_edit_dir_update_inval,
592 0, 0, 0, 0, "..");
593 goto out;
594
595 error:
596 trace_afs_edit_dir(vnode, why, afs_edit_dir_update_error,
597 0, 0, 0, 0, "..");
598 goto out;
599 }
600
601 /*
602 * Initialise a new directory. We need to fill in the "." and ".." entries.
603 */
afs_mkdir_init_dir(struct afs_vnode * dvnode,struct afs_vnode * parent_dvnode)604 void afs_mkdir_init_dir(struct afs_vnode *dvnode, struct afs_vnode *parent_dvnode)
605 {
606 union afs_xdr_dir_block *meta;
607 struct afs_dir_iter iter = { .dvnode = dvnode };
608 union afs_xdr_dirent *de;
609 unsigned int slot = AFS_DIR_RESV_BLOCKS0;
610 loff_t i_size;
611
612 i_size = i_size_read(&dvnode->netfs.inode);
613 if (i_size != AFS_DIR_BLOCK_SIZE) {
614 afs_invalidate_dir(dvnode, afs_dir_invalid_edit_add_bad_size);
615 return;
616 }
617
618 meta = afs_dir_get_block(&iter, 0);
619 if (!meta)
620 return;
621
622 afs_edit_init_block(meta, meta, 0);
623
624 de = &meta->dirents[slot];
625 de->u.valid = 1;
626 de->u.vnode = htonl(dvnode->fid.vnode);
627 de->u.unique = htonl(dvnode->fid.unique);
628 memcpy(de->u.name, ".", 2);
629 trace_afs_edit_dir(dvnode, afs_edit_dir_for_mkdir, afs_edit_dir_mkdir, 0, slot,
630 dvnode->fid.vnode, dvnode->fid.unique, ".");
631 slot++;
632
633 de = &meta->dirents[slot];
634 de->u.valid = 1;
635 de->u.vnode = htonl(parent_dvnode->fid.vnode);
636 de->u.unique = htonl(parent_dvnode->fid.unique);
637 memcpy(de->u.name, "..", 3);
638 trace_afs_edit_dir(dvnode, afs_edit_dir_for_mkdir, afs_edit_dir_mkdir, 0, slot,
639 parent_dvnode->fid.vnode, parent_dvnode->fid.unique, "..");
640
641 afs_set_contig_bits(meta, AFS_DIR_RESV_BLOCKS0, 2);
642 meta->meta.alloc_ctrs[0] -= 2;
643 kunmap_local(meta);
644
645 netfs_single_mark_inode_dirty(&dvnode->netfs.inode);
646 set_bit(AFS_VNODE_DIR_VALID, &dvnode->flags);
647 set_bit(AFS_VNODE_DIR_READ, &dvnode->flags);
648 }
649