From: NeilBrown Date: Sat, 14 Aug 2010 12:25:38 +0000 (+1000) Subject: Check if dirblock can be orphan before making it one. X-Git-Url: http://git.neil.brown.name/?a=commitdiff_plain;h=4ce23b007d7767c9f6c0a7e0fdf6c53671ac4b9e;p=LaFS.git Check if dirblock can be orphan before making it one. Only certain sorts of deletions can make a directory block into and orphan - check them out before committing resources. Signed-off-by: NeilBrown --- diff --git a/dir.c b/dir.c index b2df67a..50a7374 100644 --- a/dir.c +++ b/dir.c @@ -185,7 +185,6 @@ struct dirop_handle { * This is split into pre_create and commit_create * We already know that the name doesn't exist so a lookup will fail, * but will find the right place in the tree. - * FIXME cache the results of the prior lookup?? * pre_create allocates blocks as needed and stores info in the dirop_handle. * commit_create finalises the create and cannot fail. */ @@ -387,7 +386,7 @@ dir_delete_prepare(struct fs *fs, struct inode *dir, const char *name, int nlen, struct dirop_handle *doh) { struct datablock *dirblk; - int err; + int orphan = 0; doh->dirent_block = dirblk = dir_lookup_blk(dir, name, nlen, &doh->index, @@ -408,11 +407,33 @@ dir_delete_prepare(struct fs *fs, struct inode *dir, /* i_mutex protect us now, so don't need to maintain the lock */ lafs_iounlock_block(&dirblk->b); - /* FIXME should I check if the orphanage is needed - * before committing this block to it? + /* Only make this block an orphan if there is a real + * possibilitiy. + * i.e. one of + * We found the last possible entry + * We found the first entry + * We found the only entry (in which case we found the first) + * First entry is deleted */ - err = lafs_make_orphan(fs, doh->dirent_block, dir); - return err; + if (((doh->hash+1) & MaxDirHash) == doh->dirent_block->b.fileaddr) + /* Last possible entry is being remove */ + orphan=1; + if (!orphan) { + u32 seed = LAFSI(dir)->md.file.seed; + u8 firstpiece = 0; + struct dir_ent de; + char bits = dir->i_blkbits - 8; + char *buf = map_dblock(dirblk); + lafs_dir_find(buf, bits, seed, 0, &firstpiece); + if (doh->index == firstpiece || + lafs_dir_extract(buf, bits, &de, + firstpiece, NULL)->target == 0) + orphan = 1; + unmap_dblock(dirblk, buf); + } + if (orphan) + return lafs_make_orphan(fs, doh->dirent_block, dir); + return 0; } static void @@ -1382,7 +1403,7 @@ int lafs_dir_handle_orphan(struct datablock *b) * and remove the unanchor. */ lafs_dir_find(buf, bits, seed, 0, &firstpiece); - hash = LAFSI(dir)->md.file.seed; + hash = seed; if (firstpiece && lafs_dir_extract(buf, bits, &de, firstpiece, &hash)->target == 0 && lafs_dir_find(buf, bits, seed, hash+1, &piece) == 0) {