File Index
Files and directories
Sign in
FILE

dir_edit.c

File preview with syntax highlighting.

linux-6.19.14/fs/afs/dir_edit.c C
  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 */
 24static 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 */
 69static 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 */
 90static 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 */
111static 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
155fail:
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 */
165static 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 */
210static 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 */
241void afs_edit_dir_add(struct afs_vnode *vnode,
242		      const 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
327new_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
336found_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
369out_unmap:
370	kunmap_local(meta);
371	_leave("");
372	return;
373
374already_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
379error_too_many_blocks:
380	afs_invalidate_dir(vnode, afs_dir_invalid_edit_add_too_many_blocks);
381error:
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 */
393void afs_edit_dir_remove(struct afs_vnode *vnode,
394			 const 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
505out_unmap:
506	kunmap_local(meta);
507	_leave("");
508	return;
509
510already_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
516error_unmap:
517	kunmap_local(block);
518error:
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 an entry in a directory to update the vnode it refers to.  This is also
526 * used to update the ".." entry in a directory.
527 */
528void afs_edit_dir_update(struct afs_vnode *vnode, const struct qstr *name,
529			 struct afs_vnode *new_dvnode, 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, 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, name->name);
570	afs_invalidate_dir(vnode, afs_dir_invalid_edit_upd_no_dd);
571	goto out;
572
573found_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), name->name);
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
585out:
586	_leave("");
587	return;
588
589already_invalidated:
590	kunmap_local(block);
591	trace_afs_edit_dir(vnode, why, afs_edit_dir_update_inval,
592			   0, 0, 0, 0, name->name);
593	goto out;
594
595error:
596	trace_afs_edit_dir(vnode, why, afs_edit_dir_update_error,
597			   0, 0, 0, 0, name->name);
598	goto out;
599}
600
601/*
602 * Initialise a new directory.  We need to fill in the "." and ".." entries.
603 */
604void 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}
~/ Read-only file preview.