diff options
| -rw-r--r-- | fs/jffs2/build.c | 75 | ||||
| -rw-r--r-- | fs/jffs2/nodelist.h | 6 |
2 files changed, 62 insertions, 19 deletions
diff --git a/fs/jffs2/build.c b/fs/jffs2/build.c index 0ae91ad6df2d..b288c8ae1236 100644 --- a/fs/jffs2/build.c +++ b/fs/jffs2/build.c | |||
| @@ -50,7 +50,8 @@ next_inode(int *i, struct jffs2_inode_cache *ic, struct jffs2_sb_info *c) | |||
| 50 | 50 | ||
| 51 | 51 | ||
| 52 | static void jffs2_build_inode_pass1(struct jffs2_sb_info *c, | 52 | static void jffs2_build_inode_pass1(struct jffs2_sb_info *c, |
| 53 | struct jffs2_inode_cache *ic) | 53 | struct jffs2_inode_cache *ic, |
| 54 | int *dir_hardlinks) | ||
| 54 | { | 55 | { |
| 55 | struct jffs2_full_dirent *fd; | 56 | struct jffs2_full_dirent *fd; |
| 56 | 57 | ||
| @@ -69,19 +70,21 @@ static void jffs2_build_inode_pass1(struct jffs2_sb_info *c, | |||
| 69 | dbg_fsbuild("child \"%s\" (ino #%u) of dir ino #%u doesn't exist!\n", | 70 | dbg_fsbuild("child \"%s\" (ino #%u) of dir ino #%u doesn't exist!\n", |
| 70 | fd->name, fd->ino, ic->ino); | 71 | fd->name, fd->ino, ic->ino); |
| 71 | jffs2_mark_node_obsolete(c, fd->raw); | 72 | jffs2_mark_node_obsolete(c, fd->raw); |
| 73 | /* Clear the ic/raw union so it doesn't cause problems later. */ | ||
| 74 | fd->ic = NULL; | ||
| 72 | continue; | 75 | continue; |
| 73 | } | 76 | } |
| 74 | 77 | ||
| 78 | /* From this point, fd->raw is no longer used so we can set fd->ic */ | ||
| 79 | fd->ic = child_ic; | ||
| 80 | child_ic->pino_nlink++; | ||
| 81 | /* If we appear (at this stage) to have hard-linked directories, | ||
| 82 | * set a flag to trigger a scan later */ | ||
| 75 | if (fd->type == DT_DIR) { | 83 | if (fd->type == DT_DIR) { |
| 76 | if (child_ic->pino_nlink) { | 84 | child_ic->flags |= INO_FLAGS_IS_DIR; |
| 77 | JFFS2_ERROR("child dir \"%s\" (ino #%u) of dir ino #%u appears to be a hard link\n", | 85 | if (child_ic->pino_nlink > 1) |
| 78 | fd->name, fd->ino, ic->ino); | 86 | *dir_hardlinks = 1; |
| 79 | /* TODO: What do we do about it? */ | 87 | } |
| 80 | } else { | ||
| 81 | child_ic->pino_nlink = ic->ino; | ||
| 82 | } | ||
| 83 | } else | ||
| 84 | child_ic->pino_nlink++; | ||
| 85 | 88 | ||
| 86 | dbg_fsbuild("increased nlink for child \"%s\" (ino #%u)\n", fd->name, fd->ino); | 89 | dbg_fsbuild("increased nlink for child \"%s\" (ino #%u)\n", fd->name, fd->ino); |
| 87 | /* Can't free scan_dents so far. We might need them in pass 2 */ | 90 | /* Can't free scan_dents so far. We might need them in pass 2 */ |
| @@ -95,8 +98,7 @@ static void jffs2_build_inode_pass1(struct jffs2_sb_info *c, | |||
| 95 | */ | 98 | */ |
| 96 | static int jffs2_build_filesystem(struct jffs2_sb_info *c) | 99 | static int jffs2_build_filesystem(struct jffs2_sb_info *c) |
| 97 | { | 100 | { |
| 98 | int ret; | 101 | int ret, i, dir_hardlinks = 0; |
| 99 | int i; | ||
| 100 | struct jffs2_inode_cache *ic; | 102 | struct jffs2_inode_cache *ic; |
| 101 | struct jffs2_full_dirent *fd; | 103 | struct jffs2_full_dirent *fd; |
| 102 | struct jffs2_full_dirent *dead_fds = NULL; | 104 | struct jffs2_full_dirent *dead_fds = NULL; |
| @@ -120,7 +122,7 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c) | |||
| 120 | /* Now scan the directory tree, increasing nlink according to every dirent found. */ | 122 | /* Now scan the directory tree, increasing nlink according to every dirent found. */ |
| 121 | for_each_inode(i, c, ic) { | 123 | for_each_inode(i, c, ic) { |
| 122 | if (ic->scan_dents) { | 124 | if (ic->scan_dents) { |
| 123 | jffs2_build_inode_pass1(c, ic); | 125 | jffs2_build_inode_pass1(c, ic, &dir_hardlinks); |
| 124 | cond_resched(); | 126 | cond_resched(); |
| 125 | } | 127 | } |
| 126 | } | 128 | } |
| @@ -156,6 +158,20 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c) | |||
| 156 | } | 158 | } |
| 157 | 159 | ||
| 158 | dbg_fsbuild("pass 2a complete\n"); | 160 | dbg_fsbuild("pass 2a complete\n"); |
| 161 | |||
| 162 | if (dir_hardlinks) { | ||
| 163 | /* If we detected directory hardlinks earlier, *hopefully* | ||
| 164 | * they are gone now because some of the links were from | ||
| 165 | * dead directories which still had some old dirents lying | ||
| 166 | * around and not yet garbage-collected, but which have | ||
| 167 | * been discarded above. So clear the pino_nlink field | ||
| 168 | * in each directory, so that the final scan below can | ||
| 169 | * print appropriate warnings. */ | ||
| 170 | for_each_inode(i, c, ic) { | ||
| 171 | if (ic->flags & INO_FLAGS_IS_DIR) | ||
| 172 | ic->pino_nlink = 0; | ||
| 173 | } | ||
| 174 | } | ||
| 159 | dbg_fsbuild("freeing temporary data structures\n"); | 175 | dbg_fsbuild("freeing temporary data structures\n"); |
| 160 | 176 | ||
| 161 | /* Finally, we can scan again and free the dirent structs */ | 177 | /* Finally, we can scan again and free the dirent structs */ |
| @@ -163,6 +179,33 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c) | |||
| 163 | while(ic->scan_dents) { | 179 | while(ic->scan_dents) { |
| 164 | fd = ic->scan_dents; | 180 | fd = ic->scan_dents; |
| 165 | ic->scan_dents = fd->next; | 181 | ic->scan_dents = fd->next; |
| 182 | /* We do use the pino_nlink field to count nlink of | ||
| 183 | * directories during fs build, so set it to the | ||
| 184 | * parent ino# now. Now that there's hopefully only | ||
| 185 | * one. */ | ||
| 186 | if (fd->type == DT_DIR) { | ||
| 187 | if (!fd->ic) { | ||
| 188 | /* We'll have complained about it and marked the coresponding | ||
| 189 | raw node obsolete already. Just skip it. */ | ||
| 190 | continue; | ||
| 191 | } | ||
| 192 | |||
| 193 | /* We *have* to have set this in jffs2_build_inode_pass1() */ | ||
| 194 | BUG_ON(!(fd->ic->flags & INO_FLAGS_IS_DIR)); | ||
| 195 | |||
| 196 | /* We clear ic->pino_nlink ∀ directories' ic *only* if dir_hardlinks | ||
| 197 | * is set. Otherwise, we know this should never trigger anyway, so | ||
| 198 | * we don't do the check. And ic->pino_nlink still contains the nlink | ||
| 199 | * value (which is 1). */ | ||
| 200 | if (dir_hardlinks && fd->ic->pino_nlink) { | ||
| 201 | JFFS2_ERROR("child dir \"%s\" (ino #%u) of dir ino #%u is also hard linked from dir ino #%u\n", | ||
| 202 | fd->name, fd->ino, ic->ino, fd->ic->pino_nlink); | ||
| 203 | /* Should we unlink it from its previous parent? */ | ||
| 204 | } | ||
| 205 | |||
| 206 | /* For directories, ic->pino_nlink holds that parent inode # */ | ||
| 207 | fd->ic->pino_nlink = ic->ino; | ||
| 208 | } | ||
| 166 | jffs2_free_full_dirent(fd); | 209 | jffs2_free_full_dirent(fd); |
| 167 | } | 210 | } |
| 168 | ic->scan_dents = NULL; | 211 | ic->scan_dents = NULL; |
| @@ -241,11 +284,7 @@ static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, | |||
| 241 | 284 | ||
| 242 | /* Reduce nlink of the child. If it's now zero, stick it on the | 285 | /* Reduce nlink of the child. If it's now zero, stick it on the |
| 243 | dead_fds list to be cleaned up later. Else just free the fd */ | 286 | dead_fds list to be cleaned up later. Else just free the fd */ |
| 244 | 287 | child_ic->pino_nlink--; | |
| 245 | if (fd->type == DT_DIR) | ||
| 246 | child_ic->pino_nlink = 0; | ||
| 247 | else | ||
| 248 | child_ic->pino_nlink--; | ||
| 249 | 288 | ||
| 250 | if (!child_ic->pino_nlink) { | 289 | if (!child_ic->pino_nlink) { |
| 251 | dbg_fsbuild("inode #%u (\"%s\") now has no links; adding to dead_fds list.\n", | 290 | dbg_fsbuild("inode #%u (\"%s\") now has no links; adding to dead_fds list.\n", |
diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index fa35ff79ab35..0637271f3770 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h | |||
| @@ -194,6 +194,7 @@ struct jffs2_inode_cache { | |||
| 194 | #define INO_STATE_CLEARING 6 /* In clear_inode() */ | 194 | #define INO_STATE_CLEARING 6 /* In clear_inode() */ |
| 195 | 195 | ||
| 196 | #define INO_FLAGS_XATTR_CHECKED 0x01 /* has no duplicate xattr_ref */ | 196 | #define INO_FLAGS_XATTR_CHECKED 0x01 /* has no duplicate xattr_ref */ |
| 197 | #define INO_FLAGS_IS_DIR 0x02 /* is a directory */ | ||
| 197 | 198 | ||
| 198 | #define RAWNODE_CLASS_INODE_CACHE 0 | 199 | #define RAWNODE_CLASS_INODE_CACHE 0 |
| 199 | #define RAWNODE_CLASS_XATTR_DATUM 1 | 200 | #define RAWNODE_CLASS_XATTR_DATUM 1 |
| @@ -249,7 +250,10 @@ struct jffs2_readinode_info | |||
| 249 | 250 | ||
| 250 | struct jffs2_full_dirent | 251 | struct jffs2_full_dirent |
| 251 | { | 252 | { |
| 252 | struct jffs2_raw_node_ref *raw; | 253 | union { |
| 254 | struct jffs2_raw_node_ref *raw; | ||
| 255 | struct jffs2_inode_cache *ic; /* Just during part of build */ | ||
| 256 | }; | ||
| 253 | struct jffs2_full_dirent *next; | 257 | struct jffs2_full_dirent *next; |
| 254 | uint32_t version; | 258 | uint32_t version; |
| 255 | uint32_t ino; /* == zero for unlink */ | 259 | uint32_t ino; /* == zero for unlink */ |
