diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/autofs4/expire.c | 26 | ||||
-rw-r--r-- | fs/autofs4/root.c | 38 | ||||
-rw-r--r-- | fs/autofs4/waitq.c | 2 | ||||
-rw-r--r-- | fs/fuse/file.c | 2 | ||||
-rw-r--r-- | fs/jffs2/build.c | 31 | ||||
-rw-r--r-- | fs/jffs2/dir.c | 42 | ||||
-rw-r--r-- | fs/jffs2/erase.c | 9 | ||||
-rw-r--r-- | fs/jffs2/fs.c | 14 | ||||
-rw-r--r-- | fs/jffs2/gc.c | 8 | ||||
-rw-r--r-- | fs/jffs2/nodelist.h | 5 | ||||
-rw-r--r-- | fs/jffs2/nodemgmt.c | 2 | ||||
-rw-r--r-- | fs/jffs2/os-linux.h | 2 | ||||
-rw-r--r-- | fs/jffs2/readinode.c | 16 | ||||
-rw-r--r-- | fs/jffs2/scan.c | 9 | ||||
-rw-r--r-- | fs/jffs2/super.c | 15 | ||||
-rw-r--r-- | fs/jffs2/wbuf.c | 2 | ||||
-rw-r--r-- | fs/jffs2/write.c | 17 | ||||
-rw-r--r-- | fs/jffs2/xattr.c | 4 | ||||
-rw-r--r-- | fs/utimes.c | 17 |
19 files changed, 167 insertions, 94 deletions
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c index d96e5c14a9ca..894fee54d4d8 100644 --- a/fs/autofs4/expire.c +++ b/fs/autofs4/expire.c | |||
@@ -73,8 +73,8 @@ static int autofs4_mount_busy(struct vfsmount *mnt, struct dentry *dentry) | |||
73 | status = 0; | 73 | status = 0; |
74 | done: | 74 | done: |
75 | DPRINTK("returning = %d", status); | 75 | DPRINTK("returning = %d", status); |
76 | mntput(mnt); | ||
77 | dput(dentry); | 76 | dput(dentry); |
77 | mntput(mnt); | ||
78 | return status; | 78 | return status; |
79 | } | 79 | } |
80 | 80 | ||
@@ -333,7 +333,7 @@ static struct dentry *autofs4_expire_indirect(struct super_block *sb, | |||
333 | /* Can we expire this guy */ | 333 | /* Can we expire this guy */ |
334 | if (autofs4_can_expire(dentry, timeout, do_now)) { | 334 | if (autofs4_can_expire(dentry, timeout, do_now)) { |
335 | expired = dentry; | 335 | expired = dentry; |
336 | break; | 336 | goto found; |
337 | } | 337 | } |
338 | goto next; | 338 | goto next; |
339 | } | 339 | } |
@@ -352,7 +352,7 @@ static struct dentry *autofs4_expire_indirect(struct super_block *sb, | |||
352 | inf->flags |= AUTOFS_INF_EXPIRING; | 352 | inf->flags |= AUTOFS_INF_EXPIRING; |
353 | spin_unlock(&sbi->fs_lock); | 353 | spin_unlock(&sbi->fs_lock); |
354 | expired = dentry; | 354 | expired = dentry; |
355 | break; | 355 | goto found; |
356 | } | 356 | } |
357 | spin_unlock(&sbi->fs_lock); | 357 | spin_unlock(&sbi->fs_lock); |
358 | /* | 358 | /* |
@@ -363,7 +363,7 @@ static struct dentry *autofs4_expire_indirect(struct super_block *sb, | |||
363 | expired = autofs4_check_leaves(mnt, dentry, timeout, do_now); | 363 | expired = autofs4_check_leaves(mnt, dentry, timeout, do_now); |
364 | if (expired) { | 364 | if (expired) { |
365 | dput(dentry); | 365 | dput(dentry); |
366 | break; | 366 | goto found; |
367 | } | 367 | } |
368 | } | 368 | } |
369 | next: | 369 | next: |
@@ -371,18 +371,16 @@ next: | |||
371 | spin_lock(&dcache_lock); | 371 | spin_lock(&dcache_lock); |
372 | next = next->next; | 372 | next = next->next; |
373 | } | 373 | } |
374 | |||
375 | if (expired) { | ||
376 | DPRINTK("returning %p %.*s", | ||
377 | expired, (int)expired->d_name.len, expired->d_name.name); | ||
378 | spin_lock(&dcache_lock); | ||
379 | list_move(&expired->d_parent->d_subdirs, &expired->d_u.d_child); | ||
380 | spin_unlock(&dcache_lock); | ||
381 | return expired; | ||
382 | } | ||
383 | spin_unlock(&dcache_lock); | 374 | spin_unlock(&dcache_lock); |
384 | |||
385 | return NULL; | 375 | return NULL; |
376 | |||
377 | found: | ||
378 | DPRINTK("returning %p %.*s", | ||
379 | expired, (int)expired->d_name.len, expired->d_name.name); | ||
380 | spin_lock(&dcache_lock); | ||
381 | list_move(&expired->d_parent->d_subdirs, &expired->d_u.d_child); | ||
382 | spin_unlock(&dcache_lock); | ||
383 | return expired; | ||
386 | } | 384 | } |
387 | 385 | ||
388 | /* Perform an expiry operation */ | 386 | /* Perform an expiry operation */ |
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index aa4c5ff8a40d..edf5b6bddb52 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c | |||
@@ -146,17 +146,17 @@ static int autofs4_dir_open(struct inode *inode, struct file *file) | |||
146 | 146 | ||
147 | if (d_mountpoint(dentry)) { | 147 | if (d_mountpoint(dentry)) { |
148 | struct file *fp = NULL; | 148 | struct file *fp = NULL; |
149 | struct vfsmount *fp_mnt = mntget(mnt); | 149 | struct path fp_path = { .dentry = dentry, .mnt = mnt }; |
150 | struct dentry *fp_dentry = dget(dentry); | ||
151 | 150 | ||
152 | if (!autofs4_follow_mount(&fp_mnt, &fp_dentry)) { | 151 | path_get(&fp_path); |
153 | dput(fp_dentry); | 152 | |
154 | mntput(fp_mnt); | 153 | if (!autofs4_follow_mount(&fp_path.mnt, &fp_path.dentry)) { |
154 | path_put(&fp_path); | ||
155 | dcache_dir_close(inode, file); | 155 | dcache_dir_close(inode, file); |
156 | goto out; | 156 | goto out; |
157 | } | 157 | } |
158 | 158 | ||
159 | fp = dentry_open(fp_dentry, fp_mnt, file->f_flags); | 159 | fp = dentry_open(fp_path.dentry, fp_path.mnt, file->f_flags); |
160 | status = PTR_ERR(fp); | 160 | status = PTR_ERR(fp); |
161 | if (IS_ERR(fp)) { | 161 | if (IS_ERR(fp)) { |
162 | dcache_dir_close(inode, file); | 162 | dcache_dir_close(inode, file); |
@@ -242,7 +242,8 @@ static int try_to_fill_dentry(struct dentry *dentry, int flags) | |||
242 | { | 242 | { |
243 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); | 243 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); |
244 | struct autofs_info *ino = autofs4_dentry_ino(dentry); | 244 | struct autofs_info *ino = autofs4_dentry_ino(dentry); |
245 | int status = 0; | 245 | struct dentry *new; |
246 | int status; | ||
246 | 247 | ||
247 | /* Block on any pending expiry here; invalidate the dentry | 248 | /* Block on any pending expiry here; invalidate the dentry |
248 | when expiration is done to trigger mount request with a new | 249 | when expiration is done to trigger mount request with a new |
@@ -318,7 +319,28 @@ static int try_to_fill_dentry(struct dentry *dentry, int flags) | |||
318 | spin_lock(&dentry->d_lock); | 319 | spin_lock(&dentry->d_lock); |
319 | dentry->d_flags &= ~DCACHE_AUTOFS_PENDING; | 320 | dentry->d_flags &= ~DCACHE_AUTOFS_PENDING; |
320 | spin_unlock(&dentry->d_lock); | 321 | spin_unlock(&dentry->d_lock); |
321 | return status; | 322 | |
323 | /* | ||
324 | * The dentry that is passed in from lookup may not be the one | ||
325 | * we end up using, as mkdir can create a new one. If this | ||
326 | * happens, and another process tries the lookup at the same time, | ||
327 | * it will set the PENDING flag on this new dentry, but add itself | ||
328 | * to our waitq. Then, if after the lookup succeeds, the first | ||
329 | * process that requested the mount performs another lookup of the | ||
330 | * same directory, it will show up as still pending! So, we need | ||
331 | * to redo the lookup here and clear pending on that dentry. | ||
332 | */ | ||
333 | if (d_unhashed(dentry)) { | ||
334 | new = d_lookup(dentry->d_parent, &dentry->d_name); | ||
335 | if (new) { | ||
336 | spin_lock(&new->d_lock); | ||
337 | new->d_flags &= ~DCACHE_AUTOFS_PENDING; | ||
338 | spin_unlock(&new->d_lock); | ||
339 | dput(new); | ||
340 | } | ||
341 | } | ||
342 | |||
343 | return 0; | ||
322 | } | 344 | } |
323 | 345 | ||
324 | /* For autofs direct mounts the follow link triggers the mount */ | 346 | /* For autofs direct mounts the follow link triggers the mount */ |
diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c index 1fe28e4754c2..75e5955c3f6d 100644 --- a/fs/autofs4/waitq.c +++ b/fs/autofs4/waitq.c | |||
@@ -171,7 +171,7 @@ static int autofs4_getpath(struct autofs_sb_info *sbi, | |||
171 | for (tmp = dentry ; tmp != root ; tmp = tmp->d_parent) | 171 | for (tmp = dentry ; tmp != root ; tmp = tmp->d_parent) |
172 | len += tmp->d_name.len + 1; | 172 | len += tmp->d_name.len + 1; |
173 | 173 | ||
174 | if (--len > NAME_MAX) { | 174 | if (!len || --len > NAME_MAX) { |
175 | spin_unlock(&dcache_lock); | 175 | spin_unlock(&dcache_lock); |
176 | return 0; | 176 | return 0; |
177 | } | 177 | } |
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 9ced35b00686..f28cf8b46f80 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c | |||
@@ -934,7 +934,7 @@ static int fuse_get_user_pages(struct fuse_req *req, const char __user *buf, | |||
934 | 934 | ||
935 | nbytes = min(nbytes, (unsigned) FUSE_MAX_PAGES_PER_REQ << PAGE_SHIFT); | 935 | nbytes = min(nbytes, (unsigned) FUSE_MAX_PAGES_PER_REQ << PAGE_SHIFT); |
936 | npages = (nbytes + offset + PAGE_SIZE - 1) >> PAGE_SHIFT; | 936 | npages = (nbytes + offset + PAGE_SIZE - 1) >> PAGE_SHIFT; |
937 | npages = min(max(npages, 1), FUSE_MAX_PAGES_PER_REQ); | 937 | npages = clamp(npages, 1, FUSE_MAX_PAGES_PER_REQ); |
938 | down_read(¤t->mm->mmap_sem); | 938 | down_read(¤t->mm->mmap_sem); |
939 | npages = get_user_pages(current, current->mm, user_addr, npages, write, | 939 | npages = get_user_pages(current, current->mm, user_addr, npages, write, |
940 | 0, req->pages, NULL); | 940 | 0, req->pages, NULL); |
diff --git a/fs/jffs2/build.c b/fs/jffs2/build.c index d58f845ccb85..c5e1450d79f9 100644 --- a/fs/jffs2/build.c +++ b/fs/jffs2/build.c | |||
@@ -46,7 +46,7 @@ next_inode(int *i, struct jffs2_inode_cache *ic, struct jffs2_sb_info *c) | |||
46 | 46 | ||
47 | 47 | ||
48 | static void jffs2_build_inode_pass1(struct jffs2_sb_info *c, | 48 | static void jffs2_build_inode_pass1(struct jffs2_sb_info *c, |
49 | struct jffs2_inode_cache *ic) | 49 | struct jffs2_inode_cache *ic) |
50 | { | 50 | { |
51 | struct jffs2_full_dirent *fd; | 51 | struct jffs2_full_dirent *fd; |
52 | 52 | ||
@@ -68,11 +68,17 @@ static void jffs2_build_inode_pass1(struct jffs2_sb_info *c, | |||
68 | continue; | 68 | continue; |
69 | } | 69 | } |
70 | 70 | ||
71 | if (child_ic->nlink++ && fd->type == DT_DIR) { | 71 | if (fd->type == DT_DIR) { |
72 | JFFS2_ERROR("child dir \"%s\" (ino #%u) of dir ino #%u appears to be a hard link\n", | 72 | if (child_ic->pino_nlink) { |
73 | fd->name, fd->ino, ic->ino); | 73 | JFFS2_ERROR("child dir \"%s\" (ino #%u) of dir ino #%u appears to be a hard link\n", |
74 | /* TODO: What do we do about it? */ | 74 | fd->name, fd->ino, ic->ino); |
75 | } | 75 | /* TODO: What do we do about it? */ |
76 | } else { | ||
77 | child_ic->pino_nlink = ic->ino; | ||
78 | } | ||
79 | } else | ||
80 | child_ic->pino_nlink++; | ||
81 | |||
76 | dbg_fsbuild("increased nlink for child \"%s\" (ino #%u)\n", fd->name, fd->ino); | 82 | dbg_fsbuild("increased nlink for child \"%s\" (ino #%u)\n", fd->name, fd->ino); |
77 | /* Can't free scan_dents so far. We might need them in pass 2 */ | 83 | /* Can't free scan_dents so far. We might need them in pass 2 */ |
78 | } | 84 | } |
@@ -125,7 +131,7 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c) | |||
125 | dbg_fsbuild("pass 2 starting\n"); | 131 | dbg_fsbuild("pass 2 starting\n"); |
126 | 132 | ||
127 | for_each_inode(i, c, ic) { | 133 | for_each_inode(i, c, ic) { |
128 | if (ic->nlink) | 134 | if (ic->pino_nlink) |
129 | continue; | 135 | continue; |
130 | 136 | ||
131 | jffs2_build_remove_unlinked_inode(c, ic, &dead_fds); | 137 | jffs2_build_remove_unlinked_inode(c, ic, &dead_fds); |
@@ -232,16 +238,19 @@ static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, | |||
232 | /* Reduce nlink of the child. If it's now zero, stick it on the | 238 | /* Reduce nlink of the child. If it's now zero, stick it on the |
233 | dead_fds list to be cleaned up later. Else just free the fd */ | 239 | dead_fds list to be cleaned up later. Else just free the fd */ |
234 | 240 | ||
235 | child_ic->nlink--; | 241 | if (fd->type == DT_DIR) |
242 | child_ic->pino_nlink = 0; | ||
243 | else | ||
244 | child_ic->pino_nlink--; | ||
236 | 245 | ||
237 | if (!child_ic->nlink) { | 246 | if (!child_ic->pino_nlink) { |
238 | dbg_fsbuild("inode #%u (\"%s\") has now got zero nlink, adding to dead_fds list.\n", | 247 | dbg_fsbuild("inode #%u (\"%s\") now has no links; adding to dead_fds list.\n", |
239 | fd->ino, fd->name); | 248 | fd->ino, fd->name); |
240 | fd->next = *dead_fds; | 249 | fd->next = *dead_fds; |
241 | *dead_fds = fd; | 250 | *dead_fds = fd; |
242 | } else { | 251 | } else { |
243 | dbg_fsbuild("inode #%u (\"%s\") has now got nlink %d. Ignoring.\n", | 252 | dbg_fsbuild("inode #%u (\"%s\") has now got nlink %d. Ignoring.\n", |
244 | fd->ino, fd->name, child_ic->nlink); | 253 | fd->ino, fd->name, child_ic->pino_nlink); |
245 | jffs2_free_full_dirent(fd); | 254 | jffs2_free_full_dirent(fd); |
246 | } | 255 | } |
247 | } | 256 | } |
diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c index c63e7a96af0d..c0c141f6fde1 100644 --- a/fs/jffs2/dir.c +++ b/fs/jffs2/dir.c | |||
@@ -208,6 +208,13 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode, | |||
208 | f = JFFS2_INODE_INFO(inode); | 208 | f = JFFS2_INODE_INFO(inode); |
209 | dir_f = JFFS2_INODE_INFO(dir_i); | 209 | dir_f = JFFS2_INODE_INFO(dir_i); |
210 | 210 | ||
211 | /* jffs2_do_create() will want to lock it, _after_ reserving | ||
212 | space and taking c-alloc_sem. If we keep it locked here, | ||
213 | lockdep gets unhappy (although it's a false positive; | ||
214 | nothing else will be looking at this inode yet so there's | ||
215 | no chance of AB-BA deadlock involving its f->sem). */ | ||
216 | mutex_unlock(&f->sem); | ||
217 | |||
211 | ret = jffs2_do_create(c, dir_f, f, ri, | 218 | ret = jffs2_do_create(c, dir_f, f, ri, |
212 | dentry->d_name.name, dentry->d_name.len); | 219 | dentry->d_name.name, dentry->d_name.len); |
213 | if (ret) | 220 | if (ret) |
@@ -219,7 +226,8 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode, | |||
219 | d_instantiate(dentry, inode); | 226 | d_instantiate(dentry, inode); |
220 | 227 | ||
221 | D1(printk(KERN_DEBUG "jffs2_create: Created ino #%lu with mode %o, nlink %d(%d). nrpages %ld\n", | 228 | D1(printk(KERN_DEBUG "jffs2_create: Created ino #%lu with mode %o, nlink %d(%d). nrpages %ld\n", |
222 | inode->i_ino, inode->i_mode, inode->i_nlink, f->inocache->nlink, inode->i_mapping->nrpages)); | 229 | inode->i_ino, inode->i_mode, inode->i_nlink, |
230 | f->inocache->pino_nlink, inode->i_mapping->nrpages)); | ||
223 | return 0; | 231 | return 0; |
224 | 232 | ||
225 | fail: | 233 | fail: |
@@ -243,7 +251,7 @@ static int jffs2_unlink(struct inode *dir_i, struct dentry *dentry) | |||
243 | ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name, | 251 | ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name, |
244 | dentry->d_name.len, dead_f, now); | 252 | dentry->d_name.len, dead_f, now); |
245 | if (dead_f->inocache) | 253 | if (dead_f->inocache) |
246 | dentry->d_inode->i_nlink = dead_f->inocache->nlink; | 254 | dentry->d_inode->i_nlink = dead_f->inocache->pino_nlink; |
247 | if (!ret) | 255 | if (!ret) |
248 | dir_i->i_mtime = dir_i->i_ctime = ITIME(now); | 256 | dir_i->i_mtime = dir_i->i_ctime = ITIME(now); |
249 | return ret; | 257 | return ret; |
@@ -276,7 +284,7 @@ static int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct de | |||
276 | 284 | ||
277 | if (!ret) { | 285 | if (!ret) { |
278 | mutex_lock(&f->sem); | 286 | mutex_lock(&f->sem); |
279 | old_dentry->d_inode->i_nlink = ++f->inocache->nlink; | 287 | old_dentry->d_inode->i_nlink = ++f->inocache->pino_nlink; |
280 | mutex_unlock(&f->sem); | 288 | mutex_unlock(&f->sem); |
281 | d_instantiate(dentry, old_dentry->d_inode); | 289 | d_instantiate(dentry, old_dentry->d_inode); |
282 | dir_i->i_mtime = dir_i->i_ctime = ITIME(now); | 290 | dir_i->i_mtime = dir_i->i_ctime = ITIME(now); |
@@ -493,11 +501,14 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) | |||
493 | 501 | ||
494 | inode->i_op = &jffs2_dir_inode_operations; | 502 | inode->i_op = &jffs2_dir_inode_operations; |
495 | inode->i_fop = &jffs2_dir_operations; | 503 | inode->i_fop = &jffs2_dir_operations; |
496 | /* Directories get nlink 2 at start */ | ||
497 | inode->i_nlink = 2; | ||
498 | 504 | ||
499 | f = JFFS2_INODE_INFO(inode); | 505 | f = JFFS2_INODE_INFO(inode); |
500 | 506 | ||
507 | /* Directories get nlink 2 at start */ | ||
508 | inode->i_nlink = 2; | ||
509 | /* but ic->pino_nlink is the parent ino# */ | ||
510 | f->inocache->pino_nlink = dir_i->i_ino; | ||
511 | |||
501 | ri->data_crc = cpu_to_je32(0); | 512 | ri->data_crc = cpu_to_je32(0); |
502 | ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); | 513 | ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); |
503 | 514 | ||
@@ -594,17 +605,25 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) | |||
594 | 605 | ||
595 | static int jffs2_rmdir (struct inode *dir_i, struct dentry *dentry) | 606 | static int jffs2_rmdir (struct inode *dir_i, struct dentry *dentry) |
596 | { | 607 | { |
608 | struct jffs2_sb_info *c = JFFS2_SB_INFO(dir_i->i_sb); | ||
609 | struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i); | ||
597 | struct jffs2_inode_info *f = JFFS2_INODE_INFO(dentry->d_inode); | 610 | struct jffs2_inode_info *f = JFFS2_INODE_INFO(dentry->d_inode); |
598 | struct jffs2_full_dirent *fd; | 611 | struct jffs2_full_dirent *fd; |
599 | int ret; | 612 | int ret; |
613 | uint32_t now = get_seconds(); | ||
600 | 614 | ||
601 | for (fd = f->dents ; fd; fd = fd->next) { | 615 | for (fd = f->dents ; fd; fd = fd->next) { |
602 | if (fd->ino) | 616 | if (fd->ino) |
603 | return -ENOTEMPTY; | 617 | return -ENOTEMPTY; |
604 | } | 618 | } |
605 | ret = jffs2_unlink(dir_i, dentry); | 619 | |
606 | if (!ret) | 620 | ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name, |
621 | dentry->d_name.len, f, now); | ||
622 | if (!ret) { | ||
623 | dir_i->i_mtime = dir_i->i_ctime = ITIME(now); | ||
624 | clear_nlink(dentry->d_inode); | ||
607 | drop_nlink(dir_i); | 625 | drop_nlink(dir_i); |
626 | } | ||
608 | return ret; | 627 | return ret; |
609 | } | 628 | } |
610 | 629 | ||
@@ -817,7 +836,10 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, | |||
817 | inode which didn't exist. */ | 836 | inode which didn't exist. */ |
818 | if (victim_f->inocache) { | 837 | if (victim_f->inocache) { |
819 | mutex_lock(&victim_f->sem); | 838 | mutex_lock(&victim_f->sem); |
820 | victim_f->inocache->nlink--; | 839 | if (S_ISDIR(new_dentry->d_inode->i_mode)) |
840 | victim_f->inocache->pino_nlink = 0; | ||
841 | else | ||
842 | victim_f->inocache->pino_nlink--; | ||
821 | mutex_unlock(&victim_f->sem); | 843 | mutex_unlock(&victim_f->sem); |
822 | } | 844 | } |
823 | } | 845 | } |
@@ -838,8 +860,8 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, | |||
838 | struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode); | 860 | struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode); |
839 | mutex_lock(&f->sem); | 861 | mutex_lock(&f->sem); |
840 | inc_nlink(old_dentry->d_inode); | 862 | inc_nlink(old_dentry->d_inode); |
841 | if (f->inocache) | 863 | if (f->inocache && !S_ISDIR(old_dentry->d_inode->i_mode)) |
842 | f->inocache->nlink++; | 864 | f->inocache->pino_nlink++; |
843 | mutex_unlock(&f->sem); | 865 | mutex_unlock(&f->sem); |
844 | 866 | ||
845 | printk(KERN_NOTICE "jffs2_rename(): Link succeeded, unlink failed (err %d). You now have a hard link\n", ret); | 867 | printk(KERN_NOTICE "jffs2_rename(): Link succeeded, unlink failed (err %d). You now have a hard link\n", ret); |
diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index 25a640e566d3..dddb2a6c9e2c 100644 --- a/fs/jffs2/erase.c +++ b/fs/jffs2/erase.c | |||
@@ -294,7 +294,7 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c, | |||
294 | break; | 294 | break; |
295 | #endif | 295 | #endif |
296 | default: | 296 | default: |
297 | if (ic->nodes == (void *)ic && ic->nlink == 0) | 297 | if (ic->nodes == (void *)ic && ic->pino_nlink == 0) |
298 | jffs2_del_ino_cache(c, ic); | 298 | jffs2_del_ino_cache(c, ic); |
299 | } | 299 | } |
300 | } | 300 | } |
@@ -332,7 +332,8 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl | |||
332 | if (c->mtd->point) { | 332 | if (c->mtd->point) { |
333 | unsigned long *wordebuf; | 333 | unsigned long *wordebuf; |
334 | 334 | ||
335 | ret = c->mtd->point(c->mtd, jeb->offset, c->sector_size, &retlen, (unsigned char **)&ebuf); | 335 | ret = c->mtd->point(c->mtd, jeb->offset, c->sector_size, |
336 | &retlen, &ebuf, NULL); | ||
336 | if (ret) { | 337 | if (ret) { |
337 | D1(printk(KERN_DEBUG "MTD point failed %d\n", ret)); | 338 | D1(printk(KERN_DEBUG "MTD point failed %d\n", ret)); |
338 | goto do_flash_read; | 339 | goto do_flash_read; |
@@ -340,7 +341,7 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl | |||
340 | if (retlen < c->sector_size) { | 341 | if (retlen < c->sector_size) { |
341 | /* Don't muck about if it won't let us point to the whole erase sector */ | 342 | /* Don't muck about if it won't let us point to the whole erase sector */ |
342 | D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", retlen)); | 343 | D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", retlen)); |
343 | c->mtd->unpoint(c->mtd, ebuf, jeb->offset, retlen); | 344 | c->mtd->unpoint(c->mtd, jeb->offset, retlen); |
344 | goto do_flash_read; | 345 | goto do_flash_read; |
345 | } | 346 | } |
346 | wordebuf = ebuf-sizeof(*wordebuf); | 347 | wordebuf = ebuf-sizeof(*wordebuf); |
@@ -349,7 +350,7 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl | |||
349 | if (*++wordebuf != ~0) | 350 | if (*++wordebuf != ~0) |
350 | break; | 351 | break; |
351 | } while(--retlen); | 352 | } while(--retlen); |
352 | c->mtd->unpoint(c->mtd, ebuf, jeb->offset, c->sector_size); | 353 | c->mtd->unpoint(c->mtd, jeb->offset, c->sector_size); |
353 | if (retlen) { | 354 | if (retlen) { |
354 | printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08tx\n", | 355 | printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08tx\n", |
355 | *wordebuf, jeb->offset + c->sector_size-retlen*sizeof(*wordebuf)); | 356 | *wordebuf, jeb->offset + c->sector_size-retlen*sizeof(*wordebuf)); |
diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index 3eb1c84b0a33..086c43830221 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c | |||
@@ -273,7 +273,7 @@ struct inode *jffs2_iget(struct super_block *sb, unsigned long ino) | |||
273 | inode->i_mtime = ITIME(je32_to_cpu(latest_node.mtime)); | 273 | inode->i_mtime = ITIME(je32_to_cpu(latest_node.mtime)); |
274 | inode->i_ctime = ITIME(je32_to_cpu(latest_node.ctime)); | 274 | inode->i_ctime = ITIME(je32_to_cpu(latest_node.ctime)); |
275 | 275 | ||
276 | inode->i_nlink = f->inocache->nlink; | 276 | inode->i_nlink = f->inocache->pino_nlink; |
277 | 277 | ||
278 | inode->i_blocks = (inode->i_size + 511) >> 9; | 278 | inode->i_blocks = (inode->i_size + 511) >> 9; |
279 | 279 | ||
@@ -286,13 +286,12 @@ struct inode *jffs2_iget(struct super_block *sb, unsigned long ino) | |||
286 | case S_IFDIR: | 286 | case S_IFDIR: |
287 | { | 287 | { |
288 | struct jffs2_full_dirent *fd; | 288 | struct jffs2_full_dirent *fd; |
289 | inode->i_nlink = 2; /* parent and '.' */ | ||
289 | 290 | ||
290 | for (fd=f->dents; fd; fd = fd->next) { | 291 | for (fd=f->dents; fd; fd = fd->next) { |
291 | if (fd->type == DT_DIR && fd->ino) | 292 | if (fd->type == DT_DIR && fd->ino) |
292 | inc_nlink(inode); | 293 | inc_nlink(inode); |
293 | } | 294 | } |
294 | /* and '..' */ | ||
295 | inc_nlink(inode); | ||
296 | /* Root dir gets i_nlink 3 for some reason */ | 295 | /* Root dir gets i_nlink 3 for some reason */ |
297 | if (inode->i_ino == 1) | 296 | if (inode->i_ino == 1) |
298 | inc_nlink(inode); | 297 | inc_nlink(inode); |
@@ -586,11 +585,12 @@ void jffs2_gc_release_inode(struct jffs2_sb_info *c, | |||
586 | } | 585 | } |
587 | 586 | ||
588 | struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c, | 587 | struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c, |
589 | int inum, int nlink) | 588 | int inum, int unlinked) |
590 | { | 589 | { |
591 | struct inode *inode; | 590 | struct inode *inode; |
592 | struct jffs2_inode_cache *ic; | 591 | struct jffs2_inode_cache *ic; |
593 | if (!nlink) { | 592 | |
593 | if (unlinked) { | ||
594 | /* The inode has zero nlink but its nodes weren't yet marked | 594 | /* The inode has zero nlink but its nodes weren't yet marked |
595 | obsolete. This has to be because we're still waiting for | 595 | obsolete. This has to be because we're still waiting for |
596 | the final (close() and) iput() to happen. | 596 | the final (close() and) iput() to happen. |
@@ -638,8 +638,8 @@ struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c, | |||
638 | return ERR_CAST(inode); | 638 | return ERR_CAST(inode); |
639 | } | 639 | } |
640 | if (is_bad_inode(inode)) { | 640 | if (is_bad_inode(inode)) { |
641 | printk(KERN_NOTICE "Eep. read_inode() failed for ino #%u. nlink %d\n", | 641 | printk(KERN_NOTICE "Eep. read_inode() failed for ino #%u. unlinked %d\n", |
642 | inum, nlink); | 642 | inum, unlinked); |
643 | /* NB. This will happen again. We need to do something appropriate here. */ | 643 | /* NB. This will happen again. We need to do something appropriate here. */ |
644 | iput(inode); | 644 | iput(inode); |
645 | return ERR_PTR(-EIO); | 645 | return ERR_PTR(-EIO); |
diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c index bad005664e30..090c556ffed2 100644 --- a/fs/jffs2/gc.c +++ b/fs/jffs2/gc.c | |||
@@ -161,8 +161,8 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) | |||
161 | continue; | 161 | continue; |
162 | } | 162 | } |
163 | 163 | ||
164 | if (!ic->nlink) { | 164 | if (!ic->pino_nlink) { |
165 | D1(printk(KERN_DEBUG "Skipping check of ino #%d with nlink zero\n", | 165 | D1(printk(KERN_DEBUG "Skipping check of ino #%d with nlink/pino zero\n", |
166 | ic->ino)); | 166 | ic->ino)); |
167 | spin_unlock(&c->inocache_lock); | 167 | spin_unlock(&c->inocache_lock); |
168 | jffs2_xattr_delete_inode(c, ic); | 168 | jffs2_xattr_delete_inode(c, ic); |
@@ -398,10 +398,10 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) | |||
398 | it's vaguely possible. */ | 398 | it's vaguely possible. */ |
399 | 399 | ||
400 | inum = ic->ino; | 400 | inum = ic->ino; |
401 | nlink = ic->nlink; | 401 | nlink = ic->pino_nlink; |
402 | spin_unlock(&c->inocache_lock); | 402 | spin_unlock(&c->inocache_lock); |
403 | 403 | ||
404 | f = jffs2_gc_fetch_inode(c, inum, nlink); | 404 | f = jffs2_gc_fetch_inode(c, inum, !nlink); |
405 | if (IS_ERR(f)) { | 405 | if (IS_ERR(f)) { |
406 | ret = PTR_ERR(f); | 406 | ret = PTR_ERR(f); |
407 | goto release_sem; | 407 | goto release_sem; |
diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index 8219df6eb6d8..1750445556c3 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h | |||
@@ -177,7 +177,10 @@ struct jffs2_inode_cache { | |||
177 | #ifdef CONFIG_JFFS2_FS_XATTR | 177 | #ifdef CONFIG_JFFS2_FS_XATTR |
178 | struct jffs2_xattr_ref *xref; | 178 | struct jffs2_xattr_ref *xref; |
179 | #endif | 179 | #endif |
180 | int nlink; | 180 | uint32_t pino_nlink; /* Directories store parent inode |
181 | here; other inodes store nlink. | ||
182 | Zero always means that it's | ||
183 | completely unlinked. */ | ||
181 | }; | 184 | }; |
182 | 185 | ||
183 | /* Inode states for 'state' above. We need the 'GC' state to prevent | 186 | /* Inode states for 'state' above. We need the 'GC' state to prevent |
diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c index 9df8f3ef20df..a9bf9603c1ba 100644 --- a/fs/jffs2/nodemgmt.c +++ b/fs/jffs2/nodemgmt.c | |||
@@ -709,7 +709,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref | |||
709 | break; | 709 | break; |
710 | #endif | 710 | #endif |
711 | default: | 711 | default: |
712 | if (ic->nodes == (void *)ic && ic->nlink == 0) | 712 | if (ic->nodes == (void *)ic && ic->pino_nlink == 0) |
713 | jffs2_del_ino_cache(c, ic); | 713 | jffs2_del_ino_cache(c, ic); |
714 | break; | 714 | break; |
715 | } | 715 | } |
diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h index 1b10d2594092..2cc866cf134f 100644 --- a/fs/jffs2/os-linux.h +++ b/fs/jffs2/os-linux.h | |||
@@ -187,7 +187,7 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent); | |||
187 | void jffs2_gc_release_inode(struct jffs2_sb_info *c, | 187 | void jffs2_gc_release_inode(struct jffs2_sb_info *c, |
188 | struct jffs2_inode_info *f); | 188 | struct jffs2_inode_info *f); |
189 | struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c, | 189 | struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c, |
190 | int inum, int nlink); | 190 | int inum, int unlinked); |
191 | 191 | ||
192 | unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c, | 192 | unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c, |
193 | struct jffs2_inode_info *f, | 193 | struct jffs2_inode_info *f, |
diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c index 4cb4d76de07f..6ca08ad887c0 100644 --- a/fs/jffs2/readinode.c +++ b/fs/jffs2/readinode.c | |||
@@ -63,10 +63,11 @@ static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info | |||
63 | /* TODO: instead, incapsulate point() stuff to jffs2_flash_read(), | 63 | /* TODO: instead, incapsulate point() stuff to jffs2_flash_read(), |
64 | * adding and jffs2_flash_read_end() interface. */ | 64 | * adding and jffs2_flash_read_end() interface. */ |
65 | if (c->mtd->point) { | 65 | if (c->mtd->point) { |
66 | err = c->mtd->point(c->mtd, ofs, len, &retlen, &buffer); | 66 | err = c->mtd->point(c->mtd, ofs, len, &retlen, |
67 | (void **)&buffer, NULL); | ||
67 | if (!err && retlen < len) { | 68 | if (!err && retlen < len) { |
68 | JFFS2_WARNING("MTD point returned len too short: %zu instead of %u.\n", retlen, tn->csize); | 69 | JFFS2_WARNING("MTD point returned len too short: %zu instead of %u.\n", retlen, tn->csize); |
69 | c->mtd->unpoint(c->mtd, buffer, ofs, retlen); | 70 | c->mtd->unpoint(c->mtd, ofs, retlen); |
70 | } else if (err) | 71 | } else if (err) |
71 | JFFS2_WARNING("MTD point failed: error code %d.\n", err); | 72 | JFFS2_WARNING("MTD point failed: error code %d.\n", err); |
72 | else | 73 | else |
@@ -100,7 +101,7 @@ static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info | |||
100 | kfree(buffer); | 101 | kfree(buffer); |
101 | #ifndef __ECOS | 102 | #ifndef __ECOS |
102 | else | 103 | else |
103 | c->mtd->unpoint(c->mtd, buffer, ofs, len); | 104 | c->mtd->unpoint(c->mtd, ofs, len); |
104 | #endif | 105 | #endif |
105 | 106 | ||
106 | if (crc != tn->data_crc) { | 107 | if (crc != tn->data_crc) { |
@@ -136,7 +137,7 @@ free_out: | |||
136 | kfree(buffer); | 137 | kfree(buffer); |
137 | #ifndef __ECOS | 138 | #ifndef __ECOS |
138 | else | 139 | else |
139 | c->mtd->unpoint(c->mtd, buffer, ofs, len); | 140 | c->mtd->unpoint(c->mtd, ofs, len); |
140 | #endif | 141 | #endif |
141 | return err; | 142 | return err; |
142 | } | 143 | } |
@@ -1123,7 +1124,8 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, | |||
1123 | size_t retlen; | 1124 | size_t retlen; |
1124 | int ret; | 1125 | int ret; |
1125 | 1126 | ||
1126 | dbg_readinode("ino #%u nlink is %d\n", f->inocache->ino, f->inocache->nlink); | 1127 | dbg_readinode("ino #%u pino/nlink is %d\n", f->inocache->ino, |
1128 | f->inocache->pino_nlink); | ||
1127 | 1129 | ||
1128 | memset(&rii, 0, sizeof(rii)); | 1130 | memset(&rii, 0, sizeof(rii)); |
1129 | 1131 | ||
@@ -1358,7 +1360,7 @@ int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | |||
1358 | } | 1360 | } |
1359 | dbg_readinode("creating inocache for root inode\n"); | 1361 | dbg_readinode("creating inocache for root inode\n"); |
1360 | memset(f->inocache, 0, sizeof(struct jffs2_inode_cache)); | 1362 | memset(f->inocache, 0, sizeof(struct jffs2_inode_cache)); |
1361 | f->inocache->ino = f->inocache->nlink = 1; | 1363 | f->inocache->ino = f->inocache->pino_nlink = 1; |
1362 | f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache; | 1364 | f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache; |
1363 | f->inocache->state = INO_STATE_READING; | 1365 | f->inocache->state = INO_STATE_READING; |
1364 | jffs2_add_ino_cache(c, f->inocache); | 1366 | jffs2_add_ino_cache(c, f->inocache); |
@@ -1401,7 +1403,7 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f) | |||
1401 | jffs2_clear_acl(f); | 1403 | jffs2_clear_acl(f); |
1402 | jffs2_xattr_delete_inode(c, f->inocache); | 1404 | jffs2_xattr_delete_inode(c, f->inocache); |
1403 | mutex_lock(&f->sem); | 1405 | mutex_lock(&f->sem); |
1404 | deleted = f->inocache && !f->inocache->nlink; | 1406 | deleted = f->inocache && !f->inocache->pino_nlink; |
1405 | 1407 | ||
1406 | if (f->inocache && f->inocache->state != INO_STATE_CHECKING) | 1408 | if (f->inocache && f->inocache->state != INO_STATE_CHECKING) |
1407 | jffs2_set_inocache_state(c, f->inocache, INO_STATE_CLEARING); | 1409 | jffs2_set_inocache_state(c, f->inocache, INO_STATE_CLEARING); |
diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 272872d27fd5..1d437de1e9a8 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c | |||
@@ -97,11 +97,12 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) | |||
97 | size_t pointlen; | 97 | size_t pointlen; |
98 | 98 | ||
99 | if (c->mtd->point) { | 99 | if (c->mtd->point) { |
100 | ret = c->mtd->point (c->mtd, 0, c->mtd->size, &pointlen, &flashbuf); | 100 | ret = c->mtd->point(c->mtd, 0, c->mtd->size, &pointlen, |
101 | (void **)&flashbuf, NULL); | ||
101 | if (!ret && pointlen < c->mtd->size) { | 102 | if (!ret && pointlen < c->mtd->size) { |
102 | /* Don't muck about if it won't let us point to the whole flash */ | 103 | /* Don't muck about if it won't let us point to the whole flash */ |
103 | D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", pointlen)); | 104 | D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", pointlen)); |
104 | c->mtd->unpoint(c->mtd, flashbuf, 0, pointlen); | 105 | c->mtd->unpoint(c->mtd, 0, pointlen); |
105 | flashbuf = NULL; | 106 | flashbuf = NULL; |
106 | } | 107 | } |
107 | if (ret) | 108 | if (ret) |
@@ -267,7 +268,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) | |||
267 | kfree(flashbuf); | 268 | kfree(flashbuf); |
268 | #ifndef __ECOS | 269 | #ifndef __ECOS |
269 | else | 270 | else |
270 | c->mtd->unpoint(c->mtd, flashbuf, 0, c->mtd->size); | 271 | c->mtd->unpoint(c->mtd, 0, c->mtd->size); |
271 | #endif | 272 | #endif |
272 | if (s) | 273 | if (s) |
273 | kfree(s); | 274 | kfree(s); |
@@ -940,7 +941,7 @@ struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, uin | |||
940 | ic->nodes = (void *)ic; | 941 | ic->nodes = (void *)ic; |
941 | jffs2_add_ino_cache(c, ic); | 942 | jffs2_add_ino_cache(c, ic); |
942 | if (ino == 1) | 943 | if (ino == 1) |
943 | ic->nlink = 1; | 944 | ic->pino_nlink = 1; |
944 | return ic; | 945 | return ic; |
945 | } | 946 | } |
946 | 947 | ||
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index f3353df178e7..7da69eae49e4 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c | |||
@@ -31,11 +31,12 @@ static struct kmem_cache *jffs2_inode_cachep; | |||
31 | 31 | ||
32 | static struct inode *jffs2_alloc_inode(struct super_block *sb) | 32 | static struct inode *jffs2_alloc_inode(struct super_block *sb) |
33 | { | 33 | { |
34 | struct jffs2_inode_info *ei; | 34 | struct jffs2_inode_info *f; |
35 | ei = (struct jffs2_inode_info *)kmem_cache_alloc(jffs2_inode_cachep, GFP_KERNEL); | 35 | |
36 | if (!ei) | 36 | f = kmem_cache_alloc(jffs2_inode_cachep, GFP_KERNEL); |
37 | if (!f) | ||
37 | return NULL; | 38 | return NULL; |
38 | return &ei->vfs_inode; | 39 | return &f->vfs_inode; |
39 | } | 40 | } |
40 | 41 | ||
41 | static void jffs2_destroy_inode(struct inode *inode) | 42 | static void jffs2_destroy_inode(struct inode *inode) |
@@ -45,10 +46,10 @@ static void jffs2_destroy_inode(struct inode *inode) | |||
45 | 46 | ||
46 | static void jffs2_i_init_once(struct kmem_cache *cachep, void *foo) | 47 | static void jffs2_i_init_once(struct kmem_cache *cachep, void *foo) |
47 | { | 48 | { |
48 | struct jffs2_inode_info *ei = (struct jffs2_inode_info *) foo; | 49 | struct jffs2_inode_info *f = foo; |
49 | 50 | ||
50 | mutex_init(&ei->sem); | 51 | mutex_init(&f->sem); |
51 | inode_init_once(&ei->vfs_inode); | 52 | inode_init_once(&f->vfs_inode); |
52 | } | 53 | } |
53 | 54 | ||
54 | static int jffs2_sync_fs(struct super_block *sb, int wait) | 55 | static int jffs2_sync_fs(struct super_block *sb, int wait) |
diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index 8de52b607678..0e78b00035e4 100644 --- a/fs/jffs2/wbuf.c +++ b/fs/jffs2/wbuf.c | |||
@@ -494,7 +494,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) | |||
494 | /* If it's an in-core inode, then we have to adjust any | 494 | /* If it's an in-core inode, then we have to adjust any |
495 | full_dirent or full_dnode structure to point to the | 495 | full_dirent or full_dnode structure to point to the |
496 | new version instead of the old */ | 496 | new version instead of the old */ |
497 | f = jffs2_gc_fetch_inode(c, ic->ino, ic->nlink); | 497 | f = jffs2_gc_fetch_inode(c, ic->ino, !ic->pino_nlink); |
498 | if (IS_ERR(f)) { | 498 | if (IS_ERR(f)) { |
499 | /* Should never happen; it _must_ be present */ | 499 | /* Should never happen; it _must_ be present */ |
500 | JFFS2_ERROR("Failed to iget() ino #%u, err %ld\n", | 500 | JFFS2_ERROR("Failed to iget() ino #%u, err %ld\n", |
diff --git a/fs/jffs2/write.c b/fs/jffs2/write.c index 665fce9797d3..ca29440e9435 100644 --- a/fs/jffs2/write.c +++ b/fs/jffs2/write.c | |||
@@ -19,7 +19,8 @@ | |||
19 | #include "compr.h" | 19 | #include "compr.h" |
20 | 20 | ||
21 | 21 | ||
22 | int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint32_t mode, struct jffs2_raw_inode *ri) | 22 | int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, |
23 | uint32_t mode, struct jffs2_raw_inode *ri) | ||
23 | { | 24 | { |
24 | struct jffs2_inode_cache *ic; | 25 | struct jffs2_inode_cache *ic; |
25 | 26 | ||
@@ -31,7 +32,7 @@ int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint | |||
31 | memset(ic, 0, sizeof(*ic)); | 32 | memset(ic, 0, sizeof(*ic)); |
32 | 33 | ||
33 | f->inocache = ic; | 34 | f->inocache = ic; |
34 | f->inocache->nlink = 1; | 35 | f->inocache->pino_nlink = 1; /* Will be overwritten shortly for directories */ |
35 | f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache; | 36 | f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache; |
36 | f->inocache->state = INO_STATE_PRESENT; | 37 | f->inocache->state = INO_STATE_PRESENT; |
37 | 38 | ||
@@ -438,10 +439,10 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str | |||
438 | ret = jffs2_reserve_space(c, sizeof(*ri), &alloclen, ALLOC_NORMAL, | 439 | ret = jffs2_reserve_space(c, sizeof(*ri), &alloclen, ALLOC_NORMAL, |
439 | JFFS2_SUMMARY_INODE_SIZE); | 440 | JFFS2_SUMMARY_INODE_SIZE); |
440 | D1(printk(KERN_DEBUG "jffs2_do_create(): reserved 0x%x bytes\n", alloclen)); | 441 | D1(printk(KERN_DEBUG "jffs2_do_create(): reserved 0x%x bytes\n", alloclen)); |
441 | if (ret) { | 442 | if (ret) |
442 | mutex_unlock(&f->sem); | ||
443 | return ret; | 443 | return ret; |
444 | } | 444 | |
445 | mutex_lock(&f->sem); | ||
445 | 446 | ||
446 | ri->data_crc = cpu_to_je32(0); | 447 | ri->data_crc = cpu_to_je32(0); |
447 | ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); | 448 | ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); |
@@ -635,9 +636,9 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, | |||
635 | jffs2_mark_node_obsolete(c, fd->raw); | 636 | jffs2_mark_node_obsolete(c, fd->raw); |
636 | jffs2_free_full_dirent(fd); | 637 | jffs2_free_full_dirent(fd); |
637 | } | 638 | } |
638 | } | 639 | dead_f->inocache->pino_nlink = 0; |
639 | 640 | } else | |
640 | dead_f->inocache->nlink--; | 641 | dead_f->inocache->pino_nlink--; |
641 | /* NB: Caller must set inode nlink if appropriate */ | 642 | /* NB: Caller must set inode nlink if appropriate */ |
642 | mutex_unlock(&dead_f->sem); | 643 | mutex_unlock(&dead_f->sem); |
643 | } | 644 | } |
diff --git a/fs/jffs2/xattr.c b/fs/jffs2/xattr.c index 574cb7532d6c..082e844ab2db 100644 --- a/fs/jffs2/xattr.c +++ b/fs/jffs2/xattr.c | |||
@@ -592,7 +592,7 @@ void jffs2_xattr_delete_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache | |||
592 | When an inode with XATTR is removed, those XATTRs must be removed. */ | 592 | When an inode with XATTR is removed, those XATTRs must be removed. */ |
593 | struct jffs2_xattr_ref *ref, *_ref; | 593 | struct jffs2_xattr_ref *ref, *_ref; |
594 | 594 | ||
595 | if (!ic || ic->nlink > 0) | 595 | if (!ic || ic->pino_nlink > 0) |
596 | return; | 596 | return; |
597 | 597 | ||
598 | down_write(&c->xattr_sem); | 598 | down_write(&c->xattr_sem); |
@@ -829,7 +829,7 @@ void jffs2_build_xattr_subsystem(struct jffs2_sb_info *c) | |||
829 | ref->xd and ref->ic are not valid yet. */ | 829 | ref->xd and ref->ic are not valid yet. */ |
830 | xd = jffs2_find_xattr_datum(c, ref->xid); | 830 | xd = jffs2_find_xattr_datum(c, ref->xid); |
831 | ic = jffs2_get_ino_cache(c, ref->ino); | 831 | ic = jffs2_get_ino_cache(c, ref->ino); |
832 | if (!xd || !ic || !ic->nlink) { | 832 | if (!xd || !ic || !ic->pino_nlink) { |
833 | dbg_xattr("xref(ino=%u, xid=%u, xseqno=%u) is orphan.\n", | 833 | dbg_xattr("xref(ino=%u, xid=%u, xseqno=%u) is orphan.\n", |
834 | ref->ino, ref->xid, ref->xseqno); | 834 | ref->ino, ref->xid, ref->xseqno); |
835 | ref->xseqno |= XREF_DELETE_MARKER; | 835 | ref->xseqno |= XREF_DELETE_MARKER; |
diff --git a/fs/utimes.c b/fs/utimes.c index a2bef77dc9c9..af059d5cb485 100644 --- a/fs/utimes.c +++ b/fs/utimes.c | |||
@@ -40,9 +40,14 @@ asmlinkage long sys_utime(char __user *filename, struct utimbuf __user *times) | |||
40 | 40 | ||
41 | #endif | 41 | #endif |
42 | 42 | ||
43 | static bool nsec_special(long nsec) | ||
44 | { | ||
45 | return nsec == UTIME_OMIT || nsec == UTIME_NOW; | ||
46 | } | ||
47 | |||
43 | static bool nsec_valid(long nsec) | 48 | static bool nsec_valid(long nsec) |
44 | { | 49 | { |
45 | if (nsec == UTIME_OMIT || nsec == UTIME_NOW) | 50 | if (nsec_special(nsec)) |
46 | return true; | 51 | return true; |
47 | 52 | ||
48 | return nsec >= 0 && nsec <= 999999999; | 53 | return nsec >= 0 && nsec <= 999999999; |
@@ -119,7 +124,15 @@ long do_utimes(int dfd, char __user *filename, struct timespec *times, int flags | |||
119 | newattrs.ia_mtime.tv_nsec = times[1].tv_nsec; | 124 | newattrs.ia_mtime.tv_nsec = times[1].tv_nsec; |
120 | newattrs.ia_valid |= ATTR_MTIME_SET; | 125 | newattrs.ia_valid |= ATTR_MTIME_SET; |
121 | } | 126 | } |
122 | } else { | 127 | } |
128 | |||
129 | /* | ||
130 | * If times is NULL or both times are either UTIME_OMIT or | ||
131 | * UTIME_NOW, then need to check permissions, because | ||
132 | * inode_change_ok() won't do it. | ||
133 | */ | ||
134 | if (!times || (nsec_special(times[0].tv_nsec) && | ||
135 | nsec_special(times[1].tv_nsec))) { | ||
123 | error = -EACCES; | 136 | error = -EACCES; |
124 | if (IS_IMMUTABLE(inode)) | 137 | if (IS_IMMUTABLE(inode)) |
125 | goto mnt_drop_write_and_out; | 138 | goto mnt_drop_write_and_out; |