diff options
Diffstat (limited to 'fs')
64 files changed, 677 insertions, 431 deletions
diff --git a/fs/9p/error.c b/fs/9p/error.c index ae91555c1558..0d7fa4e08812 100644 --- a/fs/9p/error.c +++ b/fs/9p/error.c | |||
@@ -83,6 +83,7 @@ int v9fs_errstr2errno(char *errstr, int len) | |||
83 | 83 | ||
84 | if (errno == 0) { | 84 | if (errno == 0) { |
85 | /* TODO: if error isn't found, add it dynamically */ | 85 | /* TODO: if error isn't found, add it dynamically */ |
86 | errstr[len] = 0; | ||
86 | printk(KERN_ERR "%s: errstr :%s: not found\n", __FUNCTION__, | 87 | printk(KERN_ERR "%s: errstr :%s: not found\n", __FUNCTION__, |
87 | errstr); | 88 | errstr); |
88 | errno = 1; | 89 | errno = 1; |
diff --git a/fs/9p/fid.c b/fs/9p/fid.c index 27507201f9e7..a9b6301a04fc 100644 --- a/fs/9p/fid.c +++ b/fs/9p/fid.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/fs.h> | 25 | #include <linux/fs.h> |
26 | #include <linux/sched.h> | 26 | #include <linux/sched.h> |
27 | #include <linux/idr.h> | 27 | #include <linux/idr.h> |
28 | #include <asm/semaphore.h> | ||
28 | 29 | ||
29 | #include "debug.h" | 30 | #include "debug.h" |
30 | #include "v9fs.h" | 31 | #include "v9fs.h" |
@@ -84,6 +85,7 @@ struct v9fs_fid *v9fs_fid_create(struct v9fs_session_info *v9ses, int fid) | |||
84 | new->iounit = 0; | 85 | new->iounit = 0; |
85 | new->rdir_pos = 0; | 86 | new->rdir_pos = 0; |
86 | new->rdir_fcall = NULL; | 87 | new->rdir_fcall = NULL; |
88 | init_MUTEX(&new->lock); | ||
87 | INIT_LIST_HEAD(&new->list); | 89 | INIT_LIST_HEAD(&new->list); |
88 | 90 | ||
89 | return new; | 91 | return new; |
@@ -102,11 +104,11 @@ void v9fs_fid_destroy(struct v9fs_fid *fid) | |||
102 | } | 104 | } |
103 | 105 | ||
104 | /** | 106 | /** |
105 | * v9fs_fid_lookup - retrieve the right fid from a particular dentry | 107 | * v9fs_fid_lookup - return a locked fid from a dentry |
106 | * @dentry: dentry to look for fid in | 108 | * @dentry: dentry to look for fid in |
107 | * @type: intent of lookup (operation or traversal) | ||
108 | * | 109 | * |
109 | * find a fid in the dentry | 110 | * find a fid in the dentry, obtain its semaphore and return a reference to it. |
111 | * code calling lookup is responsible for releasing lock | ||
110 | * | 112 | * |
111 | * TODO: only match fids that have the same uid as current user | 113 | * TODO: only match fids that have the same uid as current user |
112 | * | 114 | * |
@@ -124,7 +126,68 @@ struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry) | |||
124 | 126 | ||
125 | if (!return_fid) { | 127 | if (!return_fid) { |
126 | dprintk(DEBUG_ERROR, "Couldn't find a fid in dentry\n"); | 128 | dprintk(DEBUG_ERROR, "Couldn't find a fid in dentry\n"); |
129 | return_fid = ERR_PTR(-EBADF); | ||
127 | } | 130 | } |
128 | 131 | ||
132 | if(down_interruptible(&return_fid->lock)) | ||
133 | return ERR_PTR(-EINTR); | ||
134 | |||
129 | return return_fid; | 135 | return return_fid; |
130 | } | 136 | } |
137 | |||
138 | /** | ||
139 | * v9fs_fid_clone - lookup the fid for a dentry, clone a private copy and release it | ||
140 | * @dentry: dentry to look for fid in | ||
141 | * | ||
142 | * find a fid in the dentry and then clone to a new private fid | ||
143 | * | ||
144 | * TODO: only match fids that have the same uid as current user | ||
145 | * | ||
146 | */ | ||
147 | |||
148 | struct v9fs_fid *v9fs_fid_clone(struct dentry *dentry) | ||
149 | { | ||
150 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode); | ||
151 | struct v9fs_fid *base_fid, *new_fid = ERR_PTR(-EBADF); | ||
152 | struct v9fs_fcall *fcall = NULL; | ||
153 | int fid, err; | ||
154 | |||
155 | base_fid = v9fs_fid_lookup(dentry); | ||
156 | |||
157 | if(IS_ERR(base_fid)) | ||
158 | return base_fid; | ||
159 | |||
160 | if(base_fid) { /* clone fid */ | ||
161 | fid = v9fs_get_idpool(&v9ses->fidpool); | ||
162 | if (fid < 0) { | ||
163 | eprintk(KERN_WARNING, "newfid fails!\n"); | ||
164 | new_fid = ERR_PTR(-ENOSPC); | ||
165 | goto Release_Fid; | ||
166 | } | ||
167 | |||
168 | err = v9fs_t_walk(v9ses, base_fid->fid, fid, NULL, &fcall); | ||
169 | if (err < 0) { | ||
170 | dprintk(DEBUG_ERROR, "clone walk didn't work\n"); | ||
171 | v9fs_put_idpool(fid, &v9ses->fidpool); | ||
172 | new_fid = ERR_PTR(err); | ||
173 | goto Free_Fcall; | ||
174 | } | ||
175 | new_fid = v9fs_fid_create(v9ses, fid); | ||
176 | if (new_fid == NULL) { | ||
177 | dprintk(DEBUG_ERROR, "out of memory\n"); | ||
178 | new_fid = ERR_PTR(-ENOMEM); | ||
179 | } | ||
180 | Free_Fcall: | ||
181 | kfree(fcall); | ||
182 | } | ||
183 | |||
184 | Release_Fid: | ||
185 | up(&base_fid->lock); | ||
186 | return new_fid; | ||
187 | } | ||
188 | |||
189 | void v9fs_fid_clunk(struct v9fs_session_info *v9ses, struct v9fs_fid *fid) | ||
190 | { | ||
191 | v9fs_t_clunk(v9ses, fid->fid); | ||
192 | v9fs_fid_destroy(fid); | ||
193 | } | ||
diff --git a/fs/9p/fid.h b/fs/9p/fid.h index aa974d6875c3..48fc170c26c8 100644 --- a/fs/9p/fid.h +++ b/fs/9p/fid.h | |||
@@ -30,6 +30,8 @@ struct v9fs_fid { | |||
30 | struct list_head list; /* list of fids associated with a dentry */ | 30 | struct list_head list; /* list of fids associated with a dentry */ |
31 | struct list_head active; /* XXX - debug */ | 31 | struct list_head active; /* XXX - debug */ |
32 | 32 | ||
33 | struct semaphore lock; | ||
34 | |||
33 | u32 fid; | 35 | u32 fid; |
34 | unsigned char fidopen; /* set when fid is opened */ | 36 | unsigned char fidopen; /* set when fid is opened */ |
35 | unsigned char fidclunked; /* set when fid has already been clunked */ | 37 | unsigned char fidclunked; /* set when fid has already been clunked */ |
@@ -55,3 +57,6 @@ struct v9fs_fid *v9fs_fid_get_created(struct dentry *); | |||
55 | void v9fs_fid_destroy(struct v9fs_fid *fid); | 57 | void v9fs_fid_destroy(struct v9fs_fid *fid); |
56 | struct v9fs_fid *v9fs_fid_create(struct v9fs_session_info *, int fid); | 58 | struct v9fs_fid *v9fs_fid_create(struct v9fs_session_info *, int fid); |
57 | int v9fs_fid_insert(struct v9fs_fid *fid, struct dentry *dentry); | 59 | int v9fs_fid_insert(struct v9fs_fid *fid, struct dentry *dentry); |
60 | struct v9fs_fid *v9fs_fid_clone(struct dentry *dentry); | ||
61 | void v9fs_fid_clunk(struct v9fs_session_info *v9ses, struct v9fs_fid *fid); | ||
62 | |||
diff --git a/fs/9p/mux.c b/fs/9p/mux.c index 944273c3dbff..147ceef8e537 100644 --- a/fs/9p/mux.c +++ b/fs/9p/mux.c | |||
@@ -132,8 +132,10 @@ int v9fs_mux_global_init(void) | |||
132 | v9fs_mux_poll_tasks[i].task = NULL; | 132 | v9fs_mux_poll_tasks[i].task = NULL; |
133 | 133 | ||
134 | v9fs_mux_wq = create_workqueue("v9fs"); | 134 | v9fs_mux_wq = create_workqueue("v9fs"); |
135 | if (!v9fs_mux_wq) | 135 | if (!v9fs_mux_wq) { |
136 | printk(KERN_WARNING "v9fs: mux: creating workqueue failed\n"); | ||
136 | return -ENOMEM; | 137 | return -ENOMEM; |
138 | } | ||
137 | 139 | ||
138 | return 0; | 140 | return 0; |
139 | } | 141 | } |
diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index 0b96fae8b479..d9b561ba5e58 100644 --- a/fs/9p/v9fs.c +++ b/fs/9p/v9fs.c | |||
@@ -457,14 +457,19 @@ static int __init init_v9fs(void) | |||
457 | 457 | ||
458 | v9fs_error_init(); | 458 | v9fs_error_init(); |
459 | 459 | ||
460 | printk(KERN_INFO "Installing v9fs 9P2000 file system support\n"); | 460 | printk(KERN_INFO "Installing v9fs 9p2000 file system support\n"); |
461 | 461 | ||
462 | ret = v9fs_mux_global_init(); | 462 | ret = v9fs_mux_global_init(); |
463 | if (!ret) | 463 | if (ret) { |
464 | printk(KERN_WARNING "v9fs: starting mux failed\n"); | ||
464 | return ret; | 465 | return ret; |
466 | } | ||
465 | ret = register_filesystem(&v9fs_fs_type); | 467 | ret = register_filesystem(&v9fs_fs_type); |
466 | if (!ret) | 468 | if (ret) { |
469 | printk(KERN_WARNING "v9fs: registering file system failed\n"); | ||
467 | v9fs_mux_global_exit(); | 470 | v9fs_mux_global_exit(); |
471 | } | ||
472 | |||
468 | return ret; | 473 | return ret; |
469 | } | 474 | } |
470 | 475 | ||
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c index e86a07151280..9f17b0cacdd0 100644 --- a/fs/9p/vfs_file.c +++ b/fs/9p/vfs_file.c | |||
@@ -55,53 +55,22 @@ int v9fs_file_open(struct inode *inode, struct file *file) | |||
55 | struct v9fs_fid *vfid; | 55 | struct v9fs_fid *vfid; |
56 | struct v9fs_fcall *fcall = NULL; | 56 | struct v9fs_fcall *fcall = NULL; |
57 | int omode; | 57 | int omode; |
58 | int fid = V9FS_NOFID; | ||
59 | int err; | 58 | int err; |
60 | 59 | ||
61 | dprintk(DEBUG_VFS, "inode: %p file: %p \n", inode, file); | 60 | dprintk(DEBUG_VFS, "inode: %p file: %p \n", inode, file); |
62 | 61 | ||
63 | vfid = v9fs_fid_lookup(file->f_path.dentry); | 62 | vfid = v9fs_fid_clone(file->f_path.dentry); |
64 | if (!vfid) { | 63 | if (IS_ERR(vfid)) |
65 | dprintk(DEBUG_ERROR, "Couldn't resolve fid from dentry\n"); | 64 | return PTR_ERR(vfid); |
66 | return -EBADF; | ||
67 | } | ||
68 | |||
69 | fid = v9fs_get_idpool(&v9ses->fidpool); | ||
70 | if (fid < 0) { | ||
71 | eprintk(KERN_WARNING, "newfid fails!\n"); | ||
72 | return -ENOSPC; | ||
73 | } | ||
74 | 65 | ||
75 | err = v9fs_t_walk(v9ses, vfid->fid, fid, NULL, &fcall); | ||
76 | if (err < 0) { | ||
77 | dprintk(DEBUG_ERROR, "rewalk didn't work\n"); | ||
78 | if (fcall && fcall->id == RWALK) | ||
79 | goto clunk_fid; | ||
80 | else { | ||
81 | v9fs_put_idpool(fid, &v9ses->fidpool); | ||
82 | goto free_fcall; | ||
83 | } | ||
84 | } | ||
85 | kfree(fcall); | ||
86 | |||
87 | /* TODO: do special things for O_EXCL, O_NOFOLLOW, O_SYNC */ | ||
88 | /* translate open mode appropriately */ | ||
89 | omode = v9fs_uflags2omode(file->f_flags); | 66 | omode = v9fs_uflags2omode(file->f_flags); |
90 | err = v9fs_t_open(v9ses, fid, omode, &fcall); | 67 | err = v9fs_t_open(v9ses, vfid->fid, omode, &fcall); |
91 | if (err < 0) { | 68 | if (err < 0) { |
92 | PRINT_FCALL_ERROR("open failed", fcall); | 69 | PRINT_FCALL_ERROR("open failed", fcall); |
93 | goto clunk_fid; | 70 | goto Clunk_Fid; |
94 | } | ||
95 | |||
96 | vfid = kmalloc(sizeof(struct v9fs_fid), GFP_KERNEL); | ||
97 | if (vfid == NULL) { | ||
98 | dprintk(DEBUG_ERROR, "out of memory\n"); | ||
99 | err = -ENOMEM; | ||
100 | goto clunk_fid; | ||
101 | } | 71 | } |
102 | 72 | ||
103 | file->private_data = vfid; | 73 | file->private_data = vfid; |
104 | vfid->fid = fid; | ||
105 | vfid->fidopen = 1; | 74 | vfid->fidopen = 1; |
106 | vfid->fidclunked = 0; | 75 | vfid->fidclunked = 0; |
107 | vfid->iounit = fcall->params.ropen.iounit; | 76 | vfid->iounit = fcall->params.ropen.iounit; |
@@ -112,10 +81,8 @@ int v9fs_file_open(struct inode *inode, struct file *file) | |||
112 | 81 | ||
113 | return 0; | 82 | return 0; |
114 | 83 | ||
115 | clunk_fid: | 84 | Clunk_Fid: |
116 | v9fs_t_clunk(v9ses, fid); | 85 | v9fs_fid_clunk(v9ses, vfid); |
117 | |||
118 | free_fcall: | ||
119 | kfree(fcall); | 86 | kfree(fcall); |
120 | 87 | ||
121 | return err; | 88 | return err; |
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 18f26cdfd882..9109ba1d6969 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c | |||
@@ -416,12 +416,8 @@ static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir) | |||
416 | sb = file_inode->i_sb; | 416 | sb = file_inode->i_sb; |
417 | v9ses = v9fs_inode2v9ses(file_inode); | 417 | v9ses = v9fs_inode2v9ses(file_inode); |
418 | v9fid = v9fs_fid_lookup(file); | 418 | v9fid = v9fs_fid_lookup(file); |
419 | 419 | if(IS_ERR(v9fid)) | |
420 | if (!v9fid) { | 420 | return PTR_ERR(v9fid); |
421 | dprintk(DEBUG_ERROR, | ||
422 | "no v9fs_fid\n"); | ||
423 | return -EBADF; | ||
424 | } | ||
425 | 421 | ||
426 | fid = v9fid->fid; | 422 | fid = v9fid->fid; |
427 | if (fid < 0) { | 423 | if (fid < 0) { |
@@ -433,11 +429,13 @@ static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir) | |||
433 | result = v9fs_t_remove(v9ses, fid, &fcall); | 429 | result = v9fs_t_remove(v9ses, fid, &fcall); |
434 | if (result < 0) { | 430 | if (result < 0) { |
435 | PRINT_FCALL_ERROR("remove fails", fcall); | 431 | PRINT_FCALL_ERROR("remove fails", fcall); |
432 | goto Error; | ||
436 | } | 433 | } |
437 | 434 | ||
438 | v9fs_put_idpool(fid, &v9ses->fidpool); | 435 | v9fs_put_idpool(fid, &v9ses->fidpool); |
439 | v9fs_fid_destroy(v9fid); | 436 | v9fs_fid_destroy(v9fid); |
440 | 437 | ||
438 | Error: | ||
441 | kfree(fcall); | 439 | kfree(fcall); |
442 | return result; | 440 | return result; |
443 | } | 441 | } |
@@ -473,9 +471,13 @@ v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode, | |||
473 | inode = NULL; | 471 | inode = NULL; |
474 | vfid = NULL; | 472 | vfid = NULL; |
475 | v9ses = v9fs_inode2v9ses(dir); | 473 | v9ses = v9fs_inode2v9ses(dir); |
476 | dfid = v9fs_fid_lookup(dentry->d_parent); | 474 | dfid = v9fs_fid_clone(dentry->d_parent); |
477 | perm = unixmode2p9mode(v9ses, mode); | 475 | if(IS_ERR(dfid)) { |
476 | err = PTR_ERR(dfid); | ||
477 | goto error; | ||
478 | } | ||
478 | 479 | ||
480 | perm = unixmode2p9mode(v9ses, mode); | ||
479 | if (nd && nd->flags & LOOKUP_OPEN) | 481 | if (nd && nd->flags & LOOKUP_OPEN) |
480 | flags = nd->intent.open.flags - 1; | 482 | flags = nd->intent.open.flags - 1; |
481 | else | 483 | else |
@@ -485,9 +487,10 @@ v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode, | |||
485 | perm, v9fs_uflags2omode(flags), NULL, &fid, &qid, &iounit); | 487 | perm, v9fs_uflags2omode(flags), NULL, &fid, &qid, &iounit); |
486 | 488 | ||
487 | if (err) | 489 | if (err) |
488 | goto error; | 490 | goto clunk_dfid; |
489 | 491 | ||
490 | vfid = v9fs_clone_walk(v9ses, dfid->fid, dentry); | 492 | vfid = v9fs_clone_walk(v9ses, dfid->fid, dentry); |
493 | v9fs_fid_clunk(v9ses, dfid); | ||
491 | if (IS_ERR(vfid)) { | 494 | if (IS_ERR(vfid)) { |
492 | err = PTR_ERR(vfid); | 495 | err = PTR_ERR(vfid); |
493 | vfid = NULL; | 496 | vfid = NULL; |
@@ -525,6 +528,9 @@ v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode, | |||
525 | 528 | ||
526 | return 0; | 529 | return 0; |
527 | 530 | ||
531 | clunk_dfid: | ||
532 | v9fs_fid_clunk(v9ses, dfid); | ||
533 | |||
528 | error: | 534 | error: |
529 | if (vfid) | 535 | if (vfid) |
530 | v9fs_fid_destroy(vfid); | 536 | v9fs_fid_destroy(vfid); |
@@ -551,7 +557,12 @@ static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
551 | inode = NULL; | 557 | inode = NULL; |
552 | vfid = NULL; | 558 | vfid = NULL; |
553 | v9ses = v9fs_inode2v9ses(dir); | 559 | v9ses = v9fs_inode2v9ses(dir); |
554 | dfid = v9fs_fid_lookup(dentry->d_parent); | 560 | dfid = v9fs_fid_clone(dentry->d_parent); |
561 | if(IS_ERR(dfid)) { | ||
562 | err = PTR_ERR(dfid); | ||
563 | goto error; | ||
564 | } | ||
565 | |||
555 | perm = unixmode2p9mode(v9ses, mode | S_IFDIR); | 566 | perm = unixmode2p9mode(v9ses, mode | S_IFDIR); |
556 | 567 | ||
557 | err = v9fs_create(v9ses, dfid->fid, (char *) dentry->d_name.name, | 568 | err = v9fs_create(v9ses, dfid->fid, (char *) dentry->d_name.name, |
@@ -559,37 +570,36 @@ static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
559 | 570 | ||
560 | if (err) { | 571 | if (err) { |
561 | dprintk(DEBUG_ERROR, "create error %d\n", err); | 572 | dprintk(DEBUG_ERROR, "create error %d\n", err); |
562 | goto error; | 573 | goto clean_up_dfid; |
563 | } | ||
564 | |||
565 | err = v9fs_t_clunk(v9ses, fid); | ||
566 | if (err) { | ||
567 | dprintk(DEBUG_ERROR, "clunk error %d\n", err); | ||
568 | goto error; | ||
569 | } | 574 | } |
570 | 575 | ||
571 | vfid = v9fs_clone_walk(v9ses, dfid->fid, dentry); | 576 | vfid = v9fs_clone_walk(v9ses, dfid->fid, dentry); |
572 | if (IS_ERR(vfid)) { | 577 | if (IS_ERR(vfid)) { |
573 | err = PTR_ERR(vfid); | 578 | err = PTR_ERR(vfid); |
574 | vfid = NULL; | 579 | vfid = NULL; |
575 | goto error; | 580 | goto clean_up_dfid; |
576 | } | 581 | } |
577 | 582 | ||
583 | v9fs_fid_clunk(v9ses, dfid); | ||
578 | inode = v9fs_inode_from_fid(v9ses, vfid->fid, dir->i_sb); | 584 | inode = v9fs_inode_from_fid(v9ses, vfid->fid, dir->i_sb); |
579 | if (IS_ERR(inode)) { | 585 | if (IS_ERR(inode)) { |
580 | err = PTR_ERR(inode); | 586 | err = PTR_ERR(inode); |
581 | inode = NULL; | 587 | inode = NULL; |
582 | goto error; | 588 | goto clean_up_fids; |
583 | } | 589 | } |
584 | 590 | ||
585 | dentry->d_op = &v9fs_dentry_operations; | 591 | dentry->d_op = &v9fs_dentry_operations; |
586 | d_instantiate(dentry, inode); | 592 | d_instantiate(dentry, inode); |
587 | return 0; | 593 | return 0; |
588 | 594 | ||
589 | error: | 595 | clean_up_fids: |
590 | if (vfid) | 596 | if (vfid) |
591 | v9fs_fid_destroy(vfid); | 597 | v9fs_fid_destroy(vfid); |
592 | 598 | ||
599 | clean_up_dfid: | ||
600 | v9fs_fid_clunk(v9ses, dfid); | ||
601 | |||
602 | error: | ||
593 | return err; | 603 | return err; |
594 | } | 604 | } |
595 | 605 | ||
@@ -622,28 +632,23 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, | |||
622 | dentry->d_op = &v9fs_dentry_operations; | 632 | dentry->d_op = &v9fs_dentry_operations; |
623 | dirfid = v9fs_fid_lookup(dentry->d_parent); | 633 | dirfid = v9fs_fid_lookup(dentry->d_parent); |
624 | 634 | ||
625 | if (!dirfid) { | 635 | if(IS_ERR(dirfid)) |
626 | dprintk(DEBUG_ERROR, "no dirfid\n"); | 636 | return ERR_PTR(PTR_ERR(dirfid)); |
627 | return ERR_PTR(-EINVAL); | ||
628 | } | ||
629 | 637 | ||
630 | dirfidnum = dirfid->fid; | 638 | dirfidnum = dirfid->fid; |
631 | 639 | ||
632 | if (dirfidnum < 0) { | ||
633 | dprintk(DEBUG_ERROR, "no dirfid for inode %p, #%lu\n", | ||
634 | dir, dir->i_ino); | ||
635 | return ERR_PTR(-EBADF); | ||
636 | } | ||
637 | |||
638 | newfid = v9fs_get_idpool(&v9ses->fidpool); | 640 | newfid = v9fs_get_idpool(&v9ses->fidpool); |
639 | if (newfid < 0) { | 641 | if (newfid < 0) { |
640 | eprintk(KERN_WARNING, "newfid fails!\n"); | 642 | eprintk(KERN_WARNING, "newfid fails!\n"); |
641 | return ERR_PTR(-ENOSPC); | 643 | result = -ENOSPC; |
644 | goto Release_Dirfid; | ||
642 | } | 645 | } |
643 | 646 | ||
644 | result = v9fs_t_walk(v9ses, dirfidnum, newfid, | 647 | result = v9fs_t_walk(v9ses, dirfidnum, newfid, |
645 | (char *)dentry->d_name.name, &fcall); | 648 | (char *)dentry->d_name.name, &fcall); |
646 | 649 | ||
650 | up(&dirfid->lock); | ||
651 | |||
647 | if (result < 0) { | 652 | if (result < 0) { |
648 | if (fcall && fcall->id == RWALK) | 653 | if (fcall && fcall->id == RWALK) |
649 | v9fs_t_clunk(v9ses, newfid); | 654 | v9fs_t_clunk(v9ses, newfid); |
@@ -701,8 +706,12 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, | |||
701 | 706 | ||
702 | return NULL; | 707 | return NULL; |
703 | 708 | ||
704 | FreeFcall: | 709 | Release_Dirfid: |
710 | up(&dirfid->lock); | ||
711 | |||
712 | FreeFcall: | ||
705 | kfree(fcall); | 713 | kfree(fcall); |
714 | |||
706 | return ERR_PTR(result); | 715 | return ERR_PTR(result); |
707 | } | 716 | } |
708 | 717 | ||
@@ -746,10 +755,8 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
746 | struct inode *old_inode = old_dentry->d_inode; | 755 | struct inode *old_inode = old_dentry->d_inode; |
747 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(old_inode); | 756 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(old_inode); |
748 | struct v9fs_fid *oldfid = v9fs_fid_lookup(old_dentry); | 757 | struct v9fs_fid *oldfid = v9fs_fid_lookup(old_dentry); |
749 | struct v9fs_fid *olddirfid = | 758 | struct v9fs_fid *olddirfid; |
750 | v9fs_fid_lookup(old_dentry->d_parent); | 759 | struct v9fs_fid *newdirfid; |
751 | struct v9fs_fid *newdirfid = | ||
752 | v9fs_fid_lookup(new_dentry->d_parent); | ||
753 | struct v9fs_wstat wstat; | 760 | struct v9fs_wstat wstat; |
754 | struct v9fs_fcall *fcall = NULL; | 761 | struct v9fs_fcall *fcall = NULL; |
755 | int fid = -1; | 762 | int fid = -1; |
@@ -759,16 +766,26 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
759 | 766 | ||
760 | dprintk(DEBUG_VFS, "\n"); | 767 | dprintk(DEBUG_VFS, "\n"); |
761 | 768 | ||
762 | if ((!oldfid) || (!olddirfid) || (!newdirfid)) { | 769 | if(IS_ERR(oldfid)) |
763 | dprintk(DEBUG_ERROR, "problem with arguments\n"); | 770 | return PTR_ERR(oldfid); |
764 | return -EBADF; | 771 | |
772 | olddirfid = v9fs_fid_clone(old_dentry->d_parent); | ||
773 | if(IS_ERR(olddirfid)) { | ||
774 | retval = PTR_ERR(olddirfid); | ||
775 | goto Release_lock; | ||
776 | } | ||
777 | |||
778 | newdirfid = v9fs_fid_clone(new_dentry->d_parent); | ||
779 | if(IS_ERR(newdirfid)) { | ||
780 | retval = PTR_ERR(newdirfid); | ||
781 | goto Clunk_olddir; | ||
765 | } | 782 | } |
766 | 783 | ||
767 | /* 9P can only handle file rename in the same directory */ | 784 | /* 9P can only handle file rename in the same directory */ |
768 | if (memcmp(&olddirfid->qid, &newdirfid->qid, sizeof(newdirfid->qid))) { | 785 | if (memcmp(&olddirfid->qid, &newdirfid->qid, sizeof(newdirfid->qid))) { |
769 | dprintk(DEBUG_ERROR, "old dir and new dir are different\n"); | 786 | dprintk(DEBUG_ERROR, "old dir and new dir are different\n"); |
770 | retval = -EPERM; | 787 | retval = -EXDEV; |
771 | goto FreeFcallnBail; | 788 | goto Clunk_newdir; |
772 | } | 789 | } |
773 | 790 | ||
774 | fid = oldfid->fid; | 791 | fid = oldfid->fid; |
@@ -779,7 +796,7 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
779 | dprintk(DEBUG_ERROR, "no fid for old file #%lu\n", | 796 | dprintk(DEBUG_ERROR, "no fid for old file #%lu\n", |
780 | old_inode->i_ino); | 797 | old_inode->i_ino); |
781 | retval = -EBADF; | 798 | retval = -EBADF; |
782 | goto FreeFcallnBail; | 799 | goto Clunk_newdir; |
783 | } | 800 | } |
784 | 801 | ||
785 | v9fs_blank_wstat(&wstat); | 802 | v9fs_blank_wstat(&wstat); |
@@ -788,11 +805,20 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
788 | 805 | ||
789 | retval = v9fs_t_wstat(v9ses, fid, &wstat, &fcall); | 806 | retval = v9fs_t_wstat(v9ses, fid, &wstat, &fcall); |
790 | 807 | ||
791 | FreeFcallnBail: | ||
792 | if (retval < 0) | 808 | if (retval < 0) |
793 | PRINT_FCALL_ERROR("wstat error", fcall); | 809 | PRINT_FCALL_ERROR("wstat error", fcall); |
794 | 810 | ||
795 | kfree(fcall); | 811 | kfree(fcall); |
812 | |||
813 | Clunk_newdir: | ||
814 | v9fs_fid_clunk(v9ses, newdirfid); | ||
815 | |||
816 | Clunk_olddir: | ||
817 | v9fs_fid_clunk(v9ses, olddirfid); | ||
818 | |||
819 | Release_lock: | ||
820 | up(&oldfid->lock); | ||
821 | |||
796 | return retval; | 822 | return retval; |
797 | } | 823 | } |
798 | 824 | ||
@@ -810,15 +836,12 @@ v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, | |||
810 | { | 836 | { |
811 | struct v9fs_fcall *fcall = NULL; | 837 | struct v9fs_fcall *fcall = NULL; |
812 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode); | 838 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode); |
813 | struct v9fs_fid *fid = v9fs_fid_lookup(dentry); | 839 | struct v9fs_fid *fid = v9fs_fid_clone(dentry); |
814 | int err = -EPERM; | 840 | int err = -EPERM; |
815 | 841 | ||
816 | dprintk(DEBUG_VFS, "dentry: %p\n", dentry); | 842 | dprintk(DEBUG_VFS, "dentry: %p\n", dentry); |
817 | if (!fid) { | 843 | if(IS_ERR(fid)) |
818 | dprintk(DEBUG_ERROR, | 844 | return PTR_ERR(fid); |
819 | "couldn't find fid associated with dentry\n"); | ||
820 | return -EBADF; | ||
821 | } | ||
822 | 845 | ||
823 | err = v9fs_t_stat(v9ses, fid->fid, &fcall); | 846 | err = v9fs_t_stat(v9ses, fid->fid, &fcall); |
824 | 847 | ||
@@ -831,6 +854,7 @@ v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, | |||
831 | } | 854 | } |
832 | 855 | ||
833 | kfree(fcall); | 856 | kfree(fcall); |
857 | v9fs_fid_clunk(v9ses, fid); | ||
834 | return err; | 858 | return err; |
835 | } | 859 | } |
836 | 860 | ||
@@ -844,18 +868,14 @@ v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, | |||
844 | static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr) | 868 | static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr) |
845 | { | 869 | { |
846 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode); | 870 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode); |
847 | struct v9fs_fid *fid = v9fs_fid_lookup(dentry); | 871 | struct v9fs_fid *fid = v9fs_fid_clone(dentry); |
848 | struct v9fs_fcall *fcall = NULL; | 872 | struct v9fs_fcall *fcall = NULL; |
849 | struct v9fs_wstat wstat; | 873 | struct v9fs_wstat wstat; |
850 | int res = -EPERM; | 874 | int res = -EPERM; |
851 | 875 | ||
852 | dprintk(DEBUG_VFS, "\n"); | 876 | dprintk(DEBUG_VFS, "\n"); |
853 | 877 | if(IS_ERR(fid)) | |
854 | if (!fid) { | 878 | return PTR_ERR(fid); |
855 | dprintk(DEBUG_ERROR, | ||
856 | "Couldn't find fid associated with dentry\n"); | ||
857 | return -EBADF; | ||
858 | } | ||
859 | 879 | ||
860 | v9fs_blank_wstat(&wstat); | 880 | v9fs_blank_wstat(&wstat); |
861 | if (iattr->ia_valid & ATTR_MODE) | 881 | if (iattr->ia_valid & ATTR_MODE) |
@@ -887,6 +907,7 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr) | |||
887 | if (res >= 0) | 907 | if (res >= 0) |
888 | res = inode_setattr(dentry->d_inode, iattr); | 908 | res = inode_setattr(dentry->d_inode, iattr); |
889 | 909 | ||
910 | v9fs_fid_clunk(v9ses, fid); | ||
890 | return res; | 911 | return res; |
891 | } | 912 | } |
892 | 913 | ||
@@ -987,18 +1008,15 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen) | |||
987 | 1008 | ||
988 | struct v9fs_fcall *fcall = NULL; | 1009 | struct v9fs_fcall *fcall = NULL; |
989 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode); | 1010 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode); |
990 | struct v9fs_fid *fid = v9fs_fid_lookup(dentry); | 1011 | struct v9fs_fid *fid = v9fs_fid_clone(dentry); |
991 | 1012 | ||
992 | if (!fid) { | 1013 | if(IS_ERR(fid)) |
993 | dprintk(DEBUG_ERROR, "could not resolve fid from dentry\n"); | 1014 | return PTR_ERR(fid); |
994 | retval = -EBADF; | ||
995 | goto FreeFcall; | ||
996 | } | ||
997 | 1015 | ||
998 | if (!v9ses->extended) { | 1016 | if (!v9ses->extended) { |
999 | retval = -EBADF; | 1017 | retval = -EBADF; |
1000 | dprintk(DEBUG_ERROR, "not extended\n"); | 1018 | dprintk(DEBUG_ERROR, "not extended\n"); |
1001 | goto FreeFcall; | 1019 | goto ClunkFid; |
1002 | } | 1020 | } |
1003 | 1021 | ||
1004 | dprintk(DEBUG_VFS, " %s\n", dentry->d_name.name); | 1022 | dprintk(DEBUG_VFS, " %s\n", dentry->d_name.name); |
@@ -1009,8 +1027,10 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen) | |||
1009 | goto FreeFcall; | 1027 | goto FreeFcall; |
1010 | } | 1028 | } |
1011 | 1029 | ||
1012 | if (!fcall) | 1030 | if (!fcall) { |
1013 | return -EIO; | 1031 | retval = -EIO; |
1032 | goto ClunkFid; | ||
1033 | } | ||
1014 | 1034 | ||
1015 | if (!(fcall->params.rstat.stat.mode & V9FS_DMSYMLINK)) { | 1035 | if (!(fcall->params.rstat.stat.mode & V9FS_DMSYMLINK)) { |
1016 | retval = -EINVAL; | 1036 | retval = -EINVAL; |
@@ -1028,9 +1048,12 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen) | |||
1028 | fcall->params.rstat.stat.extension.str, buffer); | 1048 | fcall->params.rstat.stat.extension.str, buffer); |
1029 | retval = buflen; | 1049 | retval = buflen; |
1030 | 1050 | ||
1031 | FreeFcall: | 1051 | FreeFcall: |
1032 | kfree(fcall); | 1052 | kfree(fcall); |
1033 | 1053 | ||
1054 | ClunkFid: | ||
1055 | v9fs_fid_clunk(v9ses, fid); | ||
1056 | |||
1034 | return retval; | 1057 | return retval; |
1035 | } | 1058 | } |
1036 | 1059 | ||
@@ -1123,52 +1146,58 @@ static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry, | |||
1123 | int err; | 1146 | int err; |
1124 | u32 fid, perm; | 1147 | u32 fid, perm; |
1125 | struct v9fs_session_info *v9ses; | 1148 | struct v9fs_session_info *v9ses; |
1126 | struct v9fs_fid *dfid, *vfid; | 1149 | struct v9fs_fid *dfid, *vfid = NULL; |
1127 | struct inode *inode; | 1150 | struct inode *inode = NULL; |
1128 | 1151 | ||
1129 | inode = NULL; | ||
1130 | vfid = NULL; | ||
1131 | v9ses = v9fs_inode2v9ses(dir); | 1152 | v9ses = v9fs_inode2v9ses(dir); |
1132 | dfid = v9fs_fid_lookup(dentry->d_parent); | ||
1133 | perm = unixmode2p9mode(v9ses, mode); | ||
1134 | |||
1135 | if (!v9ses->extended) { | 1153 | if (!v9ses->extended) { |
1136 | dprintk(DEBUG_ERROR, "not extended\n"); | 1154 | dprintk(DEBUG_ERROR, "not extended\n"); |
1137 | return -EPERM; | 1155 | return -EPERM; |
1138 | } | 1156 | } |
1139 | 1157 | ||
1158 | dfid = v9fs_fid_clone(dentry->d_parent); | ||
1159 | if(IS_ERR(dfid)) { | ||
1160 | err = PTR_ERR(dfid); | ||
1161 | goto error; | ||
1162 | } | ||
1163 | |||
1164 | perm = unixmode2p9mode(v9ses, mode); | ||
1165 | |||
1140 | err = v9fs_create(v9ses, dfid->fid, (char *) dentry->d_name.name, | 1166 | err = v9fs_create(v9ses, dfid->fid, (char *) dentry->d_name.name, |
1141 | perm, V9FS_OREAD, (char *) extension, &fid, NULL, NULL); | 1167 | perm, V9FS_OREAD, (char *) extension, &fid, NULL, NULL); |
1142 | 1168 | ||
1143 | if (err) | 1169 | if (err) |
1144 | goto error; | 1170 | goto clunk_dfid; |
1145 | 1171 | ||
1146 | err = v9fs_t_clunk(v9ses, fid); | 1172 | err = v9fs_t_clunk(v9ses, fid); |
1147 | if (err) | 1173 | if (err) |
1148 | goto error; | 1174 | goto clunk_dfid; |
1149 | 1175 | ||
1150 | vfid = v9fs_clone_walk(v9ses, dfid->fid, dentry); | 1176 | vfid = v9fs_clone_walk(v9ses, dfid->fid, dentry); |
1151 | if (IS_ERR(vfid)) { | 1177 | if (IS_ERR(vfid)) { |
1152 | err = PTR_ERR(vfid); | 1178 | err = PTR_ERR(vfid); |
1153 | vfid = NULL; | 1179 | vfid = NULL; |
1154 | goto error; | 1180 | goto clunk_dfid; |
1155 | } | 1181 | } |
1156 | 1182 | ||
1157 | inode = v9fs_inode_from_fid(v9ses, vfid->fid, dir->i_sb); | 1183 | inode = v9fs_inode_from_fid(v9ses, vfid->fid, dir->i_sb); |
1158 | if (IS_ERR(inode)) { | 1184 | if (IS_ERR(inode)) { |
1159 | err = PTR_ERR(inode); | 1185 | err = PTR_ERR(inode); |
1160 | inode = NULL; | 1186 | inode = NULL; |
1161 | goto error; | 1187 | goto free_vfid; |
1162 | } | 1188 | } |
1163 | 1189 | ||
1164 | dentry->d_op = &v9fs_dentry_operations; | 1190 | dentry->d_op = &v9fs_dentry_operations; |
1165 | d_instantiate(dentry, inode); | 1191 | d_instantiate(dentry, inode); |
1166 | return 0; | 1192 | return 0; |
1167 | 1193 | ||
1168 | error: | 1194 | free_vfid: |
1169 | if (vfid) | 1195 | v9fs_fid_destroy(vfid); |
1170 | v9fs_fid_destroy(vfid); | 1196 | |
1197 | clunk_dfid: | ||
1198 | v9fs_fid_clunk(v9ses, dfid); | ||
1171 | 1199 | ||
1200 | error: | ||
1172 | return err; | 1201 | return err; |
1173 | 1202 | ||
1174 | } | 1203 | } |
@@ -1209,26 +1238,29 @@ v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir, | |||
1209 | struct dentry *dentry) | 1238 | struct dentry *dentry) |
1210 | { | 1239 | { |
1211 | int retval; | 1240 | int retval; |
1241 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir); | ||
1212 | struct v9fs_fid *oldfid; | 1242 | struct v9fs_fid *oldfid; |
1213 | char *name; | 1243 | char *name; |
1214 | 1244 | ||
1215 | dprintk(DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name, | 1245 | dprintk(DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name, |
1216 | old_dentry->d_name.name); | 1246 | old_dentry->d_name.name); |
1217 | 1247 | ||
1218 | oldfid = v9fs_fid_lookup(old_dentry); | 1248 | oldfid = v9fs_fid_clone(old_dentry); |
1219 | if (!oldfid) { | 1249 | if(IS_ERR(oldfid)) |
1220 | dprintk(DEBUG_ERROR, "can't find oldfid\n"); | 1250 | return PTR_ERR(oldfid); |
1221 | return -EPERM; | ||
1222 | } | ||
1223 | 1251 | ||
1224 | name = __getname(); | 1252 | name = __getname(); |
1225 | if (unlikely(!name)) | 1253 | if (unlikely(!name)) { |
1226 | return -ENOMEM; | 1254 | retval = -ENOMEM; |
1255 | goto clunk_fid; | ||
1256 | } | ||
1227 | 1257 | ||
1228 | sprintf(name, "%d\n", oldfid->fid); | 1258 | sprintf(name, "%d\n", oldfid->fid); |
1229 | retval = v9fs_vfs_mkspecial(dir, dentry, V9FS_DMLINK, name); | 1259 | retval = v9fs_vfs_mkspecial(dir, dentry, V9FS_DMLINK, name); |
1230 | __putname(name); | 1260 | __putname(name); |
1231 | 1261 | ||
1262 | clunk_fid: | ||
1263 | v9fs_fid_clunk(v9ses, oldfid); | ||
1232 | return retval; | 1264 | return retval; |
1233 | } | 1265 | } |
1234 | 1266 | ||
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 7cb28720f90e..669dbe5b0317 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c | |||
@@ -682,6 +682,15 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
682 | retval = PTR_ERR(interpreter); | 682 | retval = PTR_ERR(interpreter); |
683 | if (IS_ERR(interpreter)) | 683 | if (IS_ERR(interpreter)) |
684 | goto out_free_interp; | 684 | goto out_free_interp; |
685 | |||
686 | /* | ||
687 | * If the binary is not readable then enforce | ||
688 | * mm->dumpable = 0 regardless of the interpreter's | ||
689 | * permissions. | ||
690 | */ | ||
691 | if (file_permission(interpreter, MAY_READ) < 0) | ||
692 | bprm->interp_flags |= BINPRM_FLAGS_ENFORCE_NONDUMP; | ||
693 | |||
685 | retval = kernel_read(interpreter, 0, bprm->buf, | 694 | retval = kernel_read(interpreter, 0, bprm->buf, |
686 | BINPRM_BUF_SIZE); | 695 | BINPRM_BUF_SIZE); |
687 | if (retval != BINPRM_BUF_SIZE) { | 696 | if (retval != BINPRM_BUF_SIZE) { |
@@ -1178,6 +1187,10 @@ static int dump_seek(struct file *file, loff_t off) | |||
1178 | */ | 1187 | */ |
1179 | static int maydump(struct vm_area_struct *vma) | 1188 | static int maydump(struct vm_area_struct *vma) |
1180 | { | 1189 | { |
1190 | /* The vma can be set up to tell us the answer directly. */ | ||
1191 | if (vma->vm_flags & VM_ALWAYSDUMP) | ||
1192 | return 1; | ||
1193 | |||
1181 | /* Do not dump I/O mapped devices or special mappings */ | 1194 | /* Do not dump I/O mapped devices or special mappings */ |
1182 | if (vma->vm_flags & (VM_IO | VM_RESERVED)) | 1195 | if (vma->vm_flags & (VM_IO | VM_RESERVED)) |
1183 | return 0; | 1196 | return 0; |
@@ -1424,6 +1437,32 @@ static int elf_dump_thread_status(long signr, struct elf_thread_status *t) | |||
1424 | return sz; | 1437 | return sz; |
1425 | } | 1438 | } |
1426 | 1439 | ||
1440 | static struct vm_area_struct *first_vma(struct task_struct *tsk, | ||
1441 | struct vm_area_struct *gate_vma) | ||
1442 | { | ||
1443 | struct vm_area_struct *ret = tsk->mm->mmap; | ||
1444 | |||
1445 | if (ret) | ||
1446 | return ret; | ||
1447 | return gate_vma; | ||
1448 | } | ||
1449 | /* | ||
1450 | * Helper function for iterating across a vma list. It ensures that the caller | ||
1451 | * will visit `gate_vma' prior to terminating the search. | ||
1452 | */ | ||
1453 | static struct vm_area_struct *next_vma(struct vm_area_struct *this_vma, | ||
1454 | struct vm_area_struct *gate_vma) | ||
1455 | { | ||
1456 | struct vm_area_struct *ret; | ||
1457 | |||
1458 | ret = this_vma->vm_next; | ||
1459 | if (ret) | ||
1460 | return ret; | ||
1461 | if (this_vma == gate_vma) | ||
1462 | return NULL; | ||
1463 | return gate_vma; | ||
1464 | } | ||
1465 | |||
1427 | /* | 1466 | /* |
1428 | * Actual dumper | 1467 | * Actual dumper |
1429 | * | 1468 | * |
@@ -1439,7 +1478,7 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) | |||
1439 | int segs; | 1478 | int segs; |
1440 | size_t size = 0; | 1479 | size_t size = 0; |
1441 | int i; | 1480 | int i; |
1442 | struct vm_area_struct *vma; | 1481 | struct vm_area_struct *vma, *gate_vma; |
1443 | struct elfhdr *elf = NULL; | 1482 | struct elfhdr *elf = NULL; |
1444 | loff_t offset = 0, dataoff, foffset; | 1483 | loff_t offset = 0, dataoff, foffset; |
1445 | unsigned long limit = current->signal->rlim[RLIMIT_CORE].rlim_cur; | 1484 | unsigned long limit = current->signal->rlim[RLIMIT_CORE].rlim_cur; |
@@ -1525,6 +1564,10 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) | |||
1525 | segs += ELF_CORE_EXTRA_PHDRS; | 1564 | segs += ELF_CORE_EXTRA_PHDRS; |
1526 | #endif | 1565 | #endif |
1527 | 1566 | ||
1567 | gate_vma = get_gate_vma(current); | ||
1568 | if (gate_vma != NULL) | ||
1569 | segs++; | ||
1570 | |||
1528 | /* Set up header */ | 1571 | /* Set up header */ |
1529 | fill_elf_header(elf, segs + 1); /* including notes section */ | 1572 | fill_elf_header(elf, segs + 1); /* including notes section */ |
1530 | 1573 | ||
@@ -1592,7 +1635,8 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) | |||
1592 | dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE); | 1635 | dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE); |
1593 | 1636 | ||
1594 | /* Write program headers for segments dump */ | 1637 | /* Write program headers for segments dump */ |
1595 | for (vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) { | 1638 | for (vma = first_vma(current, gate_vma); vma != NULL; |
1639 | vma = next_vma(vma, gate_vma)) { | ||
1596 | struct elf_phdr phdr; | 1640 | struct elf_phdr phdr; |
1597 | size_t sz; | 1641 | size_t sz; |
1598 | 1642 | ||
@@ -1641,7 +1685,8 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) | |||
1641 | /* Align to page */ | 1685 | /* Align to page */ |
1642 | DUMP_SEEK(dataoff - foffset); | 1686 | DUMP_SEEK(dataoff - foffset); |
1643 | 1687 | ||
1644 | for (vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) { | 1688 | for (vma = first_vma(current, gate_vma); vma != NULL; |
1689 | vma = next_vma(vma, gate_vma)) { | ||
1645 | unsigned long addr; | 1690 | unsigned long addr; |
1646 | 1691 | ||
1647 | if (!maydump(vma)) | 1692 | if (!maydump(vma)) |
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index 6e6d4568d548..a4d933a51208 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c | |||
@@ -234,6 +234,14 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm, | |||
234 | goto error; | 234 | goto error; |
235 | } | 235 | } |
236 | 236 | ||
237 | /* | ||
238 | * If the binary is not readable then enforce | ||
239 | * mm->dumpable = 0 regardless of the interpreter's | ||
240 | * permissions. | ||
241 | */ | ||
242 | if (file_permission(interpreter, MAY_READ) < 0) | ||
243 | bprm->interp_flags |= BINPRM_FLAGS_ENFORCE_NONDUMP; | ||
244 | |||
237 | retval = kernel_read(interpreter, 0, bprm->buf, | 245 | retval = kernel_read(interpreter, 0, bprm->buf, |
238 | BINPRM_BUF_SIZE); | 246 | BINPRM_BUF_SIZE); |
239 | if (retval < 0) | 247 | if (retval < 0) |
diff --git a/fs/block_dev.c b/fs/block_dev.c index 8b18e43b82fe..d9bdf2b3ade2 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
@@ -146,7 +146,7 @@ static int blk_end_aio(struct bio *bio, unsigned int bytes_done, int error) | |||
146 | iocb->ki_nbytes = -EIO; | 146 | iocb->ki_nbytes = -EIO; |
147 | 147 | ||
148 | if (atomic_dec_and_test(bio_count)) { | 148 | if (atomic_dec_and_test(bio_count)) { |
149 | if (iocb->ki_nbytes < 0) | 149 | if ((long)iocb->ki_nbytes < 0) |
150 | aio_complete(iocb, iocb->ki_nbytes, 0); | 150 | aio_complete(iocb, iocb->ki_nbytes, 0); |
151 | else | 151 | else |
152 | aio_complete(iocb, iocb->ki_left, 0); | 152 | aio_complete(iocb, iocb->ki_left, 0); |
@@ -190,6 +190,12 @@ static struct page *blk_get_page(unsigned long addr, size_t count, int rw, | |||
190 | return pvec->page[pvec->idx++]; | 190 | return pvec->page[pvec->idx++]; |
191 | } | 191 | } |
192 | 192 | ||
193 | /* return a page back to pvec array */ | ||
194 | static void blk_unget_page(struct page *page, struct pvec *pvec) | ||
195 | { | ||
196 | pvec->page[--pvec->idx] = page; | ||
197 | } | ||
198 | |||
193 | static ssize_t | 199 | static ssize_t |
194 | blkdev_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, | 200 | blkdev_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, |
195 | loff_t pos, unsigned long nr_segs) | 201 | loff_t pos, unsigned long nr_segs) |
@@ -278,6 +284,8 @@ same_bio: | |||
278 | count = min(count, nbytes); | 284 | count = min(count, nbytes); |
279 | goto same_bio; | 285 | goto same_bio; |
280 | } | 286 | } |
287 | } else { | ||
288 | blk_unget_page(page, &pvec); | ||
281 | } | 289 | } |
282 | 290 | ||
283 | /* bio is ready, submit it */ | 291 | /* bio is ready, submit it */ |
diff --git a/fs/buffer.c b/fs/buffer.c index 3b116078b4c3..1ad674fd348c 100644 --- a/fs/buffer.c +++ b/fs/buffer.c | |||
@@ -2834,7 +2834,7 @@ int try_to_free_buffers(struct page *page) | |||
2834 | int ret = 0; | 2834 | int ret = 0; |
2835 | 2835 | ||
2836 | BUG_ON(!PageLocked(page)); | 2836 | BUG_ON(!PageLocked(page)); |
2837 | if (PageDirty(page) || PageWriteback(page)) | 2837 | if (PageWriteback(page)) |
2838 | return 0; | 2838 | return 0; |
2839 | 2839 | ||
2840 | if (mapping == NULL) { /* can this still happen? */ | 2840 | if (mapping == NULL) { /* can this still happen? */ |
@@ -2844,6 +2844,23 @@ int try_to_free_buffers(struct page *page) | |||
2844 | 2844 | ||
2845 | spin_lock(&mapping->private_lock); | 2845 | spin_lock(&mapping->private_lock); |
2846 | ret = drop_buffers(page, &buffers_to_free); | 2846 | ret = drop_buffers(page, &buffers_to_free); |
2847 | |||
2848 | /* | ||
2849 | * If the filesystem writes its buffers by hand (eg ext3) | ||
2850 | * then we can have clean buffers against a dirty page. We | ||
2851 | * clean the page here; otherwise the VM will never notice | ||
2852 | * that the filesystem did any IO at all. | ||
2853 | * | ||
2854 | * Also, during truncate, discard_buffer will have marked all | ||
2855 | * the page's buffers clean. We discover that here and clean | ||
2856 | * the page also. | ||
2857 | * | ||
2858 | * private_lock must be held over this entire operation in order | ||
2859 | * to synchronise against __set_page_dirty_buffers and prevent the | ||
2860 | * dirty bit from being lost. | ||
2861 | */ | ||
2862 | if (ret) | ||
2863 | cancel_dirty_page(page, PAGE_CACHE_SIZE); | ||
2847 | spin_unlock(&mapping->private_lock); | 2864 | spin_unlock(&mapping->private_lock); |
2848 | out: | 2865 | out: |
2849 | if (buffers_to_free) { | 2866 | if (buffers_to_free) { |
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 3539d6ef9611..d04d2f7448d9 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES | |||
@@ -1,3 +1,7 @@ | |||
1 | Version 1.47 | ||
2 | ------------ | ||
3 | Fix oops in list_del during mount caused by unaligned string. | ||
4 | |||
1 | Version 1.46 | 5 | Version 1.46 |
2 | ------------ | 6 | ------------ |
3 | Support deep tree mounts. Better support OS/2, Win9x (DOS) time stamps. | 7 | Support deep tree mounts. Better support OS/2, Win9x (DOS) time stamps. |
diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 96abeb738978..6017c465440e 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c | |||
@@ -143,8 +143,8 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, | |||
143 | ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); | 143 | ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); |
144 | if((ses->serverDomain == NULL) || (ses->serverOS == NULL) || | 144 | if((ses->serverDomain == NULL) || (ses->serverOS == NULL) || |
145 | (ses->serverNOS == NULL)) { | 145 | (ses->serverNOS == NULL)) { |
146 | buf += sprintf("\nentry for %s not fully displayed\n\t", | 146 | buf += sprintf(buf, "\nentry for %s not fully " |
147 | ses->serverName); | 147 | "displayed\n\t", ses->serverName); |
148 | 148 | ||
149 | } else { | 149 | } else { |
150 | length = | 150 | length = |
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index a243f779b363..8aa66dcf13bd 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h | |||
@@ -100,5 +100,5 @@ extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t); | |||
100 | extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); | 100 | extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); |
101 | extern int cifs_ioctl (struct inode * inode, struct file * filep, | 101 | extern int cifs_ioctl (struct inode * inode, struct file * filep, |
102 | unsigned int command, unsigned long arg); | 102 | unsigned int command, unsigned long arg); |
103 | #define CIFS_VERSION "1.46" | 103 | #define CIFS_VERSION "1.47" |
104 | #endif /* _CIFSFS_H */ | 104 | #endif /* _CIFSFS_H */ |
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index aedf683f011f..19cc294c7c70 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c | |||
@@ -71,9 +71,7 @@ sesInfoAlloc(void) | |||
71 | { | 71 | { |
72 | struct cifsSesInfo *ret_buf; | 72 | struct cifsSesInfo *ret_buf; |
73 | 73 | ||
74 | ret_buf = | 74 | ret_buf = kzalloc(sizeof (struct cifsSesInfo), GFP_KERNEL); |
75 | (struct cifsSesInfo *) kzalloc(sizeof (struct cifsSesInfo), | ||
76 | GFP_KERNEL); | ||
77 | if (ret_buf) { | 75 | if (ret_buf) { |
78 | write_lock(&GlobalSMBSeslock); | 76 | write_lock(&GlobalSMBSeslock); |
79 | atomic_inc(&sesInfoAllocCount); | 77 | atomic_inc(&sesInfoAllocCount); |
@@ -109,9 +107,7 @@ struct cifsTconInfo * | |||
109 | tconInfoAlloc(void) | 107 | tconInfoAlloc(void) |
110 | { | 108 | { |
111 | struct cifsTconInfo *ret_buf; | 109 | struct cifsTconInfo *ret_buf; |
112 | ret_buf = | 110 | ret_buf = kzalloc(sizeof (struct cifsTconInfo), GFP_KERNEL); |
113 | (struct cifsTconInfo *) kzalloc(sizeof (struct cifsTconInfo), | ||
114 | GFP_KERNEL); | ||
115 | if (ret_buf) { | 111 | if (ret_buf) { |
116 | write_lock(&GlobalSMBSeslock); | 112 | write_lock(&GlobalSMBSeslock); |
117 | atomic_inc(&tconInfoAllocCount); | 113 | atomic_inc(&tconInfoAllocCount); |
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index bbdda99dce61..758464630893 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c | |||
@@ -182,11 +182,14 @@ static int decode_unicode_ssetup(char ** pbcc_area, int bleft, struct cifsSesInf | |||
182 | cFYI(1,("bleft %d",bleft)); | 182 | cFYI(1,("bleft %d",bleft)); |
183 | 183 | ||
184 | 184 | ||
185 | /* word align, if bytes remaining is not even */ | 185 | /* SMB header is unaligned, so cifs servers word align start of |
186 | if(bleft % 2) { | 186 | Unicode strings */ |
187 | bleft--; | 187 | data++; |
188 | data++; | 188 | bleft--; /* Windows servers do not always double null terminate |
189 | } | 189 | their final Unicode string - in which case we |
190 | now will not attempt to decode the byte of junk | ||
191 | which follows it */ | ||
192 | |||
190 | words_left = bleft / 2; | 193 | words_left = bleft / 2; |
191 | 194 | ||
192 | /* save off server operating system */ | 195 | /* save off server operating system */ |
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index c403b66ec83c..a4b142a6a2c7 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c | |||
@@ -251,8 +251,19 @@ __writeback_single_inode(struct inode *inode, struct writeback_control *wbc) | |||
251 | WARN_ON(inode->i_state & I_WILL_FREE); | 251 | WARN_ON(inode->i_state & I_WILL_FREE); |
252 | 252 | ||
253 | if ((wbc->sync_mode != WB_SYNC_ALL) && (inode->i_state & I_LOCK)) { | 253 | if ((wbc->sync_mode != WB_SYNC_ALL) && (inode->i_state & I_LOCK)) { |
254 | struct address_space *mapping = inode->i_mapping; | ||
255 | int ret; | ||
256 | |||
254 | list_move(&inode->i_list, &inode->i_sb->s_dirty); | 257 | list_move(&inode->i_list, &inode->i_sb->s_dirty); |
255 | return 0; | 258 | |
259 | /* | ||
260 | * Even if we don't actually write the inode itself here, | ||
261 | * we can at least start some of the data writeout.. | ||
262 | */ | ||
263 | spin_unlock(&inode_lock); | ||
264 | ret = do_writepages(mapping, wbc); | ||
265 | spin_lock(&inode_lock); | ||
266 | return ret; | ||
256 | } | 267 | } |
257 | 268 | ||
258 | /* | 269 | /* |
diff --git a/fs/fuse/control.c b/fs/fuse/control.c index 8c58bd453993..1794305f9ed8 100644 --- a/fs/fuse/control.c +++ b/fs/fuse/control.c | |||
@@ -193,8 +193,12 @@ static int fuse_ctl_get_sb(struct file_system_type *fs_type, int flags, | |||
193 | 193 | ||
194 | static void fuse_ctl_kill_sb(struct super_block *sb) | 194 | static void fuse_ctl_kill_sb(struct super_block *sb) |
195 | { | 195 | { |
196 | struct fuse_conn *fc; | ||
197 | |||
196 | mutex_lock(&fuse_mutex); | 198 | mutex_lock(&fuse_mutex); |
197 | fuse_control_sb = NULL; | 199 | fuse_control_sb = NULL; |
200 | list_for_each_entry(fc, &fuse_conn_list, entry) | ||
201 | fc->ctl_ndents = 0; | ||
198 | mutex_unlock(&fuse_mutex); | 202 | mutex_unlock(&fuse_mutex); |
199 | 203 | ||
200 | kill_litter_super(sb); | 204 | kill_litter_super(sb); |
diff --git a/fs/hostfs/hostfs.h b/fs/hostfs/hostfs.h index cca3fb693f99..70543b17e4c7 100644 --- a/fs/hostfs/hostfs.h +++ b/fs/hostfs/hostfs.h | |||
@@ -76,7 +76,7 @@ extern int make_symlink(const char *from, const char *to); | |||
76 | extern int unlink_file(const char *file); | 76 | extern int unlink_file(const char *file); |
77 | extern int do_mkdir(const char *file, int mode); | 77 | extern int do_mkdir(const char *file, int mode); |
78 | extern int do_rmdir(const char *file); | 78 | extern int do_rmdir(const char *file); |
79 | extern int do_mknod(const char *file, int mode, int dev); | 79 | extern int do_mknod(const char *file, int mode, unsigned int major, unsigned int minor); |
80 | extern int link_file(const char *from, const char *to); | 80 | extern int link_file(const char *from, const char *to); |
81 | extern int do_readlink(char *file, char *buf, int size); | 81 | extern int do_readlink(char *file, char *buf, int size); |
82 | extern int rename_file(char *from, char *to); | 82 | extern int rename_file(char *from, char *to); |
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index 1e6fc3799876..69a376f35a68 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c | |||
@@ -755,7 +755,7 @@ int hostfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) | |||
755 | goto out_put; | 755 | goto out_put; |
756 | 756 | ||
757 | init_special_inode(inode, mode, dev); | 757 | init_special_inode(inode, mode, dev); |
758 | err = do_mknod(name, mode, dev); | 758 | err = do_mknod(name, mode, MAJOR(dev), MINOR(dev)); |
759 | if(err) | 759 | if(err) |
760 | goto out_free; | 760 | goto out_free; |
761 | 761 | ||
diff --git a/fs/hostfs/hostfs_user.c b/fs/hostfs/hostfs_user.c index 23b7cee72123..1ed5ea389f15 100644 --- a/fs/hostfs/hostfs_user.c +++ b/fs/hostfs/hostfs_user.c | |||
@@ -295,11 +295,11 @@ int do_rmdir(const char *file) | |||
295 | return(0); | 295 | return(0); |
296 | } | 296 | } |
297 | 297 | ||
298 | int do_mknod(const char *file, int mode, int dev) | 298 | int do_mknod(const char *file, int mode, unsigned int major, unsigned int minor) |
299 | { | 299 | { |
300 | int err; | 300 | int err; |
301 | 301 | ||
302 | err = mknod(file, mode, dev); | 302 | err = mknod(file, mode, makedev(major, minor)); |
303 | if(err) return(-errno); | 303 | if(err) return(-errno); |
304 | return(0); | 304 | return(0); |
305 | } | 305 | } |
diff --git a/fs/jffs/jffs_fm.c b/fs/jffs/jffs_fm.c index 077258b2103e..5a95fbdd6fdb 100644 --- a/fs/jffs/jffs_fm.c +++ b/fs/jffs/jffs_fm.c | |||
@@ -17,6 +17,7 @@ | |||
17 | * | 17 | * |
18 | */ | 18 | */ |
19 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
20 | #include <linux/err.h> | ||
20 | #include <linux/blkdev.h> | 21 | #include <linux/blkdev.h> |
21 | #include <linux/jffs.h> | 22 | #include <linux/jffs.h> |
22 | #include "jffs_fm.h" | 23 | #include "jffs_fm.h" |
@@ -104,7 +105,7 @@ jffs_build_begin(struct jffs_control *c, int unit) | |||
104 | 105 | ||
105 | mtd = get_mtd_device(NULL, unit); | 106 | mtd = get_mtd_device(NULL, unit); |
106 | 107 | ||
107 | if (!mtd) { | 108 | if (IS_ERR(mtd)) { |
108 | kfree(fmc); | 109 | kfree(fmc); |
109 | DJM(no_jffs_fmcontrol--); | 110 | DJM(no_jffs_fmcontrol--); |
110 | return NULL; | 111 | return NULL; |
diff --git a/fs/jffs2/debug.c b/fs/jffs2/debug.c index 72b4fc13a106..4189e4a36050 100644 --- a/fs/jffs2/debug.c +++ b/fs/jffs2/debug.c | |||
@@ -178,8 +178,8 @@ __jffs2_dbg_acct_paranoia_check_nolock(struct jffs2_sb_info *c, | |||
178 | while (ref2) { | 178 | while (ref2) { |
179 | uint32_t totlen = ref_totlen(c, jeb, ref2); | 179 | uint32_t totlen = ref_totlen(c, jeb, ref2); |
180 | 180 | ||
181 | if (ref2->flash_offset < jeb->offset || | 181 | if (ref_offset(ref2) < jeb->offset || |
182 | ref2->flash_offset > jeb->offset + c->sector_size) { | 182 | ref_offset(ref2) > jeb->offset + c->sector_size) { |
183 | JFFS2_ERROR("node_ref %#08x shouldn't be in block at %#08x.\n", | 183 | JFFS2_ERROR("node_ref %#08x shouldn't be in block at %#08x.\n", |
184 | ref_offset(ref2), jeb->offset); | 184 | ref_offset(ref2), jeb->offset); |
185 | goto error; | 185 | goto error; |
diff --git a/fs/jffs2/debug.h b/fs/jffs2/debug.h index 3daf3bca0376..f89c85d5a3f8 100644 --- a/fs/jffs2/debug.h +++ b/fs/jffs2/debug.h | |||
@@ -13,6 +13,7 @@ | |||
13 | #ifndef _JFFS2_DEBUG_H_ | 13 | #ifndef _JFFS2_DEBUG_H_ |
14 | #define _JFFS2_DEBUG_H_ | 14 | #define _JFFS2_DEBUG_H_ |
15 | 15 | ||
16 | #include <linux/sched.h> | ||
16 | 17 | ||
17 | #ifndef CONFIG_JFFS2_FS_DEBUG | 18 | #ifndef CONFIG_JFFS2_FS_DEBUG |
18 | #define CONFIG_JFFS2_FS_DEBUG 0 | 19 | #define CONFIG_JFFS2_FS_DEBUG 0 |
diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index 7bc1a4201c0c..abb90c0c09cc 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c | |||
@@ -502,12 +502,11 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent) | |||
502 | if (ret) | 502 | if (ret) |
503 | return ret; | 503 | return ret; |
504 | 504 | ||
505 | c->inocache_list = kmalloc(INOCACHE_HASHSIZE * sizeof(struct jffs2_inode_cache *), GFP_KERNEL); | 505 | c->inocache_list = kcalloc(INOCACHE_HASHSIZE, sizeof(struct jffs2_inode_cache *), GFP_KERNEL); |
506 | if (!c->inocache_list) { | 506 | if (!c->inocache_list) { |
507 | ret = -ENOMEM; | 507 | ret = -ENOMEM; |
508 | goto out_wbuf; | 508 | goto out_wbuf; |
509 | } | 509 | } |
510 | memset(c->inocache_list, 0, INOCACHE_HASHSIZE * sizeof(struct jffs2_inode_cache *)); | ||
511 | 510 | ||
512 | jffs2_init_xattr_subsystem(c); | 511 | jffs2_init_xattr_subsystem(c); |
513 | 512 | ||
diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c index daff3341ff92..3a3cf225981f 100644 --- a/fs/jffs2/gc.c +++ b/fs/jffs2/gc.c | |||
@@ -838,6 +838,8 @@ static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct | |||
838 | 838 | ||
839 | for (raw = f->inocache->nodes; raw != (void *)f->inocache; raw = raw->next_in_ino) { | 839 | for (raw = f->inocache->nodes; raw != (void *)f->inocache; raw = raw->next_in_ino) { |
840 | 840 | ||
841 | cond_resched(); | ||
842 | |||
841 | /* We only care about obsolete ones */ | 843 | /* We only care about obsolete ones */ |
842 | if (!(ref_obsolete(raw))) | 844 | if (!(ref_obsolete(raw))) |
843 | continue; | 845 | continue; |
diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index 0ddfd70307fb..4178b4b55948 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h | |||
@@ -294,23 +294,21 @@ static inline int jffs2_encode_dev(union jffs2_device_node *jdev, dev_t rdev) | |||
294 | 294 | ||
295 | static inline struct jffs2_node_frag *frag_first(struct rb_root *root) | 295 | static inline struct jffs2_node_frag *frag_first(struct rb_root *root) |
296 | { | 296 | { |
297 | struct rb_node *node = root->rb_node; | 297 | struct rb_node *node = rb_first(root); |
298 | 298 | ||
299 | if (!node) | 299 | if (!node) |
300 | return NULL; | 300 | return NULL; |
301 | while(node->rb_left) | 301 | |
302 | node = node->rb_left; | ||
303 | return rb_entry(node, struct jffs2_node_frag, rb); | 302 | return rb_entry(node, struct jffs2_node_frag, rb); |
304 | } | 303 | } |
305 | 304 | ||
306 | static inline struct jffs2_node_frag *frag_last(struct rb_root *root) | 305 | static inline struct jffs2_node_frag *frag_last(struct rb_root *root) |
307 | { | 306 | { |
308 | struct rb_node *node = root->rb_node; | 307 | struct rb_node *node = rb_last(root); |
309 | 308 | ||
310 | if (!node) | 309 | if (!node) |
311 | return NULL; | 310 | return NULL; |
312 | while(node->rb_right) | 311 | |
313 | node = node->rb_right; | ||
314 | return rb_entry(node, struct jffs2_node_frag, rb); | 312 | return rb_entry(node, struct jffs2_node_frag, rb); |
315 | } | 313 | } |
316 | 314 | ||
diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c index 266423b2709d..58a0b912e9d0 100644 --- a/fs/jffs2/readinode.c +++ b/fs/jffs2/readinode.c | |||
@@ -944,13 +944,12 @@ int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | |||
944 | int jffs2_do_crccheck_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic) | 944 | int jffs2_do_crccheck_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic) |
945 | { | 945 | { |
946 | struct jffs2_raw_inode n; | 946 | struct jffs2_raw_inode n; |
947 | struct jffs2_inode_info *f = kmalloc(sizeof(*f), GFP_KERNEL); | 947 | struct jffs2_inode_info *f = kzalloc(sizeof(*f), GFP_KERNEL); |
948 | int ret; | 948 | int ret; |
949 | 949 | ||
950 | if (!f) | 950 | if (!f) |
951 | return -ENOMEM; | 951 | return -ENOMEM; |
952 | 952 | ||
953 | memset(f, 0, sizeof(*f)); | ||
954 | init_MUTEX_LOCKED(&f->sem); | 953 | init_MUTEX_LOCKED(&f->sem); |
955 | f->inocache = ic; | 954 | f->inocache = ic; |
956 | 955 | ||
diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index e2413466ddd5..3af746eaff0e 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c | |||
@@ -128,17 +128,19 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) | |||
128 | } | 128 | } |
129 | 129 | ||
130 | if (jffs2_sum_active()) { | 130 | if (jffs2_sum_active()) { |
131 | s = kmalloc(sizeof(struct jffs2_summary), GFP_KERNEL); | 131 | s = kzalloc(sizeof(struct jffs2_summary), GFP_KERNEL); |
132 | if (!s) { | 132 | if (!s) { |
133 | kfree(flashbuf); | ||
133 | JFFS2_WARNING("Can't allocate memory for summary\n"); | 134 | JFFS2_WARNING("Can't allocate memory for summary\n"); |
134 | return -ENOMEM; | 135 | return -ENOMEM; |
135 | } | 136 | } |
136 | memset(s, 0, sizeof(struct jffs2_summary)); | ||
137 | } | 137 | } |
138 | 138 | ||
139 | for (i=0; i<c->nr_blocks; i++) { | 139 | for (i=0; i<c->nr_blocks; i++) { |
140 | struct jffs2_eraseblock *jeb = &c->blocks[i]; | 140 | struct jffs2_eraseblock *jeb = &c->blocks[i]; |
141 | 141 | ||
142 | cond_resched(); | ||
143 | |||
142 | /* reset summary info for next eraseblock scan */ | 144 | /* reset summary info for next eraseblock scan */ |
143 | jffs2_sum_reset_collected(s); | 145 | jffs2_sum_reset_collected(s); |
144 | 146 | ||
diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index e52cef526d90..25265965bdc1 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c | |||
@@ -26,15 +26,13 @@ | |||
26 | 26 | ||
27 | int jffs2_sum_init(struct jffs2_sb_info *c) | 27 | int jffs2_sum_init(struct jffs2_sb_info *c) |
28 | { | 28 | { |
29 | c->summary = kmalloc(sizeof(struct jffs2_summary), GFP_KERNEL); | 29 | c->summary = kzalloc(sizeof(struct jffs2_summary), GFP_KERNEL); |
30 | 30 | ||
31 | if (!c->summary) { | 31 | if (!c->summary) { |
32 | JFFS2_WARNING("Can't allocate memory for summary information!\n"); | 32 | JFFS2_WARNING("Can't allocate memory for summary information!\n"); |
33 | return -ENOMEM; | 33 | return -ENOMEM; |
34 | } | 34 | } |
35 | 35 | ||
36 | memset(c->summary, 0, sizeof(struct jffs2_summary)); | ||
37 | |||
38 | c->summary->sum_buf = vmalloc(c->sector_size); | 36 | c->summary->sum_buf = vmalloc(c->sector_size); |
39 | 37 | ||
40 | if (!c->summary->sum_buf) { | 38 | if (!c->summary->sum_buf) { |
@@ -398,6 +396,8 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras | |||
398 | for (i=0; i<je32_to_cpu(summary->sum_num); i++) { | 396 | for (i=0; i<je32_to_cpu(summary->sum_num); i++) { |
399 | dbg_summary("processing summary index %d\n", i); | 397 | dbg_summary("processing summary index %d\n", i); |
400 | 398 | ||
399 | cond_resched(); | ||
400 | |||
401 | /* Make sure there's a spare ref for dirty space */ | 401 | /* Make sure there's a spare ref for dirty space */ |
402 | err = jffs2_prealloc_raw_node_refs(c, jeb, 2); | 402 | err = jffs2_prealloc_raw_node_refs(c, jeb, 2); |
403 | if (err) | 403 | if (err) |
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index 7deb78254021..08a0e6c49e61 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/init.h> | 17 | #include <linux/init.h> |
18 | #include <linux/list.h> | 18 | #include <linux/list.h> |
19 | #include <linux/fs.h> | 19 | #include <linux/fs.h> |
20 | #include <linux/err.h> | ||
20 | #include <linux/mount.h> | 21 | #include <linux/mount.h> |
21 | #include <linux/jffs2.h> | 22 | #include <linux/jffs2.h> |
22 | #include <linux/pagemap.h> | 23 | #include <linux/pagemap.h> |
@@ -184,9 +185,9 @@ static int jffs2_get_sb_mtdnr(struct file_system_type *fs_type, | |||
184 | struct mtd_info *mtd; | 185 | struct mtd_info *mtd; |
185 | 186 | ||
186 | mtd = get_mtd_device(NULL, mtdnr); | 187 | mtd = get_mtd_device(NULL, mtdnr); |
187 | if (!mtd) { | 188 | if (IS_ERR(mtd)) { |
188 | D1(printk(KERN_DEBUG "jffs2: MTD device #%u doesn't appear to exist\n", mtdnr)); | 189 | D1(printk(KERN_DEBUG "jffs2: MTD device #%u doesn't appear to exist\n", mtdnr)); |
189 | return -EINVAL; | 190 | return PTR_ERR(mtd); |
190 | } | 191 | } |
191 | 192 | ||
192 | return jffs2_get_sb_mtd(fs_type, flags, dev_name, data, mtd, mnt); | 193 | return jffs2_get_sb_mtd(fs_type, flags, dev_name, data, mtd, mnt); |
@@ -221,7 +222,7 @@ static int jffs2_get_sb(struct file_system_type *fs_type, | |||
221 | D1(printk(KERN_DEBUG "jffs2_get_sb(): mtd:%%s, name \"%s\"\n", dev_name+4)); | 222 | D1(printk(KERN_DEBUG "jffs2_get_sb(): mtd:%%s, name \"%s\"\n", dev_name+4)); |
222 | for (mtdnr = 0; mtdnr < MAX_MTD_DEVICES; mtdnr++) { | 223 | for (mtdnr = 0; mtdnr < MAX_MTD_DEVICES; mtdnr++) { |
223 | mtd = get_mtd_device(NULL, mtdnr); | 224 | mtd = get_mtd_device(NULL, mtdnr); |
224 | if (mtd) { | 225 | if (!IS_ERR(mtd)) { |
225 | if (!strcmp(mtd->name, dev_name+4)) | 226 | if (!strcmp(mtd->name, dev_name+4)) |
226 | return jffs2_get_sb_mtd(fs_type, flags, dev_name, data, mtd, mnt); | 227 | return jffs2_get_sb_mtd(fs_type, flags, dev_name, data, mtd, mnt); |
227 | put_mtd_device(mtd); | 228 | put_mtd_device(mtd); |
diff --git a/fs/jffs2/symlink.c b/fs/jffs2/symlink.c index fc211b6e9b03..b90d5aa3d969 100644 --- a/fs/jffs2/symlink.c +++ b/fs/jffs2/symlink.c | |||
@@ -51,7 +51,7 @@ static void *jffs2_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
51 | */ | 51 | */ |
52 | 52 | ||
53 | if (!p) { | 53 | if (!p) { |
54 | printk(KERN_ERR "jffs2_follow_link(): can't find symlink taerget\n"); | 54 | printk(KERN_ERR "jffs2_follow_link(): can't find symlink target\n"); |
55 | p = ERR_PTR(-EIO); | 55 | p = ERR_PTR(-EIO); |
56 | } | 56 | } |
57 | D1(printk(KERN_DEBUG "jffs2_follow_link(): target path is '%s'\n", (char *) f->target)); | 57 | D1(printk(KERN_DEBUG "jffs2_follow_link(): target path is '%s'\n", (char *) f->target)); |
diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index 70707309dfa1..9c99859f5edd 100644 --- a/fs/jffs2/wbuf.c +++ b/fs/jffs2/wbuf.c | |||
@@ -969,8 +969,7 @@ int jffs2_check_oob_empty(struct jffs2_sb_info *c, | |||
969 | int oobsize = c->mtd->oobsize; | 969 | int oobsize = c->mtd->oobsize; |
970 | struct mtd_oob_ops ops; | 970 | struct mtd_oob_ops ops; |
971 | 971 | ||
972 | ops.len = NR_OOB_SCAN_PAGES * oobsize; | 972 | ops.ooblen = NR_OOB_SCAN_PAGES * oobsize; |
973 | ops.ooblen = oobsize; | ||
974 | ops.oobbuf = c->oobbuf; | 973 | ops.oobbuf = c->oobbuf; |
975 | ops.ooboffs = 0; | 974 | ops.ooboffs = 0; |
976 | ops.datbuf = NULL; | 975 | ops.datbuf = NULL; |
@@ -983,10 +982,10 @@ int jffs2_check_oob_empty(struct jffs2_sb_info *c, | |||
983 | return ret; | 982 | return ret; |
984 | } | 983 | } |
985 | 984 | ||
986 | if (ops.retlen < ops.len) { | 985 | if (ops.oobretlen < ops.ooblen) { |
987 | D1(printk(KERN_WARNING "jffs2_check_oob_empty(): Read OOB " | 986 | D1(printk(KERN_WARNING "jffs2_check_oob_empty(): Read OOB " |
988 | "returned short read (%zd bytes not %d) for block " | 987 | "returned short read (%zd bytes not %d) for block " |
989 | "at %08x\n", ops.retlen, ops.len, jeb->offset)); | 988 | "at %08x\n", ops.oobretlen, ops.ooblen, jeb->offset)); |
990 | return -EIO; | 989 | return -EIO; |
991 | } | 990 | } |
992 | 991 | ||
@@ -1005,7 +1004,7 @@ int jffs2_check_oob_empty(struct jffs2_sb_info *c, | |||
1005 | } | 1004 | } |
1006 | 1005 | ||
1007 | /* we know, we are aligned :) */ | 1006 | /* we know, we are aligned :) */ |
1008 | for (page = oobsize; page < ops.len; page += sizeof(long)) { | 1007 | for (page = oobsize; page < ops.ooblen; page += sizeof(long)) { |
1009 | long dat = *(long *)(&ops.oobbuf[page]); | 1008 | long dat = *(long *)(&ops.oobbuf[page]); |
1010 | if(dat != -1) | 1009 | if(dat != -1) |
1011 | return 1; | 1010 | return 1; |
@@ -1033,7 +1032,6 @@ int jffs2_check_nand_cleanmarker (struct jffs2_sb_info *c, | |||
1033 | return 2; | 1032 | return 2; |
1034 | } | 1033 | } |
1035 | 1034 | ||
1036 | ops.len = oobsize; | ||
1037 | ops.ooblen = oobsize; | 1035 | ops.ooblen = oobsize; |
1038 | ops.oobbuf = c->oobbuf; | 1036 | ops.oobbuf = c->oobbuf; |
1039 | ops.ooboffs = 0; | 1037 | ops.ooboffs = 0; |
@@ -1048,10 +1046,10 @@ int jffs2_check_nand_cleanmarker (struct jffs2_sb_info *c, | |||
1048 | return ret; | 1046 | return ret; |
1049 | } | 1047 | } |
1050 | 1048 | ||
1051 | if (ops.retlen < ops.len) { | 1049 | if (ops.oobretlen < ops.ooblen) { |
1052 | D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): " | 1050 | D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): " |
1053 | "Read OOB return short read (%zd bytes not %d) " | 1051 | "Read OOB return short read (%zd bytes not %d) " |
1054 | "for block at %08x\n", ops.retlen, ops.len, | 1052 | "for block at %08x\n", ops.oobretlen, ops.ooblen, |
1055 | jeb->offset)); | 1053 | jeb->offset)); |
1056 | return -EIO; | 1054 | return -EIO; |
1057 | } | 1055 | } |
@@ -1090,8 +1088,7 @@ int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, | |||
1090 | n.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER); | 1088 | n.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER); |
1091 | n.totlen = cpu_to_je32(8); | 1089 | n.totlen = cpu_to_je32(8); |
1092 | 1090 | ||
1093 | ops.len = c->fsdata_len; | 1091 | ops.ooblen = c->fsdata_len; |
1094 | ops.ooblen = c->fsdata_len;; | ||
1095 | ops.oobbuf = (uint8_t *)&n; | 1092 | ops.oobbuf = (uint8_t *)&n; |
1096 | ops.ooboffs = c->fsdata_pos; | 1093 | ops.ooboffs = c->fsdata_pos; |
1097 | ops.datbuf = NULL; | 1094 | ops.datbuf = NULL; |
@@ -1105,10 +1102,10 @@ int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, | |||
1105 | jeb->offset, ret)); | 1102 | jeb->offset, ret)); |
1106 | return ret; | 1103 | return ret; |
1107 | } | 1104 | } |
1108 | if (ops.retlen != ops.len) { | 1105 | if (ops.oobretlen != ops.ooblen) { |
1109 | D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): " | 1106 | D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): " |
1110 | "Short write for block at %08x: %zd not %d\n", | 1107 | "Short write for block at %08x: %zd not %d\n", |
1111 | jeb->offset, ops.retlen, ops.len)); | 1108 | jeb->offset, ops.oobretlen, ops.ooblen)); |
1112 | return -EIO; | 1109 | return -EIO; |
1113 | } | 1110 | } |
1114 | return 0; | 1111 | return 0; |
diff --git a/fs/jffs2/xattr.c b/fs/jffs2/xattr.c index 4da09ce1d1f5..4bb3f1897330 100644 --- a/fs/jffs2/xattr.c +++ b/fs/jffs2/xattr.c | |||
@@ -399,8 +399,6 @@ static void unrefer_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datu | |||
399 | { | 399 | { |
400 | /* must be called under down_write(xattr_sem) */ | 400 | /* must be called under down_write(xattr_sem) */ |
401 | if (atomic_dec_and_lock(&xd->refcnt, &c->erase_completion_lock)) { | 401 | if (atomic_dec_and_lock(&xd->refcnt, &c->erase_completion_lock)) { |
402 | uint32_t xid = xd->xid, version = xd->version; | ||
403 | |||
404 | unload_xattr_datum(c, xd); | 402 | unload_xattr_datum(c, xd); |
405 | xd->flags |= JFFS2_XFLAGS_DEAD; | 403 | xd->flags |= JFFS2_XFLAGS_DEAD; |
406 | if (xd->node == (void *)xd) { | 404 | if (xd->node == (void *)xd) { |
@@ -411,7 +409,8 @@ static void unrefer_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datu | |||
411 | } | 409 | } |
412 | spin_unlock(&c->erase_completion_lock); | 410 | spin_unlock(&c->erase_completion_lock); |
413 | 411 | ||
414 | dbg_xattr("xdatum(xid=%u, version=%u) was removed.\n", xid, version); | 412 | dbg_xattr("xdatum(xid=%u, version=%u) was removed.\n", |
413 | xd->xid, xd->version); | ||
415 | } | 414 | } |
416 | } | 415 | } |
417 | 416 | ||
diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c index 062707745162..f4d45d4d835b 100644 --- a/fs/lockd/clntlock.c +++ b/fs/lockd/clntlock.c | |||
@@ -176,7 +176,7 @@ reclaimer(void *ptr) | |||
176 | lock_kernel(); | 176 | lock_kernel(); |
177 | lockd_up(0); /* note: this cannot fail as lockd is already running */ | 177 | lockd_up(0); /* note: this cannot fail as lockd is already running */ |
178 | 178 | ||
179 | dprintk("lockd: reclaiming locks for host %s", host->h_name); | 179 | dprintk("lockd: reclaiming locks for host %s\n", host->h_name); |
180 | 180 | ||
181 | restart: | 181 | restart: |
182 | nsmstate = host->h_nsmstate; | 182 | nsmstate = host->h_nsmstate; |
@@ -206,7 +206,7 @@ restart: | |||
206 | 206 | ||
207 | host->h_reclaiming = 0; | 207 | host->h_reclaiming = 0; |
208 | up_write(&host->h_rwsem); | 208 | up_write(&host->h_rwsem); |
209 | dprintk("NLM: done reclaiming locks for host %s", host->h_name); | 209 | dprintk("NLM: done reclaiming locks for host %s\n", host->h_name); |
210 | 210 | ||
211 | /* Now, wake up all processes that sleep on a blocked lock */ | 211 | /* Now, wake up all processes that sleep on a blocked lock */ |
212 | list_for_each_entry(block, &nlm_blocked, b_list) { | 212 | list_for_each_entry(block, &nlm_blocked, b_list) { |
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index dee3d6c0f194..d9ba8cb0ee75 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -532,7 +532,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
532 | 532 | ||
533 | lock_kernel(); | 533 | lock_kernel(); |
534 | 534 | ||
535 | res = nfs_revalidate_mapping(inode, filp->f_mapping); | 535 | res = nfs_revalidate_mapping_nolock(inode, filp->f_mapping); |
536 | if (res < 0) { | 536 | if (res < 0) { |
537 | unlock_kernel(); | 537 | unlock_kernel(); |
538 | return res; | 538 | return res; |
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index fab20d06d936..9e4a2b70995a 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
@@ -434,8 +434,9 @@ static int do_vfs_lock(struct file *file, struct file_lock *fl) | |||
434 | BUG(); | 434 | BUG(); |
435 | } | 435 | } |
436 | if (res < 0) | 436 | if (res < 0) |
437 | printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", | 437 | dprintk(KERN_WARNING "%s: VFS is out of sync with lock manager" |
438 | __FUNCTION__); | 438 | " - error %d!\n", |
439 | __FUNCTION__, res); | ||
439 | return res; | 440 | return res; |
440 | } | 441 | } |
441 | 442 | ||
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 63e470279309..d83498282837 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -665,49 +665,86 @@ int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) | |||
665 | return __nfs_revalidate_inode(server, inode); | 665 | return __nfs_revalidate_inode(server, inode); |
666 | } | 666 | } |
667 | 667 | ||
668 | static int nfs_invalidate_mapping_nolock(struct inode *inode, struct address_space *mapping) | ||
669 | { | ||
670 | struct nfs_inode *nfsi = NFS_I(inode); | ||
671 | |||
672 | if (mapping->nrpages != 0) { | ||
673 | int ret = invalidate_inode_pages2(mapping); | ||
674 | if (ret < 0) | ||
675 | return ret; | ||
676 | } | ||
677 | spin_lock(&inode->i_lock); | ||
678 | nfsi->cache_validity &= ~NFS_INO_INVALID_DATA; | ||
679 | if (S_ISDIR(inode->i_mode)) { | ||
680 | memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf)); | ||
681 | /* This ensures we revalidate child dentries */ | ||
682 | nfsi->cache_change_attribute = jiffies; | ||
683 | } | ||
684 | spin_unlock(&inode->i_lock); | ||
685 | nfs_inc_stats(inode, NFSIOS_DATAINVALIDATE); | ||
686 | dfprintk(PAGECACHE, "NFS: (%s/%Ld) data cache invalidated\n", | ||
687 | inode->i_sb->s_id, (long long)NFS_FILEID(inode)); | ||
688 | return 0; | ||
689 | } | ||
690 | |||
691 | static int nfs_invalidate_mapping(struct inode *inode, struct address_space *mapping) | ||
692 | { | ||
693 | int ret = 0; | ||
694 | |||
695 | mutex_lock(&inode->i_mutex); | ||
696 | if (NFS_I(inode)->cache_validity & NFS_INO_INVALID_DATA) { | ||
697 | ret = nfs_sync_mapping(mapping); | ||
698 | if (ret == 0) | ||
699 | ret = nfs_invalidate_mapping_nolock(inode, mapping); | ||
700 | } | ||
701 | mutex_unlock(&inode->i_mutex); | ||
702 | return ret; | ||
703 | } | ||
704 | |||
668 | /** | 705 | /** |
669 | * nfs_revalidate_mapping - Revalidate the pagecache | 706 | * nfs_revalidate_mapping_nolock - Revalidate the pagecache |
670 | * @inode - pointer to host inode | 707 | * @inode - pointer to host inode |
671 | * @mapping - pointer to mapping | 708 | * @mapping - pointer to mapping |
672 | */ | 709 | */ |
673 | int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping) | 710 | int nfs_revalidate_mapping_nolock(struct inode *inode, struct address_space *mapping) |
674 | { | 711 | { |
675 | struct nfs_inode *nfsi = NFS_I(inode); | 712 | struct nfs_inode *nfsi = NFS_I(inode); |
676 | int ret = 0; | 713 | int ret = 0; |
677 | 714 | ||
678 | if (NFS_STALE(inode)) | ||
679 | ret = -ESTALE; | ||
680 | if ((nfsi->cache_validity & NFS_INO_REVAL_PAGECACHE) | 715 | if ((nfsi->cache_validity & NFS_INO_REVAL_PAGECACHE) |
681 | || nfs_attribute_timeout(inode)) | 716 | || nfs_attribute_timeout(inode) || NFS_STALE(inode)) { |
682 | ret = __nfs_revalidate_inode(NFS_SERVER(inode), inode); | 717 | ret = __nfs_revalidate_inode(NFS_SERVER(inode), inode); |
683 | if (ret < 0) | 718 | if (ret < 0) |
684 | goto out; | 719 | goto out; |
720 | } | ||
721 | if (nfsi->cache_validity & NFS_INO_INVALID_DATA) | ||
722 | ret = nfs_invalidate_mapping_nolock(inode, mapping); | ||
723 | out: | ||
724 | return ret; | ||
725 | } | ||
685 | 726 | ||
686 | if (nfsi->cache_validity & NFS_INO_INVALID_DATA) { | 727 | /** |
687 | if (mapping->nrpages != 0) { | 728 | * nfs_revalidate_mapping - Revalidate the pagecache |
688 | if (S_ISREG(inode->i_mode)) { | 729 | * @inode - pointer to host inode |
689 | ret = nfs_sync_mapping(mapping); | 730 | * @mapping - pointer to mapping |
690 | if (ret < 0) | 731 | * |
691 | goto out; | 732 | * This version of the function will take the inode->i_mutex and attempt to |
692 | } | 733 | * flush out all dirty data if it needs to invalidate the page cache. |
693 | ret = invalidate_inode_pages2(mapping); | 734 | */ |
694 | if (ret < 0) | 735 | int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping) |
695 | goto out; | 736 | { |
696 | } | 737 | struct nfs_inode *nfsi = NFS_I(inode); |
697 | spin_lock(&inode->i_lock); | 738 | int ret = 0; |
698 | nfsi->cache_validity &= ~NFS_INO_INVALID_DATA; | ||
699 | if (S_ISDIR(inode->i_mode)) { | ||
700 | memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf)); | ||
701 | /* This ensures we revalidate child dentries */ | ||
702 | nfsi->cache_change_attribute = jiffies; | ||
703 | } | ||
704 | spin_unlock(&inode->i_lock); | ||
705 | 739 | ||
706 | nfs_inc_stats(inode, NFSIOS_DATAINVALIDATE); | 740 | if ((nfsi->cache_validity & NFS_INO_REVAL_PAGECACHE) |
707 | dfprintk(PAGECACHE, "NFS: (%s/%Ld) data cache invalidated\n", | 741 | || nfs_attribute_timeout(inode) || NFS_STALE(inode)) { |
708 | inode->i_sb->s_id, | 742 | ret = __nfs_revalidate_inode(NFS_SERVER(inode), inode); |
709 | (long long)NFS_FILEID(inode)); | 743 | if (ret < 0) |
744 | goto out; | ||
710 | } | 745 | } |
746 | if (nfsi->cache_validity & NFS_INO_INVALID_DATA) | ||
747 | ret = nfs_invalidate_mapping(inode, mapping); | ||
711 | out: | 748 | out: |
712 | return ret; | 749 | return ret; |
713 | } | 750 | } |
diff --git a/fs/nfs/symlink.c b/fs/nfs/symlink.c index 6c686112cc03..525c136c7d8c 100644 --- a/fs/nfs/symlink.c +++ b/fs/nfs/symlink.c | |||
@@ -50,7 +50,9 @@ static void *nfs_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
50 | { | 50 | { |
51 | struct inode *inode = dentry->d_inode; | 51 | struct inode *inode = dentry->d_inode; |
52 | struct page *page; | 52 | struct page *page; |
53 | void *err = ERR_PTR(nfs_revalidate_mapping(inode, inode->i_mapping)); | 53 | void *err; |
54 | |||
55 | err = ERR_PTR(nfs_revalidate_mapping_nolock(inode, inode->i_mapping)); | ||
54 | if (err) | 56 | if (err) |
55 | goto read_failed; | 57 | goto read_failed; |
56 | page = read_cache_page(&inode->i_data, 0, | 58 | page = read_cache_page(&inode->i_data, 0, |
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 248dd92e6a56..49c310b84923 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c | |||
@@ -35,7 +35,6 @@ | |||
35 | #include <linux/lockd/bind.h> | 35 | #include <linux/lockd/bind.h> |
36 | 36 | ||
37 | #define NFSDDBG_FACILITY NFSDDBG_EXPORT | 37 | #define NFSDDBG_FACILITY NFSDDBG_EXPORT |
38 | #define NFSD_PARANOIA 1 | ||
39 | 38 | ||
40 | typedef struct auth_domain svc_client; | 39 | typedef struct auth_domain svc_client; |
41 | typedef struct svc_export svc_export; | 40 | typedef struct svc_export svc_export; |
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index 277df40f098d..e695660921ec 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c | |||
@@ -990,15 +990,16 @@ encode_entry(struct readdir_cd *ccd, const char *name, | |||
990 | } | 990 | } |
991 | 991 | ||
992 | int | 992 | int |
993 | nfs3svc_encode_entry(struct readdir_cd *cd, const char *name, | 993 | nfs3svc_encode_entry(void *cd, const char *name, |
994 | int namlen, loff_t offset, ino_t ino, unsigned int d_type) | 994 | int namlen, loff_t offset, u64 ino, unsigned int d_type) |
995 | { | 995 | { |
996 | return encode_entry(cd, name, namlen, offset, ino, d_type, 0); | 996 | return encode_entry(cd, name, namlen, offset, ino, d_type, 0); |
997 | } | 997 | } |
998 | 998 | ||
999 | int | 999 | int |
1000 | nfs3svc_encode_entry_plus(struct readdir_cd *cd, const char *name, | 1000 | nfs3svc_encode_entry_plus(void *cd, const char *name, |
1001 | int namlen, loff_t offset, ino_t ino, unsigned int d_type) | 1001 | int namlen, loff_t offset, u64 ino, |
1002 | unsigned int d_type) | ||
1002 | { | 1003 | { |
1003 | return encode_entry(cd, name, namlen, offset, ino, d_type, 1); | 1004 | return encode_entry(cd, name, namlen, offset, ino, d_type, 1); |
1004 | } | 1005 | } |
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index fea46368afb2..18aa9440df14 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
@@ -1880,9 +1880,10 @@ nfsd4_encode_rdattr_error(__be32 *p, int buflen, __be32 nfserr) | |||
1880 | } | 1880 | } |
1881 | 1881 | ||
1882 | static int | 1882 | static int |
1883 | nfsd4_encode_dirent(struct readdir_cd *ccd, const char *name, int namlen, | 1883 | nfsd4_encode_dirent(void *ccdv, const char *name, int namlen, |
1884 | loff_t offset, ino_t ino, unsigned int d_type) | 1884 | loff_t offset, u64 ino, unsigned int d_type) |
1885 | { | 1885 | { |
1886 | struct readdir_cd *ccd = ccdv; | ||
1886 | struct nfsd4_readdir *cd = container_of(ccd, struct nfsd4_readdir, common); | 1887 | struct nfsd4_readdir *cd = container_of(ccd, struct nfsd4_readdir, common); |
1887 | int buflen; | 1888 | int buflen; |
1888 | __be32 *p = cd->buffer; | 1889 | __be32 *p = cd->buffer; |
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index b06bf9f70efc..98338a569dc0 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c | |||
@@ -24,8 +24,6 @@ | |||
24 | #include <linux/nfsd/nfsd.h> | 24 | #include <linux/nfsd/nfsd.h> |
25 | 25 | ||
26 | #define NFSDDBG_FACILITY NFSDDBG_FH | 26 | #define NFSDDBG_FACILITY NFSDDBG_FH |
27 | #define NFSD_PARANOIA 1 | ||
28 | /* #define NFSD_DEBUG_VERBOSE 1 */ | ||
29 | 27 | ||
30 | 28 | ||
31 | static int nfsd_nr_verified; | 29 | static int nfsd_nr_verified; |
@@ -230,13 +228,12 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) | |||
230 | error = nfserrno(PTR_ERR(dentry)); | 228 | error = nfserrno(PTR_ERR(dentry)); |
231 | goto out; | 229 | goto out; |
232 | } | 230 | } |
233 | #ifdef NFSD_PARANOIA | 231 | |
234 | if (S_ISDIR(dentry->d_inode->i_mode) && | 232 | if (S_ISDIR(dentry->d_inode->i_mode) && |
235 | (dentry->d_flags & DCACHE_DISCONNECTED)) { | 233 | (dentry->d_flags & DCACHE_DISCONNECTED)) { |
236 | printk("nfsd: find_fh_dentry returned a DISCONNECTED directory: %s/%s\n", | 234 | printk("nfsd: find_fh_dentry returned a DISCONNECTED directory: %s/%s\n", |
237 | dentry->d_parent->d_name.name, dentry->d_name.name); | 235 | dentry->d_parent->d_name.name, dentry->d_name.name); |
238 | } | 236 | } |
239 | #endif | ||
240 | 237 | ||
241 | fhp->fh_dentry = dentry; | 238 | fhp->fh_dentry = dentry; |
242 | fhp->fh_export = exp; | 239 | fhp->fh_export = exp; |
@@ -267,12 +264,13 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) | |||
267 | /* Finally, check access permissions. */ | 264 | /* Finally, check access permissions. */ |
268 | error = nfsd_permission(exp, dentry, access); | 265 | error = nfsd_permission(exp, dentry, access); |
269 | 266 | ||
270 | #ifdef NFSD_PARANOIA_EXTREME | ||
271 | if (error) { | 267 | if (error) { |
272 | printk("fh_verify: %s/%s permission failure, acc=%x, error=%d\n", | 268 | dprintk("fh_verify: %s/%s permission failure, " |
273 | dentry->d_parent->d_name.name, dentry->d_name.name, access, (error >> 24)); | 269 | "acc=%x, error=%d\n", |
270 | dentry->d_parent->d_name.name, | ||
271 | dentry->d_name.name, | ||
272 | access, (error >> 24)); | ||
274 | } | 273 | } |
275 | #endif | ||
276 | out: | 274 | out: |
277 | if (exp && !IS_ERR(exp)) | 275 | if (exp && !IS_ERR(exp)) |
278 | exp_put(exp); | 276 | exp_put(exp); |
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 0aaccb03bf76..fbf5d51947ea 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c | |||
@@ -72,7 +72,7 @@ static struct svc_program nfsd_acl_program = { | |||
72 | .pg_prog = NFS_ACL_PROGRAM, | 72 | .pg_prog = NFS_ACL_PROGRAM, |
73 | .pg_nvers = NFSD_ACL_NRVERS, | 73 | .pg_nvers = NFSD_ACL_NRVERS, |
74 | .pg_vers = nfsd_acl_versions, | 74 | .pg_vers = nfsd_acl_versions, |
75 | .pg_name = "nfsd", | 75 | .pg_name = "nfsacl", |
76 | .pg_class = "nfsd", | 76 | .pg_class = "nfsd", |
77 | .pg_stats = &nfsd_acl_svcstats, | 77 | .pg_stats = &nfsd_acl_svcstats, |
78 | .pg_authenticate = &svc_set_client, | 78 | .pg_authenticate = &svc_set_client, |
@@ -118,16 +118,16 @@ int nfsd_vers(int vers, enum vers_op change) | |||
118 | switch(change) { | 118 | switch(change) { |
119 | case NFSD_SET: | 119 | case NFSD_SET: |
120 | nfsd_versions[vers] = nfsd_version[vers]; | 120 | nfsd_versions[vers] = nfsd_version[vers]; |
121 | break; | ||
122 | #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) | 121 | #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) |
123 | if (vers < NFSD_ACL_NRVERS) | 122 | if (vers < NFSD_ACL_NRVERS) |
124 | nfsd_acl_version[vers] = nfsd_acl_version[vers]; | 123 | nfsd_acl_versions[vers] = nfsd_acl_version[vers]; |
125 | #endif | 124 | #endif |
125 | break; | ||
126 | case NFSD_CLEAR: | 126 | case NFSD_CLEAR: |
127 | nfsd_versions[vers] = NULL; | 127 | nfsd_versions[vers] = NULL; |
128 | #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) | 128 | #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) |
129 | if (vers < NFSD_ACL_NRVERS) | 129 | if (vers < NFSD_ACL_NRVERS) |
130 | nfsd_acl_version[vers] = NULL; | 130 | nfsd_acl_versions[vers] = NULL; |
131 | #endif | 131 | #endif |
132 | break; | 132 | break; |
133 | case NFSD_TEST: | 133 | case NFSD_TEST: |
diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c index f5243f943996..6555c50d9006 100644 --- a/fs/nfsd/nfsxdr.c +++ b/fs/nfsd/nfsxdr.c | |||
@@ -462,9 +462,10 @@ nfssvc_encode_statfsres(struct svc_rqst *rqstp, __be32 *p, | |||
462 | } | 462 | } |
463 | 463 | ||
464 | int | 464 | int |
465 | nfssvc_encode_entry(struct readdir_cd *ccd, const char *name, | 465 | nfssvc_encode_entry(void *ccdv, const char *name, |
466 | int namlen, loff_t offset, ino_t ino, unsigned int d_type) | 466 | int namlen, loff_t offset, u64 ino, unsigned int d_type) |
467 | { | 467 | { |
468 | struct readdir_cd *ccd = ccdv; | ||
468 | struct nfsd_readdirres *cd = container_of(ccd, struct nfsd_readdirres, common); | 469 | struct nfsd_readdirres *cd = container_of(ccd, struct nfsd_readdirres, common); |
469 | __be32 *p = cd->buffer; | 470 | __be32 *p = cd->buffer; |
470 | int buflen, slen; | 471 | int buflen, slen; |
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 7a79c23aa6d4..8283236c6a0f 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
@@ -59,7 +59,6 @@ | |||
59 | #include <asm/uaccess.h> | 59 | #include <asm/uaccess.h> |
60 | 60 | ||
61 | #define NFSDDBG_FACILITY NFSDDBG_FILEOP | 61 | #define NFSDDBG_FACILITY NFSDDBG_FILEOP |
62 | #define NFSD_PARANOIA | ||
63 | 62 | ||
64 | 63 | ||
65 | /* We must ignore files (but only files) which might have mandatory | 64 | /* We must ignore files (but only files) which might have mandatory |
@@ -822,7 +821,8 @@ nfsd_read_actor(read_descriptor_t *desc, struct page *page, unsigned long offset | |||
822 | rqstp->rq_res.page_len = size; | 821 | rqstp->rq_res.page_len = size; |
823 | } else if (page != pp[-1]) { | 822 | } else if (page != pp[-1]) { |
824 | get_page(page); | 823 | get_page(page); |
825 | put_page(*pp); | 824 | if (*pp) |
825 | put_page(*pp); | ||
826 | *pp = page; | 826 | *pp = page; |
827 | rqstp->rq_resused++; | 827 | rqstp->rq_resused++; |
828 | rqstp->rq_res.page_len += size; | 828 | rqstp->rq_res.page_len += size; |
@@ -1244,7 +1244,6 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1244 | __be32 err; | 1244 | __be32 err; |
1245 | int host_err; | 1245 | int host_err; |
1246 | __u32 v_mtime=0, v_atime=0; | 1246 | __u32 v_mtime=0, v_atime=0; |
1247 | int v_mode=0; | ||
1248 | 1247 | ||
1249 | err = nfserr_perm; | 1248 | err = nfserr_perm; |
1250 | if (!flen) | 1249 | if (!flen) |
@@ -1281,16 +1280,11 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1281 | goto out; | 1280 | goto out; |
1282 | 1281 | ||
1283 | if (createmode == NFS3_CREATE_EXCLUSIVE) { | 1282 | if (createmode == NFS3_CREATE_EXCLUSIVE) { |
1284 | /* while the verifier would fit in mtime+atime, | 1283 | /* solaris7 gets confused (bugid 4218508) if these have |
1285 | * solaris7 gets confused (bugid 4218508) if these have | 1284 | * the high bit set, so just clear the high bits. |
1286 | * the high bit set, so we use the mode as well | ||
1287 | */ | 1285 | */ |
1288 | v_mtime = verifier[0]&0x7fffffff; | 1286 | v_mtime = verifier[0]&0x7fffffff; |
1289 | v_atime = verifier[1]&0x7fffffff; | 1287 | v_atime = verifier[1]&0x7fffffff; |
1290 | v_mode = S_IFREG | ||
1291 | | ((verifier[0]&0x80000000) >> (32-7)) /* u+x */ | ||
1292 | | ((verifier[1]&0x80000000) >> (32-9)) /* u+r */ | ||
1293 | ; | ||
1294 | } | 1288 | } |
1295 | 1289 | ||
1296 | if (dchild->d_inode) { | 1290 | if (dchild->d_inode) { |
@@ -1318,7 +1312,6 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1318 | case NFS3_CREATE_EXCLUSIVE: | 1312 | case NFS3_CREATE_EXCLUSIVE: |
1319 | if ( dchild->d_inode->i_mtime.tv_sec == v_mtime | 1313 | if ( dchild->d_inode->i_mtime.tv_sec == v_mtime |
1320 | && dchild->d_inode->i_atime.tv_sec == v_atime | 1314 | && dchild->d_inode->i_atime.tv_sec == v_atime |
1321 | && dchild->d_inode->i_mode == v_mode | ||
1322 | && dchild->d_inode->i_size == 0 ) | 1315 | && dchild->d_inode->i_size == 0 ) |
1323 | break; | 1316 | break; |
1324 | /* fallthru */ | 1317 | /* fallthru */ |
@@ -1340,26 +1333,22 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1340 | } | 1333 | } |
1341 | 1334 | ||
1342 | if (createmode == NFS3_CREATE_EXCLUSIVE) { | 1335 | if (createmode == NFS3_CREATE_EXCLUSIVE) { |
1343 | /* Cram the verifier into atime/mtime/mode */ | 1336 | /* Cram the verifier into atime/mtime */ |
1344 | iap->ia_valid = ATTR_MTIME|ATTR_ATIME | 1337 | iap->ia_valid = ATTR_MTIME|ATTR_ATIME |
1345 | | ATTR_MTIME_SET|ATTR_ATIME_SET | 1338 | | ATTR_MTIME_SET|ATTR_ATIME_SET; |
1346 | | ATTR_MODE; | ||
1347 | /* XXX someone who knows this better please fix it for nsec */ | 1339 | /* XXX someone who knows this better please fix it for nsec */ |
1348 | iap->ia_mtime.tv_sec = v_mtime; | 1340 | iap->ia_mtime.tv_sec = v_mtime; |
1349 | iap->ia_atime.tv_sec = v_atime; | 1341 | iap->ia_atime.tv_sec = v_atime; |
1350 | iap->ia_mtime.tv_nsec = 0; | 1342 | iap->ia_mtime.tv_nsec = 0; |
1351 | iap->ia_atime.tv_nsec = 0; | 1343 | iap->ia_atime.tv_nsec = 0; |
1352 | iap->ia_mode = v_mode; | ||
1353 | } | 1344 | } |
1354 | 1345 | ||
1355 | /* Set file attributes. | 1346 | /* Set file attributes. |
1356 | * Mode has already been set but we might need to reset it | ||
1357 | * for CREATE_EXCLUSIVE | ||
1358 | * Irix appears to send along the gid when it tries to | 1347 | * Irix appears to send along the gid when it tries to |
1359 | * implement setgid directories via NFS. Clear out all that cruft. | 1348 | * implement setgid directories via NFS. Clear out all that cruft. |
1360 | */ | 1349 | */ |
1361 | set_attr: | 1350 | set_attr: |
1362 | if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID)) != 0) { | 1351 | if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID|ATTR_MODE)) != 0) { |
1363 | __be32 err2 = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0); | 1352 | __be32 err2 = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0); |
1364 | if (err2) | 1353 | if (err2) |
1365 | err = err2; | 1354 | err = err2; |
@@ -1726,7 +1715,7 @@ out: | |||
1726 | */ | 1715 | */ |
1727 | __be32 | 1716 | __be32 |
1728 | nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t *offsetp, | 1717 | nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t *offsetp, |
1729 | struct readdir_cd *cdp, encode_dent_fn func) | 1718 | struct readdir_cd *cdp, filldir_t func) |
1730 | { | 1719 | { |
1731 | __be32 err; | 1720 | __be32 err; |
1732 | int host_err; | 1721 | int host_err; |
@@ -1751,7 +1740,7 @@ nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t *offsetp, | |||
1751 | 1740 | ||
1752 | do { | 1741 | do { |
1753 | cdp->err = nfserr_eof; /* will be cleared on successful read */ | 1742 | cdp->err = nfserr_eof; /* will be cleared on successful read */ |
1754 | host_err = vfs_readdir(file, (filldir_t) func, cdp); | 1743 | host_err = vfs_readdir(file, func, cdp); |
1755 | } while (host_err >=0 && cdp->err == nfs_ok); | 1744 | } while (host_err >=0 && cdp->err == nfs_ok); |
1756 | if (host_err) | 1745 | if (host_err) |
1757 | err = nfserrno(host_err); | 1746 | err = nfserrno(host_err); |
diff --git a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog index 35cc4b1d60f7..af4ef808fa94 100644 --- a/fs/ntfs/ChangeLog +++ b/fs/ntfs/ChangeLog | |||
@@ -17,6 +17,13 @@ ToDo/Notes: | |||
17 | happen is unclear however so it is worth waiting until someone hits | 17 | happen is unclear however so it is worth waiting until someone hits |
18 | the problem. | 18 | the problem. |
19 | 19 | ||
20 | 2.1.28 - Fix a deadlock. | ||
21 | |||
22 | - Fix deadlock in fs/ntfs/inode.c::ntfs_put_inode(). Thanks to Sergey | ||
23 | Vlasov for the report and detailed analysis of the deadlock. The fix | ||
24 | involved getting rid of ntfs_put_inode() altogether and hence NTFS no | ||
25 | longer has a ->put_inode super operation. | ||
26 | |||
20 | 2.1.27 - Various bug fixes and cleanups. | 27 | 2.1.27 - Various bug fixes and cleanups. |
21 | 28 | ||
22 | - Fix two compiler warnings on Alpha. Thanks to Andrew Morton for | 29 | - Fix two compiler warnings on Alpha. Thanks to Andrew Morton for |
diff --git a/fs/ntfs/Makefile b/fs/ntfs/Makefile index e27b4eacffbf..825508385565 100644 --- a/fs/ntfs/Makefile +++ b/fs/ntfs/Makefile | |||
@@ -6,7 +6,7 @@ ntfs-objs := aops.o attrib.o collate.o compress.o debug.o dir.o file.o \ | |||
6 | index.o inode.o mft.o mst.o namei.o runlist.o super.o sysctl.o \ | 6 | index.o inode.o mft.o mst.o namei.o runlist.o super.o sysctl.o \ |
7 | unistr.o upcase.o | 7 | unistr.o upcase.o |
8 | 8 | ||
9 | EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.27\" | 9 | EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.28\" |
10 | 10 | ||
11 | ifeq ($(CONFIG_NTFS_DEBUG),y) | 11 | ifeq ($(CONFIG_NTFS_DEBUG),y) |
12 | EXTRA_CFLAGS += -DDEBUG | 12 | EXTRA_CFLAGS += -DDEBUG |
diff --git a/fs/ntfs/aops.c b/fs/ntfs/aops.c index 7b2c8f4f6a6f..629e7abdd840 100644 --- a/fs/ntfs/aops.c +++ b/fs/ntfs/aops.c | |||
@@ -92,10 +92,12 @@ static void ntfs_end_buffer_async_read(struct buffer_head *bh, int uptodate) | |||
92 | ofs = 0; | 92 | ofs = 0; |
93 | if (file_ofs < init_size) | 93 | if (file_ofs < init_size) |
94 | ofs = init_size - file_ofs; | 94 | ofs = init_size - file_ofs; |
95 | local_irq_save(flags); | ||
95 | kaddr = kmap_atomic(page, KM_BIO_SRC_IRQ); | 96 | kaddr = kmap_atomic(page, KM_BIO_SRC_IRQ); |
96 | memset(kaddr + bh_offset(bh) + ofs, 0, | 97 | memset(kaddr + bh_offset(bh) + ofs, 0, |
97 | bh->b_size - ofs); | 98 | bh->b_size - ofs); |
98 | kunmap_atomic(kaddr, KM_BIO_SRC_IRQ); | 99 | kunmap_atomic(kaddr, KM_BIO_SRC_IRQ); |
100 | local_irq_restore(flags); | ||
99 | flush_dcache_page(page); | 101 | flush_dcache_page(page); |
100 | } | 102 | } |
101 | } else { | 103 | } else { |
@@ -143,11 +145,13 @@ static void ntfs_end_buffer_async_read(struct buffer_head *bh, int uptodate) | |||
143 | recs = PAGE_CACHE_SIZE / rec_size; | 145 | recs = PAGE_CACHE_SIZE / rec_size; |
144 | /* Should have been verified before we got here... */ | 146 | /* Should have been verified before we got here... */ |
145 | BUG_ON(!recs); | 147 | BUG_ON(!recs); |
148 | local_irq_save(flags); | ||
146 | kaddr = kmap_atomic(page, KM_BIO_SRC_IRQ); | 149 | kaddr = kmap_atomic(page, KM_BIO_SRC_IRQ); |
147 | for (i = 0; i < recs; i++) | 150 | for (i = 0; i < recs; i++) |
148 | post_read_mst_fixup((NTFS_RECORD*)(kaddr + | 151 | post_read_mst_fixup((NTFS_RECORD*)(kaddr + |
149 | i * rec_size), rec_size); | 152 | i * rec_size), rec_size); |
150 | kunmap_atomic(kaddr, KM_BIO_SRC_IRQ); | 153 | kunmap_atomic(kaddr, KM_BIO_SRC_IRQ); |
154 | local_irq_restore(flags); | ||
151 | flush_dcache_page(page); | 155 | flush_dcache_page(page); |
152 | if (likely(page_uptodate && !PageError(page))) | 156 | if (likely(page_uptodate && !PageError(page))) |
153 | SetPageUptodate(page); | 157 | SetPageUptodate(page); |
diff --git a/fs/ntfs/dir.c b/fs/ntfs/dir.c index 8296c29ae3b8..74f99a6a369b 100644 --- a/fs/ntfs/dir.c +++ b/fs/ntfs/dir.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /** | 1 | /** |
2 | * dir.c - NTFS kernel directory operations. Part of the Linux-NTFS project. | 2 | * dir.c - NTFS kernel directory operations. Part of the Linux-NTFS project. |
3 | * | 3 | * |
4 | * Copyright (c) 2001-2005 Anton Altaparmakov | 4 | * Copyright (c) 2001-2007 Anton Altaparmakov |
5 | * Copyright (c) 2002 Richard Russon | 5 | * Copyright (c) 2002 Richard Russon |
6 | * | 6 | * |
7 | * This program/include file is free software; you can redistribute it and/or | 7 | * This program/include file is free software; you can redistribute it and/or |
@@ -1249,16 +1249,12 @@ skip_index_root: | |||
1249 | /* Get the offset into the index allocation attribute. */ | 1249 | /* Get the offset into the index allocation attribute. */ |
1250 | ia_pos = (s64)fpos - vol->mft_record_size; | 1250 | ia_pos = (s64)fpos - vol->mft_record_size; |
1251 | ia_mapping = vdir->i_mapping; | 1251 | ia_mapping = vdir->i_mapping; |
1252 | bmp_vi = ndir->itype.index.bmp_ino; | 1252 | ntfs_debug("Inode 0x%lx, getting index bitmap.", vdir->i_ino); |
1253 | if (unlikely(!bmp_vi)) { | 1253 | bmp_vi = ntfs_attr_iget(vdir, AT_BITMAP, I30, 4); |
1254 | ntfs_debug("Inode 0x%lx, regetting index bitmap.", vdir->i_ino); | 1254 | if (IS_ERR(bmp_vi)) { |
1255 | bmp_vi = ntfs_attr_iget(vdir, AT_BITMAP, I30, 4); | 1255 | ntfs_error(sb, "Failed to get bitmap attribute."); |
1256 | if (IS_ERR(bmp_vi)) { | 1256 | err = PTR_ERR(bmp_vi); |
1257 | ntfs_error(sb, "Failed to get bitmap attribute."); | 1257 | goto err_out; |
1258 | err = PTR_ERR(bmp_vi); | ||
1259 | goto err_out; | ||
1260 | } | ||
1261 | ndir->itype.index.bmp_ino = bmp_vi; | ||
1262 | } | 1258 | } |
1263 | bmp_mapping = bmp_vi->i_mapping; | 1259 | bmp_mapping = bmp_vi->i_mapping; |
1264 | /* Get the starting bitmap bit position and sanity check it. */ | 1260 | /* Get the starting bitmap bit position and sanity check it. */ |
@@ -1266,7 +1262,7 @@ skip_index_root: | |||
1266 | if (unlikely(bmp_pos >> 3 >= i_size_read(bmp_vi))) { | 1262 | if (unlikely(bmp_pos >> 3 >= i_size_read(bmp_vi))) { |
1267 | ntfs_error(sb, "Current index allocation position exceeds " | 1263 | ntfs_error(sb, "Current index allocation position exceeds " |
1268 | "index bitmap size."); | 1264 | "index bitmap size."); |
1269 | goto err_out; | 1265 | goto iput_err_out; |
1270 | } | 1266 | } |
1271 | /* Get the starting bit position in the current bitmap page. */ | 1267 | /* Get the starting bit position in the current bitmap page. */ |
1272 | cur_bmp_pos = bmp_pos & ((PAGE_CACHE_SIZE * 8) - 1); | 1268 | cur_bmp_pos = bmp_pos & ((PAGE_CACHE_SIZE * 8) - 1); |
@@ -1282,7 +1278,7 @@ get_next_bmp_page: | |||
1282 | ntfs_error(sb, "Reading index bitmap failed."); | 1278 | ntfs_error(sb, "Reading index bitmap failed."); |
1283 | err = PTR_ERR(bmp_page); | 1279 | err = PTR_ERR(bmp_page); |
1284 | bmp_page = NULL; | 1280 | bmp_page = NULL; |
1285 | goto err_out; | 1281 | goto iput_err_out; |
1286 | } | 1282 | } |
1287 | bmp = (u8*)page_address(bmp_page); | 1283 | bmp = (u8*)page_address(bmp_page); |
1288 | /* Find next index block in use. */ | 1284 | /* Find next index block in use. */ |
@@ -1429,6 +1425,7 @@ find_next_index_buffer: | |||
1429 | /* @ia_page is already unlocked in this case. */ | 1425 | /* @ia_page is already unlocked in this case. */ |
1430 | ntfs_unmap_page(ia_page); | 1426 | ntfs_unmap_page(ia_page); |
1431 | ntfs_unmap_page(bmp_page); | 1427 | ntfs_unmap_page(bmp_page); |
1428 | iput(bmp_vi); | ||
1432 | goto abort; | 1429 | goto abort; |
1433 | } | 1430 | } |
1434 | } | 1431 | } |
@@ -1439,6 +1436,7 @@ unm_EOD: | |||
1439 | ntfs_unmap_page(ia_page); | 1436 | ntfs_unmap_page(ia_page); |
1440 | } | 1437 | } |
1441 | ntfs_unmap_page(bmp_page); | 1438 | ntfs_unmap_page(bmp_page); |
1439 | iput(bmp_vi); | ||
1442 | EOD: | 1440 | EOD: |
1443 | /* We are finished, set fpos to EOD. */ | 1441 | /* We are finished, set fpos to EOD. */ |
1444 | fpos = i_size + vol->mft_record_size; | 1442 | fpos = i_size + vol->mft_record_size; |
@@ -1455,8 +1453,11 @@ done: | |||
1455 | filp->f_pos = fpos; | 1453 | filp->f_pos = fpos; |
1456 | return 0; | 1454 | return 0; |
1457 | err_out: | 1455 | err_out: |
1458 | if (bmp_page) | 1456 | if (bmp_page) { |
1459 | ntfs_unmap_page(bmp_page); | 1457 | ntfs_unmap_page(bmp_page); |
1458 | iput_err_out: | ||
1459 | iput(bmp_vi); | ||
1460 | } | ||
1460 | if (ia_page) { | 1461 | if (ia_page) { |
1461 | unlock_page(ia_page); | 1462 | unlock_page(ia_page); |
1462 | ntfs_unmap_page(ia_page); | 1463 | ntfs_unmap_page(ia_page); |
@@ -1529,14 +1530,22 @@ static int ntfs_dir_open(struct inode *vi, struct file *filp) | |||
1529 | static int ntfs_dir_fsync(struct file *filp, struct dentry *dentry, | 1530 | static int ntfs_dir_fsync(struct file *filp, struct dentry *dentry, |
1530 | int datasync) | 1531 | int datasync) |
1531 | { | 1532 | { |
1532 | struct inode *vi = dentry->d_inode; | 1533 | struct inode *bmp_vi, *vi = dentry->d_inode; |
1533 | ntfs_inode *ni = NTFS_I(vi); | ||
1534 | int err, ret; | 1534 | int err, ret; |
1535 | ntfs_attr na; | ||
1535 | 1536 | ||
1536 | ntfs_debug("Entering for inode 0x%lx.", vi->i_ino); | 1537 | ntfs_debug("Entering for inode 0x%lx.", vi->i_ino); |
1537 | BUG_ON(!S_ISDIR(vi->i_mode)); | 1538 | BUG_ON(!S_ISDIR(vi->i_mode)); |
1538 | if (NInoIndexAllocPresent(ni) && ni->itype.index.bmp_ino) | 1539 | /* If the bitmap attribute inode is in memory sync it, too. */ |
1539 | write_inode_now(ni->itype.index.bmp_ino, !datasync); | 1540 | na.mft_no = vi->i_ino; |
1541 | na.type = AT_BITMAP; | ||
1542 | na.name = I30; | ||
1543 | na.name_len = 4; | ||
1544 | bmp_vi = ilookup5(vi->i_sb, vi->i_ino, (test_t)ntfs_test_inode, &na); | ||
1545 | if (bmp_vi) { | ||
1546 | write_inode_now(bmp_vi, !datasync); | ||
1547 | iput(bmp_vi); | ||
1548 | } | ||
1540 | ret = ntfs_write_inode(vi, 1); | 1549 | ret = ntfs_write_inode(vi, 1); |
1541 | write_inode_now(vi, !datasync); | 1550 | write_inode_now(vi, !datasync); |
1542 | err = sync_blockdev(vi->i_sb->s_bdev); | 1551 | err = sync_blockdev(vi->i_sb->s_bdev); |
diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c index 247989891b4b..f8bf8da67ee8 100644 --- a/fs/ntfs/inode.c +++ b/fs/ntfs/inode.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /** | 1 | /** |
2 | * inode.c - NTFS kernel inode handling. Part of the Linux-NTFS project. | 2 | * inode.c - NTFS kernel inode handling. Part of the Linux-NTFS project. |
3 | * | 3 | * |
4 | * Copyright (c) 2001-2006 Anton Altaparmakov | 4 | * Copyright (c) 2001-2007 Anton Altaparmakov |
5 | * | 5 | * |
6 | * This program/include file is free software; you can redistribute it and/or | 6 | * This program/include file is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU General Public License as published | 7 | * modify it under the terms of the GNU General Public License as published |
@@ -95,7 +95,7 @@ int ntfs_test_inode(struct inode *vi, ntfs_attr *na) | |||
95 | * If initializing the normal file/directory inode, set @na->type to AT_UNUSED. | 95 | * If initializing the normal file/directory inode, set @na->type to AT_UNUSED. |
96 | * In that case, @na->name and @na->name_len should be set to NULL and 0, | 96 | * In that case, @na->name and @na->name_len should be set to NULL and 0, |
97 | * respectively. Although that is not strictly necessary as | 97 | * respectively. Although that is not strictly necessary as |
98 | * ntfs_read_inode_locked() will fill them in later. | 98 | * ntfs_read_locked_inode() will fill them in later. |
99 | * | 99 | * |
100 | * Return 0 on success and -errno on error. | 100 | * Return 0 on success and -errno on error. |
101 | * | 101 | * |
@@ -171,8 +171,8 @@ static int ntfs_read_locked_index_inode(struct inode *base_vi, | |||
171 | struct inode *ntfs_iget(struct super_block *sb, unsigned long mft_no) | 171 | struct inode *ntfs_iget(struct super_block *sb, unsigned long mft_no) |
172 | { | 172 | { |
173 | struct inode *vi; | 173 | struct inode *vi; |
174 | ntfs_attr na; | ||
175 | int err; | 174 | int err; |
175 | ntfs_attr na; | ||
176 | 176 | ||
177 | na.mft_no = mft_no; | 177 | na.mft_no = mft_no; |
178 | na.type = AT_UNUSED; | 178 | na.type = AT_UNUSED; |
@@ -229,8 +229,8 @@ struct inode *ntfs_attr_iget(struct inode *base_vi, ATTR_TYPE type, | |||
229 | ntfschar *name, u32 name_len) | 229 | ntfschar *name, u32 name_len) |
230 | { | 230 | { |
231 | struct inode *vi; | 231 | struct inode *vi; |
232 | ntfs_attr na; | ||
233 | int err; | 232 | int err; |
233 | ntfs_attr na; | ||
234 | 234 | ||
235 | /* Make sure no one calls ntfs_attr_iget() for indices. */ | 235 | /* Make sure no one calls ntfs_attr_iget() for indices. */ |
236 | BUG_ON(type == AT_INDEX_ALLOCATION); | 236 | BUG_ON(type == AT_INDEX_ALLOCATION); |
@@ -287,8 +287,8 @@ struct inode *ntfs_index_iget(struct inode *base_vi, ntfschar *name, | |||
287 | u32 name_len) | 287 | u32 name_len) |
288 | { | 288 | { |
289 | struct inode *vi; | 289 | struct inode *vi; |
290 | ntfs_attr na; | ||
291 | int err; | 290 | int err; |
291 | ntfs_attr na; | ||
292 | 292 | ||
293 | na.mft_no = base_vi->i_ino; | 293 | na.mft_no = base_vi->i_ino; |
294 | na.type = AT_INDEX_ALLOCATION; | 294 | na.type = AT_INDEX_ALLOCATION; |
@@ -402,7 +402,6 @@ void __ntfs_init_inode(struct super_block *sb, ntfs_inode *ni) | |||
402 | ntfs_init_runlist(&ni->attr_list_rl); | 402 | ntfs_init_runlist(&ni->attr_list_rl); |
403 | lockdep_set_class(&ni->attr_list_rl.lock, | 403 | lockdep_set_class(&ni->attr_list_rl.lock, |
404 | &attr_list_rl_lock_class); | 404 | &attr_list_rl_lock_class); |
405 | ni->itype.index.bmp_ino = NULL; | ||
406 | ni->itype.index.block_size = 0; | 405 | ni->itype.index.block_size = 0; |
407 | ni->itype.index.vcn_size = 0; | 406 | ni->itype.index.vcn_size = 0; |
408 | ni->itype.index.collation_rule = 0; | 407 | ni->itype.index.collation_rule = 0; |
@@ -546,6 +545,7 @@ static int ntfs_read_locked_inode(struct inode *vi) | |||
546 | { | 545 | { |
547 | ntfs_volume *vol = NTFS_SB(vi->i_sb); | 546 | ntfs_volume *vol = NTFS_SB(vi->i_sb); |
548 | ntfs_inode *ni; | 547 | ntfs_inode *ni; |
548 | struct inode *bvi; | ||
549 | MFT_RECORD *m; | 549 | MFT_RECORD *m; |
550 | ATTR_RECORD *a; | 550 | ATTR_RECORD *a; |
551 | STANDARD_INFORMATION *si; | 551 | STANDARD_INFORMATION *si; |
@@ -780,7 +780,6 @@ skip_attr_list_load: | |||
780 | */ | 780 | */ |
781 | if (S_ISDIR(vi->i_mode)) { | 781 | if (S_ISDIR(vi->i_mode)) { |
782 | loff_t bvi_size; | 782 | loff_t bvi_size; |
783 | struct inode *bvi; | ||
784 | ntfs_inode *bni; | 783 | ntfs_inode *bni; |
785 | INDEX_ROOT *ir; | 784 | INDEX_ROOT *ir; |
786 | u8 *ir_end, *index_end; | 785 | u8 *ir_end, *index_end; |
@@ -985,13 +984,12 @@ skip_attr_list_load: | |||
985 | err = PTR_ERR(bvi); | 984 | err = PTR_ERR(bvi); |
986 | goto unm_err_out; | 985 | goto unm_err_out; |
987 | } | 986 | } |
988 | ni->itype.index.bmp_ino = bvi; | ||
989 | bni = NTFS_I(bvi); | 987 | bni = NTFS_I(bvi); |
990 | if (NInoCompressed(bni) || NInoEncrypted(bni) || | 988 | if (NInoCompressed(bni) || NInoEncrypted(bni) || |
991 | NInoSparse(bni)) { | 989 | NInoSparse(bni)) { |
992 | ntfs_error(vi->i_sb, "$BITMAP attribute is compressed " | 990 | ntfs_error(vi->i_sb, "$BITMAP attribute is compressed " |
993 | "and/or encrypted and/or sparse."); | 991 | "and/or encrypted and/or sparse."); |
994 | goto unm_err_out; | 992 | goto iput_unm_err_out; |
995 | } | 993 | } |
996 | /* Consistency check bitmap size vs. index allocation size. */ | 994 | /* Consistency check bitmap size vs. index allocation size. */ |
997 | bvi_size = i_size_read(bvi); | 995 | bvi_size = i_size_read(bvi); |
@@ -1000,8 +998,10 @@ skip_attr_list_load: | |||
1000 | ntfs_error(vi->i_sb, "Index bitmap too small (0x%llx) " | 998 | ntfs_error(vi->i_sb, "Index bitmap too small (0x%llx) " |
1001 | "for index allocation (0x%llx).", | 999 | "for index allocation (0x%llx).", |
1002 | bvi_size << 3, vi->i_size); | 1000 | bvi_size << 3, vi->i_size); |
1003 | goto unm_err_out; | 1001 | goto iput_unm_err_out; |
1004 | } | 1002 | } |
1003 | /* No longer need the bitmap attribute inode. */ | ||
1004 | iput(bvi); | ||
1005 | skip_large_dir_stuff: | 1005 | skip_large_dir_stuff: |
1006 | /* Setup the operations for this inode. */ | 1006 | /* Setup the operations for this inode. */ |
1007 | vi->i_op = &ntfs_dir_inode_ops; | 1007 | vi->i_op = &ntfs_dir_inode_ops; |
@@ -1176,7 +1176,8 @@ no_data_attr_special_case: | |||
1176 | vi->i_blocks = ni->allocated_size >> 9; | 1176 | vi->i_blocks = ni->allocated_size >> 9; |
1177 | ntfs_debug("Done."); | 1177 | ntfs_debug("Done."); |
1178 | return 0; | 1178 | return 0; |
1179 | 1179 | iput_unm_err_out: | |
1180 | iput(bvi); | ||
1180 | unm_err_out: | 1181 | unm_err_out: |
1181 | if (!err) | 1182 | if (!err) |
1182 | err = -EIO; | 1183 | err = -EIO; |
@@ -1697,7 +1698,7 @@ static int ntfs_read_locked_index_inode(struct inode *base_vi, struct inode *vi) | |||
1697 | vi->i_size); | 1698 | vi->i_size); |
1698 | goto iput_unm_err_out; | 1699 | goto iput_unm_err_out; |
1699 | } | 1700 | } |
1700 | ni->itype.index.bmp_ino = bvi; | 1701 | iput(bvi); |
1701 | skip_large_index_stuff: | 1702 | skip_large_index_stuff: |
1702 | /* Setup the operations for this index inode. */ | 1703 | /* Setup the operations for this index inode. */ |
1703 | vi->i_op = NULL; | 1704 | vi->i_op = NULL; |
@@ -1714,7 +1715,6 @@ skip_large_index_stuff: | |||
1714 | 1715 | ||
1715 | ntfs_debug("Done."); | 1716 | ntfs_debug("Done."); |
1716 | return 0; | 1717 | return 0; |
1717 | |||
1718 | iput_unm_err_out: | 1718 | iput_unm_err_out: |
1719 | iput(bvi); | 1719 | iput(bvi); |
1720 | unm_err_out: | 1720 | unm_err_out: |
@@ -2191,37 +2191,6 @@ err_out: | |||
2191 | return -1; | 2191 | return -1; |
2192 | } | 2192 | } |
2193 | 2193 | ||
2194 | /** | ||
2195 | * ntfs_put_inode - handler for when the inode reference count is decremented | ||
2196 | * @vi: vfs inode | ||
2197 | * | ||
2198 | * The VFS calls ntfs_put_inode() every time the inode reference count (i_count) | ||
2199 | * is about to be decremented (but before the decrement itself. | ||
2200 | * | ||
2201 | * If the inode @vi is a directory with two references, one of which is being | ||
2202 | * dropped, we need to put the attribute inode for the directory index bitmap, | ||
2203 | * if it is present, otherwise the directory inode would remain pinned for | ||
2204 | * ever. | ||
2205 | */ | ||
2206 | void ntfs_put_inode(struct inode *vi) | ||
2207 | { | ||
2208 | if (S_ISDIR(vi->i_mode) && atomic_read(&vi->i_count) == 2) { | ||
2209 | ntfs_inode *ni = NTFS_I(vi); | ||
2210 | if (NInoIndexAllocPresent(ni)) { | ||
2211 | struct inode *bvi = NULL; | ||
2212 | mutex_lock(&vi->i_mutex); | ||
2213 | if (atomic_read(&vi->i_count) == 2) { | ||
2214 | bvi = ni->itype.index.bmp_ino; | ||
2215 | if (bvi) | ||
2216 | ni->itype.index.bmp_ino = NULL; | ||
2217 | } | ||
2218 | mutex_unlock(&vi->i_mutex); | ||
2219 | if (bvi) | ||
2220 | iput(bvi); | ||
2221 | } | ||
2222 | } | ||
2223 | } | ||
2224 | |||
2225 | static void __ntfs_clear_inode(ntfs_inode *ni) | 2194 | static void __ntfs_clear_inode(ntfs_inode *ni) |
2226 | { | 2195 | { |
2227 | /* Free all alocated memory. */ | 2196 | /* Free all alocated memory. */ |
@@ -2287,18 +2256,6 @@ void ntfs_clear_big_inode(struct inode *vi) | |||
2287 | { | 2256 | { |
2288 | ntfs_inode *ni = NTFS_I(vi); | 2257 | ntfs_inode *ni = NTFS_I(vi); |
2289 | 2258 | ||
2290 | /* | ||
2291 | * If the inode @vi is an index inode we need to put the attribute | ||
2292 | * inode for the index bitmap, if it is present, otherwise the index | ||
2293 | * inode would disappear and the attribute inode for the index bitmap | ||
2294 | * would no longer be referenced from anywhere and thus it would remain | ||
2295 | * pinned for ever. | ||
2296 | */ | ||
2297 | if (NInoAttr(ni) && (ni->type == AT_INDEX_ALLOCATION) && | ||
2298 | NInoIndexAllocPresent(ni) && ni->itype.index.bmp_ino) { | ||
2299 | iput(ni->itype.index.bmp_ino); | ||
2300 | ni->itype.index.bmp_ino = NULL; | ||
2301 | } | ||
2302 | #ifdef NTFS_RW | 2259 | #ifdef NTFS_RW |
2303 | if (NInoDirty(ni)) { | 2260 | if (NInoDirty(ni)) { |
2304 | bool was_bad = (is_bad_inode(vi)); | 2261 | bool was_bad = (is_bad_inode(vi)); |
diff --git a/fs/ntfs/inode.h b/fs/ntfs/inode.h index f088291e017c..117eaf8032a3 100644 --- a/fs/ntfs/inode.h +++ b/fs/ntfs/inode.h | |||
@@ -2,7 +2,7 @@ | |||
2 | * inode.h - Defines for inode structures NTFS Linux kernel driver. Part of | 2 | * inode.h - Defines for inode structures NTFS Linux kernel driver. Part of |
3 | * the Linux-NTFS project. | 3 | * the Linux-NTFS project. |
4 | * | 4 | * |
5 | * Copyright (c) 2001-2005 Anton Altaparmakov | 5 | * Copyright (c) 2001-2007 Anton Altaparmakov |
6 | * Copyright (c) 2002 Richard Russon | 6 | * Copyright (c) 2002 Richard Russon |
7 | * | 7 | * |
8 | * This program/include file is free software; you can redistribute it and/or | 8 | * This program/include file is free software; you can redistribute it and/or |
@@ -101,8 +101,6 @@ struct _ntfs_inode { | |||
101 | runlist attr_list_rl; /* Run list for the attribute list value. */ | 101 | runlist attr_list_rl; /* Run list for the attribute list value. */ |
102 | union { | 102 | union { |
103 | struct { /* It is a directory, $MFT, or an index inode. */ | 103 | struct { /* It is a directory, $MFT, or an index inode. */ |
104 | struct inode *bmp_ino; /* Attribute inode for the | ||
105 | index $BITMAP. */ | ||
106 | u32 block_size; /* Size of an index block. */ | 104 | u32 block_size; /* Size of an index block. */ |
107 | u32 vcn_size; /* Size of a vcn in this | 105 | u32 vcn_size; /* Size of a vcn in this |
108 | index. */ | 106 | index. */ |
@@ -300,8 +298,6 @@ extern void ntfs_clear_extent_inode(ntfs_inode *ni); | |||
300 | 298 | ||
301 | extern int ntfs_read_inode_mount(struct inode *vi); | 299 | extern int ntfs_read_inode_mount(struct inode *vi); |
302 | 300 | ||
303 | extern void ntfs_put_inode(struct inode *vi); | ||
304 | |||
305 | extern int ntfs_show_options(struct seq_file *sf, struct vfsmount *mnt); | 301 | extern int ntfs_show_options(struct seq_file *sf, struct vfsmount *mnt); |
306 | 302 | ||
307 | #ifdef NTFS_RW | 303 | #ifdef NTFS_RW |
diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c index 03a391ac7145..babf94d90def 100644 --- a/fs/ntfs/super.c +++ b/fs/ntfs/super.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * super.c - NTFS kernel super block handling. Part of the Linux-NTFS project. | 2 | * super.c - NTFS kernel super block handling. Part of the Linux-NTFS project. |
3 | * | 3 | * |
4 | * Copyright (c) 2001-2006 Anton Altaparmakov | 4 | * Copyright (c) 2001-2007 Anton Altaparmakov |
5 | * Copyright (c) 2001,2002 Richard Russon | 5 | * Copyright (c) 2001,2002 Richard Russon |
6 | * | 6 | * |
7 | * This program/include file is free software; you can redistribute it and/or | 7 | * This program/include file is free software; you can redistribute it and/or |
@@ -2702,9 +2702,6 @@ static int ntfs_statfs(struct dentry *dentry, struct kstatfs *sfs) | |||
2702 | static struct super_operations ntfs_sops = { | 2702 | static struct super_operations ntfs_sops = { |
2703 | .alloc_inode = ntfs_alloc_big_inode, /* VFS: Allocate new inode. */ | 2703 | .alloc_inode = ntfs_alloc_big_inode, /* VFS: Allocate new inode. */ |
2704 | .destroy_inode = ntfs_destroy_big_inode, /* VFS: Deallocate inode. */ | 2704 | .destroy_inode = ntfs_destroy_big_inode, /* VFS: Deallocate inode. */ |
2705 | .put_inode = ntfs_put_inode, /* VFS: Called just before | ||
2706 | the inode reference count | ||
2707 | is decreased. */ | ||
2708 | #ifdef NTFS_RW | 2705 | #ifdef NTFS_RW |
2709 | //.dirty_inode = NULL, /* VFS: Called from | 2706 | //.dirty_inode = NULL, /* VFS: Called from |
2710 | // __mark_inode_dirty(). */ | 2707 | // __mark_inode_dirty(). */ |
@@ -3261,7 +3258,7 @@ static void __exit exit_ntfs_fs(void) | |||
3261 | } | 3258 | } |
3262 | 3259 | ||
3263 | MODULE_AUTHOR("Anton Altaparmakov <aia21@cantab.net>"); | 3260 | MODULE_AUTHOR("Anton Altaparmakov <aia21@cantab.net>"); |
3264 | MODULE_DESCRIPTION("NTFS 1.2/3.x driver - Copyright (c) 2001-2006 Anton Altaparmakov"); | 3261 | MODULE_DESCRIPTION("NTFS 1.2/3.x driver - Copyright (c) 2001-2007 Anton Altaparmakov"); |
3265 | MODULE_VERSION(NTFS_VERSION); | 3262 | MODULE_VERSION(NTFS_VERSION); |
3266 | MODULE_LICENSE("GPL"); | 3263 | MODULE_LICENSE("GPL"); |
3267 | #ifdef DEBUG | 3264 | #ifdef DEBUG |
diff --git a/fs/ocfs2/export.c b/fs/ocfs2/export.c index 06be6e774cf9..56e1fefc1205 100644 --- a/fs/ocfs2/export.c +++ b/fs/ocfs2/export.c | |||
@@ -60,14 +60,11 @@ static struct dentry *ocfs2_get_dentry(struct super_block *sb, void *vobjp) | |||
60 | 60 | ||
61 | inode = ocfs2_iget(OCFS2_SB(sb), handle->ih_blkno, 0); | 61 | inode = ocfs2_iget(OCFS2_SB(sb), handle->ih_blkno, 0); |
62 | 62 | ||
63 | if (IS_ERR(inode)) { | 63 | if (IS_ERR(inode)) |
64 | mlog_errno(PTR_ERR(inode)); | ||
65 | return (void *)inode; | 64 | return (void *)inode; |
66 | } | ||
67 | 65 | ||
68 | if (handle->ih_generation != inode->i_generation) { | 66 | if (handle->ih_generation != inode->i_generation) { |
69 | iput(inode); | 67 | iput(inode); |
70 | mlog_errno(-ESTALE); | ||
71 | return ERR_PTR(-ESTALE); | 68 | return ERR_PTR(-ESTALE); |
72 | } | 69 | } |
73 | 70 | ||
diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c index e4d91493d7d7..28ab56f2b98c 100644 --- a/fs/ocfs2/inode.c +++ b/fs/ocfs2/inode.c | |||
@@ -146,7 +146,6 @@ struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 blkno, int flags) | |||
146 | if (is_bad_inode(inode)) { | 146 | if (is_bad_inode(inode)) { |
147 | iput(inode); | 147 | iput(inode); |
148 | inode = ERR_PTR(-ESTALE); | 148 | inode = ERR_PTR(-ESTALE); |
149 | mlog_errno(PTR_ERR(inode)); | ||
150 | goto bail; | 149 | goto bail; |
151 | } | 150 | } |
152 | 151 | ||
@@ -155,8 +154,7 @@ bail: | |||
155 | mlog(0, "returning inode with number %llu\n", | 154 | mlog(0, "returning inode with number %llu\n", |
156 | (unsigned long long)OCFS2_I(inode)->ip_blkno); | 155 | (unsigned long long)OCFS2_I(inode)->ip_blkno); |
157 | mlog_exit_ptr(inode); | 156 | mlog_exit_ptr(inode); |
158 | } else | 157 | } |
159 | mlog_errno(PTR_ERR(inode)); | ||
160 | 158 | ||
161 | return inode; | 159 | return inode; |
162 | } | 160 | } |
@@ -247,7 +245,7 @@ int ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe, | |||
247 | * today. change if needed. */ | 245 | * today. change if needed. */ |
248 | if (!OCFS2_IS_VALID_DINODE(fe) || | 246 | if (!OCFS2_IS_VALID_DINODE(fe) || |
249 | !(fe->i_flags & cpu_to_le32(OCFS2_VALID_FL))) { | 247 | !(fe->i_flags & cpu_to_le32(OCFS2_VALID_FL))) { |
250 | mlog(ML_ERROR, "Invalid dinode: i_ino=%lu, i_blkno=%llu, " | 248 | mlog(0, "Invalid dinode: i_ino=%lu, i_blkno=%llu, " |
251 | "signature = %.*s, flags = 0x%x\n", | 249 | "signature = %.*s, flags = 0x%x\n", |
252 | inode->i_ino, | 250 | inode->i_ino, |
253 | (unsigned long long)le64_to_cpu(fe->i_blkno), 7, | 251 | (unsigned long long)le64_to_cpu(fe->i_blkno), 7, |
@@ -478,11 +476,8 @@ static int ocfs2_read_locked_inode(struct inode *inode, | |||
478 | S_ISBLK(le16_to_cpu(fe->i_mode))) | 476 | S_ISBLK(le16_to_cpu(fe->i_mode))) |
479 | inode->i_rdev = huge_decode_dev(le64_to_cpu(fe->id1.dev1.i_rdev)); | 477 | inode->i_rdev = huge_decode_dev(le64_to_cpu(fe->id1.dev1.i_rdev)); |
480 | 478 | ||
481 | if (ocfs2_populate_inode(inode, fe, 0) < 0) { | 479 | if (ocfs2_populate_inode(inode, fe, 0) < 0) |
482 | mlog(ML_ERROR, "populate failed! i_blkno=%llu, i_ino=%lu\n", | ||
483 | (unsigned long long)fe->i_blkno, inode->i_ino); | ||
484 | goto bail; | 480 | goto bail; |
485 | } | ||
486 | 481 | ||
487 | BUG_ON(args->fi_blkno != le64_to_cpu(fe->i_blkno)); | 482 | BUG_ON(args->fi_blkno != le64_to_cpu(fe->i_blkno)); |
488 | 483 | ||
diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index 9637039c2633..f3d7803b4b46 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c | |||
@@ -932,14 +932,15 @@ static int ocfs2_unlink(struct inode *dir, | |||
932 | goto leave; | 932 | goto leave; |
933 | } | 933 | } |
934 | 934 | ||
935 | if (S_ISDIR(inode->i_mode)) { | 935 | dir->i_ctime = dir->i_mtime = CURRENT_TIME; |
936 | if (S_ISDIR(inode->i_mode)) | ||
936 | drop_nlink(dir); | 937 | drop_nlink(dir); |
937 | status = ocfs2_mark_inode_dirty(handle, dir, | 938 | |
938 | parent_node_bh); | 939 | status = ocfs2_mark_inode_dirty(handle, dir, parent_node_bh); |
939 | if (status < 0) { | 940 | if (status < 0) { |
940 | mlog_errno(status); | 941 | mlog_errno(status); |
942 | if (S_ISDIR(inode->i_mode)) | ||
941 | inc_nlink(dir); | 943 | inc_nlink(dir); |
942 | } | ||
943 | } | 944 | } |
944 | 945 | ||
945 | leave: | 946 | leave: |
@@ -1068,6 +1069,7 @@ static int ocfs2_rename(struct inode *old_dir, | |||
1068 | char orphan_name[OCFS2_ORPHAN_NAMELEN + 1]; | 1069 | char orphan_name[OCFS2_ORPHAN_NAMELEN + 1]; |
1069 | struct buffer_head *orphan_entry_bh = NULL; | 1070 | struct buffer_head *orphan_entry_bh = NULL; |
1070 | struct buffer_head *newfe_bh = NULL; | 1071 | struct buffer_head *newfe_bh = NULL; |
1072 | struct buffer_head *old_inode_bh = NULL; | ||
1071 | struct buffer_head *insert_entry_bh = NULL; | 1073 | struct buffer_head *insert_entry_bh = NULL; |
1072 | struct ocfs2_super *osb = NULL; | 1074 | struct ocfs2_super *osb = NULL; |
1073 | u64 newfe_blkno; | 1075 | u64 newfe_blkno; |
@@ -1079,7 +1081,7 @@ static int ocfs2_rename(struct inode *old_dir, | |||
1079 | struct buffer_head *new_de_bh = NULL, *old_de_bh = NULL; // bhs for above | 1081 | struct buffer_head *new_de_bh = NULL, *old_de_bh = NULL; // bhs for above |
1080 | struct buffer_head *old_inode_de_bh = NULL; // if old_dentry is a dir, | 1082 | struct buffer_head *old_inode_de_bh = NULL; // if old_dentry is a dir, |
1081 | // this is the 1st dirent bh | 1083 | // this is the 1st dirent bh |
1082 | nlink_t old_dir_nlink = old_dir->i_nlink, new_dir_nlink = new_dir->i_nlink; | 1084 | nlink_t old_dir_nlink = old_dir->i_nlink; |
1083 | 1085 | ||
1084 | /* At some point it might be nice to break this function up a | 1086 | /* At some point it might be nice to break this function up a |
1085 | * bit. */ | 1087 | * bit. */ |
@@ -1139,12 +1141,11 @@ static int ocfs2_rename(struct inode *old_dir, | |||
1139 | } | 1141 | } |
1140 | 1142 | ||
1141 | /* | 1143 | /* |
1142 | * Though we don't require an inode meta data update if | 1144 | * Aside from allowing a meta data update, the locking here |
1143 | * old_inode is not a directory, we lock anyway here to ensure | 1145 | * also ensures that the vote thread on other nodes won't have |
1144 | * the vote thread on other nodes won't have to concurrently | 1146 | * to concurrently downconvert the inode and the dentry locks. |
1145 | * downconvert the inode and the dentry locks. | ||
1146 | */ | 1147 | */ |
1147 | status = ocfs2_meta_lock(old_inode, NULL, 1); | 1148 | status = ocfs2_meta_lock(old_inode, &old_inode_bh, 1); |
1148 | if (status < 0) { | 1149 | if (status < 0) { |
1149 | if (status != -ENOENT) | 1150 | if (status != -ENOENT) |
1150 | mlog_errno(status); | 1151 | mlog_errno(status); |
@@ -1355,6 +1356,7 @@ static int ocfs2_rename(struct inode *old_dir, | |||
1355 | 1356 | ||
1356 | old_inode->i_ctime = CURRENT_TIME; | 1357 | old_inode->i_ctime = CURRENT_TIME; |
1357 | mark_inode_dirty(old_inode); | 1358 | mark_inode_dirty(old_inode); |
1359 | ocfs2_mark_inode_dirty(handle, old_inode, old_inode_bh); | ||
1358 | 1360 | ||
1359 | /* now that the name has been added to new_dir, remove the old name */ | 1361 | /* now that the name has been added to new_dir, remove the old name */ |
1360 | status = ocfs2_delete_entry(handle, old_dir, old_de, old_de_bh); | 1362 | status = ocfs2_delete_entry(handle, old_dir, old_de, old_de_bh); |
@@ -1384,27 +1386,22 @@ static int ocfs2_rename(struct inode *old_dir, | |||
1384 | } | 1386 | } |
1385 | } | 1387 | } |
1386 | mark_inode_dirty(old_dir); | 1388 | mark_inode_dirty(old_dir); |
1387 | if (new_inode) | 1389 | ocfs2_mark_inode_dirty(handle, old_dir, old_dir_bh); |
1390 | if (new_inode) { | ||
1388 | mark_inode_dirty(new_inode); | 1391 | mark_inode_dirty(new_inode); |
1392 | ocfs2_mark_inode_dirty(handle, new_inode, newfe_bh); | ||
1393 | } | ||
1389 | 1394 | ||
1390 | if (old_dir != new_dir) | 1395 | if (old_dir != new_dir) { |
1391 | if (new_dir_nlink != new_dir->i_nlink) { | 1396 | /* Keep the same times on both directories.*/ |
1392 | if (!new_dir_bh) { | 1397 | new_dir->i_ctime = new_dir->i_mtime = old_dir->i_ctime; |
1393 | mlog(ML_ERROR, "need to change nlink for new " | 1398 | |
1394 | "dir %llu from %d to %d but bh is NULL\n", | 1399 | /* |
1395 | (unsigned long long)OCFS2_I(new_dir)->ip_blkno, | 1400 | * This will also pick up the i_nlink change from the |
1396 | (int)new_dir_nlink, new_dir->i_nlink); | 1401 | * block above. |
1397 | } else { | 1402 | */ |
1398 | struct ocfs2_dinode *fe; | 1403 | ocfs2_mark_inode_dirty(handle, new_dir, new_dir_bh); |
1399 | status = ocfs2_journal_access(handle, | 1404 | } |
1400 | new_dir, | ||
1401 | new_dir_bh, | ||
1402 | OCFS2_JOURNAL_ACCESS_WRITE); | ||
1403 | fe = (struct ocfs2_dinode *) new_dir_bh->b_data; | ||
1404 | fe->i_links_count = cpu_to_le16(new_dir->i_nlink); | ||
1405 | status = ocfs2_journal_dirty(handle, new_dir_bh); | ||
1406 | } | ||
1407 | } | ||
1408 | 1405 | ||
1409 | if (old_dir_nlink != old_dir->i_nlink) { | 1406 | if (old_dir_nlink != old_dir->i_nlink) { |
1410 | if (!old_dir_bh) { | 1407 | if (!old_dir_bh) { |
@@ -1455,6 +1452,8 @@ bail: | |||
1455 | iput(new_inode); | 1452 | iput(new_inode); |
1456 | if (newfe_bh) | 1453 | if (newfe_bh) |
1457 | brelse(newfe_bh); | 1454 | brelse(newfe_bh); |
1455 | if (old_inode_bh) | ||
1456 | brelse(old_inode_bh); | ||
1458 | if (old_dir_bh) | 1457 | if (old_dir_bh) |
1459 | brelse(old_dir_bh); | 1458 | brelse(old_dir_bh); |
1460 | if (new_dir_bh) | 1459 | if (new_dir_bh) |
@@ -1826,6 +1825,13 @@ static int __ocfs2_add_entry(handle_t *handle, | |||
1826 | (le16_to_cpu(de->rec_len) >= rec_len)) || | 1825 | (le16_to_cpu(de->rec_len) >= rec_len)) || |
1827 | (le16_to_cpu(de->rec_len) >= | 1826 | (le16_to_cpu(de->rec_len) >= |
1828 | (OCFS2_DIR_REC_LEN(de->name_len) + rec_len))) { | 1827 | (OCFS2_DIR_REC_LEN(de->name_len) + rec_len))) { |
1828 | dir->i_mtime = dir->i_ctime = CURRENT_TIME; | ||
1829 | retval = ocfs2_mark_inode_dirty(handle, dir, parent_fe_bh); | ||
1830 | if (retval < 0) { | ||
1831 | mlog_errno(retval); | ||
1832 | goto bail; | ||
1833 | } | ||
1834 | |||
1829 | status = ocfs2_journal_access(handle, dir, insert_bh, | 1835 | status = ocfs2_journal_access(handle, dir, insert_bh, |
1830 | OCFS2_JOURNAL_ACCESS_WRITE); | 1836 | OCFS2_JOURNAL_ACCESS_WRITE); |
1831 | /* By now the buffer is marked for journaling */ | 1837 | /* By now the buffer is marked for journaling */ |
@@ -1848,7 +1854,6 @@ static int __ocfs2_add_entry(handle_t *handle, | |||
1848 | de->name_len = namelen; | 1854 | de->name_len = namelen; |
1849 | memcpy(de->name, name, namelen); | 1855 | memcpy(de->name, name, namelen); |
1850 | 1856 | ||
1851 | dir->i_mtime = dir->i_ctime = CURRENT_TIME; | ||
1852 | dir->i_version++; | 1857 | dir->i_version++; |
1853 | status = ocfs2_journal_dirty(handle, insert_bh); | 1858 | status = ocfs2_journal_dirty(handle, insert_bh); |
1854 | retval = 0; | 1859 | retval = 0; |
diff --git a/fs/ocfs2/ocfs2_fs.h b/fs/ocfs2/ocfs2_fs.h index b5c68567077e..e61e218f5e0b 100644 --- a/fs/ocfs2/ocfs2_fs.h +++ b/fs/ocfs2/ocfs2_fs.h | |||
@@ -85,7 +85,7 @@ | |||
85 | #define OCFS2_CLEAR_INCOMPAT_FEATURE(sb,mask) \ | 85 | #define OCFS2_CLEAR_INCOMPAT_FEATURE(sb,mask) \ |
86 | OCFS2_SB(sb)->s_feature_incompat &= ~(mask) | 86 | OCFS2_SB(sb)->s_feature_incompat &= ~(mask) |
87 | 87 | ||
88 | #define OCFS2_FEATURE_COMPAT_SUPP 0 | 88 | #define OCFS2_FEATURE_COMPAT_SUPP OCFS2_FEATURE_COMPAT_BACKUP_SB |
89 | #define OCFS2_FEATURE_INCOMPAT_SUPP OCFS2_FEATURE_INCOMPAT_LOCAL_MOUNT | 89 | #define OCFS2_FEATURE_INCOMPAT_SUPP OCFS2_FEATURE_INCOMPAT_LOCAL_MOUNT |
90 | #define OCFS2_FEATURE_RO_COMPAT_SUPP 0 | 90 | #define OCFS2_FEATURE_RO_COMPAT_SUPP 0 |
91 | 91 | ||
@@ -110,6 +110,20 @@ | |||
110 | #define OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC 0x0010 | 110 | #define OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC 0x0010 |
111 | 111 | ||
112 | /* | 112 | /* |
113 | * backup superblock flag is used to indicate that this volume | ||
114 | * has backup superblocks. | ||
115 | */ | ||
116 | #define OCFS2_FEATURE_COMPAT_BACKUP_SB 0x0001 | ||
117 | |||
118 | /* The byte offset of the first backup block will be 1G. | ||
119 | * The following will be 4G, 16G, 64G, 256G and 1T. | ||
120 | */ | ||
121 | #define OCFS2_BACKUP_SB_START 1 << 30 | ||
122 | |||
123 | /* the max backup superblock nums */ | ||
124 | #define OCFS2_MAX_BACKUP_SUPERBLOCKS 6 | ||
125 | |||
126 | /* | ||
113 | * Flags on ocfs2_dinode.i_flags | 127 | * Flags on ocfs2_dinode.i_flags |
114 | */ | 128 | */ |
115 | #define OCFS2_VALID_FL (0x00000001) /* Inode is valid */ | 129 | #define OCFS2_VALID_FL (0x00000001) /* Inode is valid */ |
@@ -566,6 +580,20 @@ static inline int ocfs2_truncate_recs_per_inode(struct super_block *sb) | |||
566 | 580 | ||
567 | return size / sizeof(struct ocfs2_truncate_rec); | 581 | return size / sizeof(struct ocfs2_truncate_rec); |
568 | } | 582 | } |
583 | |||
584 | static inline u64 ocfs2_backup_super_blkno(struct super_block *sb, int index) | ||
585 | { | ||
586 | u64 offset = OCFS2_BACKUP_SB_START; | ||
587 | |||
588 | if (index >= 0 && index < OCFS2_MAX_BACKUP_SUPERBLOCKS) { | ||
589 | offset <<= (2 * index); | ||
590 | offset >>= sb->s_blocksize_bits; | ||
591 | return offset; | ||
592 | } | ||
593 | |||
594 | return 0; | ||
595 | |||
596 | } | ||
569 | #else | 597 | #else |
570 | static inline int ocfs2_fast_symlink_chars(int blocksize) | 598 | static inline int ocfs2_fast_symlink_chars(int blocksize) |
571 | { | 599 | { |
@@ -631,6 +659,19 @@ static inline int ocfs2_truncate_recs_per_inode(int blocksize) | |||
631 | 659 | ||
632 | return size / sizeof(struct ocfs2_truncate_rec); | 660 | return size / sizeof(struct ocfs2_truncate_rec); |
633 | } | 661 | } |
662 | |||
663 | static inline uint64_t ocfs2_backup_super_blkno(int blocksize, int index) | ||
664 | { | ||
665 | uint64_t offset = OCFS2_BACKUP_SB_START; | ||
666 | |||
667 | if (index >= 0 && index < OCFS2_MAX_BACKUP_SUPERBLOCKS) { | ||
668 | offset <<= (2 * index); | ||
669 | offset /= blocksize; | ||
670 | return offset; | ||
671 | } | ||
672 | |||
673 | return 0; | ||
674 | } | ||
634 | #endif /* __KERNEL__ */ | 675 | #endif /* __KERNEL__ */ |
635 | 676 | ||
636 | 677 | ||
diff --git a/fs/ocfs2/symlink.c b/fs/ocfs2/symlink.c index 957d6878b03e..03b0191534d5 100644 --- a/fs/ocfs2/symlink.c +++ b/fs/ocfs2/symlink.c | |||
@@ -158,8 +158,7 @@ static void *ocfs2_follow_link(struct dentry *dentry, | |||
158 | } | 158 | } |
159 | 159 | ||
160 | status = vfs_follow_link(nd, link); | 160 | status = vfs_follow_link(nd, link); |
161 | if (status && status != -ENOENT) | 161 | |
162 | mlog_errno(status); | ||
163 | bail: | 162 | bail: |
164 | if (page) { | 163 | if (page) { |
165 | kunmap(page); | 164 | kunmap(page); |
diff --git a/fs/proc/base.c b/fs/proc/base.c index 77a57b5799c4..ff7a66850602 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -371,9 +371,11 @@ static int mounts_open(struct inode *inode, struct file *file) | |||
371 | 371 | ||
372 | if (task) { | 372 | if (task) { |
373 | task_lock(task); | 373 | task_lock(task); |
374 | ns = task->nsproxy->mnt_ns; | 374 | if (task->nsproxy) { |
375 | if (ns) | 375 | ns = task->nsproxy->mnt_ns; |
376 | get_mnt_ns(ns); | 376 | if (ns) |
377 | get_mnt_ns(ns); | ||
378 | } | ||
377 | task_unlock(task); | 379 | task_unlock(task); |
378 | put_task_struct(task); | 380 | put_task_struct(task); |
379 | } | 381 | } |
diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c index 99b6f329ba23..5109f1d5e7ff 100644 --- a/fs/reiserfs/file.c +++ b/fs/reiserfs/file.c | |||
@@ -48,6 +48,11 @@ static int reiserfs_file_release(struct inode *inode, struct file *filp) | |||
48 | } | 48 | } |
49 | 49 | ||
50 | mutex_lock(&inode->i_mutex); | 50 | mutex_lock(&inode->i_mutex); |
51 | |||
52 | mutex_lock(&(REISERFS_I(inode)->i_mmap)); | ||
53 | if (REISERFS_I(inode)->i_flags & i_ever_mapped) | ||
54 | REISERFS_I(inode)->i_flags &= ~i_pack_on_close_mask; | ||
55 | |||
51 | reiserfs_write_lock(inode->i_sb); | 56 | reiserfs_write_lock(inode->i_sb); |
52 | /* freeing preallocation only involves relogging blocks that | 57 | /* freeing preallocation only involves relogging blocks that |
53 | * are already in the current transaction. preallocation gets | 58 | * are already in the current transaction. preallocation gets |
@@ -100,11 +105,24 @@ static int reiserfs_file_release(struct inode *inode, struct file *filp) | |||
100 | err = reiserfs_truncate_file(inode, 0); | 105 | err = reiserfs_truncate_file(inode, 0); |
101 | } | 106 | } |
102 | out: | 107 | out: |
108 | mutex_unlock(&(REISERFS_I(inode)->i_mmap)); | ||
103 | mutex_unlock(&inode->i_mutex); | 109 | mutex_unlock(&inode->i_mutex); |
104 | reiserfs_write_unlock(inode->i_sb); | 110 | reiserfs_write_unlock(inode->i_sb); |
105 | return err; | 111 | return err; |
106 | } | 112 | } |
107 | 113 | ||
114 | static int reiserfs_file_mmap(struct file *file, struct vm_area_struct *vma) | ||
115 | { | ||
116 | struct inode *inode; | ||
117 | |||
118 | inode = file->f_path.dentry->d_inode; | ||
119 | mutex_lock(&(REISERFS_I(inode)->i_mmap)); | ||
120 | REISERFS_I(inode)->i_flags |= i_ever_mapped; | ||
121 | mutex_unlock(&(REISERFS_I(inode)->i_mmap)); | ||
122 | |||
123 | return generic_file_mmap(file, vma); | ||
124 | } | ||
125 | |||
108 | static void reiserfs_vfs_truncate_file(struct inode *inode) | 126 | static void reiserfs_vfs_truncate_file(struct inode *inode) |
109 | { | 127 | { |
110 | reiserfs_truncate_file(inode, 1); | 128 | reiserfs_truncate_file(inode, 1); |
@@ -1527,7 +1545,7 @@ const struct file_operations reiserfs_file_operations = { | |||
1527 | #ifdef CONFIG_COMPAT | 1545 | #ifdef CONFIG_COMPAT |
1528 | .compat_ioctl = reiserfs_compat_ioctl, | 1546 | .compat_ioctl = reiserfs_compat_ioctl, |
1529 | #endif | 1547 | #endif |
1530 | .mmap = generic_file_mmap, | 1548 | .mmap = reiserfs_file_mmap, |
1531 | .open = generic_file_open, | 1549 | .open = generic_file_open, |
1532 | .release = reiserfs_file_release, | 1550 | .release = reiserfs_file_release, |
1533 | .fsync = reiserfs_sync_file, | 1551 | .fsync = reiserfs_sync_file, |
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index f3d1c4a77979..9fcbfe316977 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c | |||
@@ -1125,6 +1125,7 @@ static void init_inode(struct inode *inode, struct treepath *path) | |||
1125 | REISERFS_I(inode)->i_prealloc_count = 0; | 1125 | REISERFS_I(inode)->i_prealloc_count = 0; |
1126 | REISERFS_I(inode)->i_trans_id = 0; | 1126 | REISERFS_I(inode)->i_trans_id = 0; |
1127 | REISERFS_I(inode)->i_jl = NULL; | 1127 | REISERFS_I(inode)->i_jl = NULL; |
1128 | mutex_init(&(REISERFS_I(inode)->i_mmap)); | ||
1128 | reiserfs_init_acl_access(inode); | 1129 | reiserfs_init_acl_access(inode); |
1129 | reiserfs_init_acl_default(inode); | 1130 | reiserfs_init_acl_default(inode); |
1130 | reiserfs_init_xattr_rwsem(inode); | 1131 | reiserfs_init_xattr_rwsem(inode); |
@@ -1832,6 +1833,7 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th, | |||
1832 | REISERFS_I(inode)->i_attrs = | 1833 | REISERFS_I(inode)->i_attrs = |
1833 | REISERFS_I(dir)->i_attrs & REISERFS_INHERIT_MASK; | 1834 | REISERFS_I(dir)->i_attrs & REISERFS_INHERIT_MASK; |
1834 | sd_attrs_to_i_attrs(REISERFS_I(inode)->i_attrs, inode); | 1835 | sd_attrs_to_i_attrs(REISERFS_I(inode)->i_attrs, inode); |
1836 | mutex_init(&(REISERFS_I(inode)->i_mmap)); | ||
1835 | reiserfs_init_acl_access(inode); | 1837 | reiserfs_init_acl_access(inode); |
1836 | reiserfs_init_acl_default(inode); | 1838 | reiserfs_init_acl_default(inode); |
1837 | reiserfs_init_xattr_rwsem(inode); | 1839 | reiserfs_init_xattr_rwsem(inode); |
diff --git a/fs/ufs/balloc.c b/fs/ufs/balloc.c index 2e0021e8f366..638f4c585e89 100644 --- a/fs/ufs/balloc.c +++ b/fs/ufs/balloc.c | |||
@@ -227,24 +227,27 @@ failed: | |||
227 | * We can come here from ufs_writepage or ufs_prepare_write, | 227 | * We can come here from ufs_writepage or ufs_prepare_write, |
228 | * locked_page is argument of these functions, so we already lock it. | 228 | * locked_page is argument of these functions, so we already lock it. |
229 | */ | 229 | */ |
230 | static void ufs_change_blocknr(struct inode *inode, unsigned int baseblk, | 230 | static void ufs_change_blocknr(struct inode *inode, unsigned int beg, |
231 | unsigned int count, unsigned int oldb, | 231 | unsigned int count, unsigned int oldb, |
232 | unsigned int newb, struct page *locked_page) | 232 | unsigned int newb, struct page *locked_page) |
233 | { | 233 | { |
234 | unsigned int blk_per_page = 1 << (PAGE_CACHE_SHIFT - inode->i_blkbits); | 234 | const unsigned mask = (1 << (PAGE_CACHE_SHIFT - inode->i_blkbits)) - 1; |
235 | struct address_space *mapping = inode->i_mapping; | 235 | struct address_space * const mapping = inode->i_mapping; |
236 | pgoff_t index, cur_index = locked_page->index; | 236 | pgoff_t index, cur_index; |
237 | unsigned int i, j; | 237 | unsigned end, pos, j; |
238 | struct page *page; | 238 | struct page *page; |
239 | struct buffer_head *head, *bh; | 239 | struct buffer_head *head, *bh; |
240 | 240 | ||
241 | UFSD("ENTER, ino %lu, count %u, oldb %u, newb %u\n", | 241 | UFSD("ENTER, ino %lu, count %u, oldb %u, newb %u\n", |
242 | inode->i_ino, count, oldb, newb); | 242 | inode->i_ino, count, oldb, newb); |
243 | 243 | ||
244 | BUG_ON(!locked_page); | ||
244 | BUG_ON(!PageLocked(locked_page)); | 245 | BUG_ON(!PageLocked(locked_page)); |
245 | 246 | ||
246 | for (i = 0; i < count; i += blk_per_page) { | 247 | cur_index = locked_page->index; |
247 | index = (baseblk+i) >> (PAGE_CACHE_SHIFT - inode->i_blkbits); | 248 | |
249 | for (end = count + beg; beg < end; beg = (beg | mask) + 1) { | ||
250 | index = beg >> (PAGE_CACHE_SHIFT - inode->i_blkbits); | ||
248 | 251 | ||
249 | if (likely(cur_index != index)) { | 252 | if (likely(cur_index != index)) { |
250 | page = ufs_get_locked_page(mapping, index); | 253 | page = ufs_get_locked_page(mapping, index); |
@@ -253,21 +256,32 @@ static void ufs_change_blocknr(struct inode *inode, unsigned int baseblk, | |||
253 | } else | 256 | } else |
254 | page = locked_page; | 257 | page = locked_page; |
255 | 258 | ||
256 | j = i; | ||
257 | head = page_buffers(page); | 259 | head = page_buffers(page); |
258 | bh = head; | 260 | bh = head; |
261 | pos = beg & mask; | ||
262 | for (j = 0; j < pos; ++j) | ||
263 | bh = bh->b_this_page; | ||
264 | j = 0; | ||
259 | do { | 265 | do { |
260 | if (likely(bh->b_blocknr == j + oldb && j < count)) { | 266 | if (buffer_mapped(bh)) { |
261 | unmap_underlying_metadata(bh->b_bdev, | 267 | pos = bh->b_blocknr - oldb; |
262 | bh->b_blocknr); | 268 | if (pos < count) { |
263 | bh->b_blocknr = newb + j++; | 269 | UFSD(" change from %llu to %llu\n", |
264 | mark_buffer_dirty(bh); | 270 | (unsigned long long)pos + oldb, |
271 | (unsigned long long)pos + newb); | ||
272 | bh->b_blocknr = newb + pos; | ||
273 | unmap_underlying_metadata(bh->b_bdev, | ||
274 | bh->b_blocknr); | ||
275 | mark_buffer_dirty(bh); | ||
276 | ++j; | ||
277 | } | ||
265 | } | 278 | } |
266 | 279 | ||
267 | bh = bh->b_this_page; | 280 | bh = bh->b_this_page; |
268 | } while (bh != head); | 281 | } while (bh != head); |
269 | 282 | ||
270 | set_page_dirty(page); | 283 | if (j) |
284 | set_page_dirty(page); | ||
271 | 285 | ||
272 | if (likely(cur_index != index)) | 286 | if (likely(cur_index != index)) |
273 | ufs_put_locked_page(page); | 287 | ufs_put_locked_page(page); |
@@ -415,14 +429,14 @@ unsigned ufs_new_fragments(struct inode * inode, __fs32 * p, unsigned fragment, | |||
415 | } | 429 | } |
416 | result = ufs_alloc_fragments (inode, cgno, goal, request, err); | 430 | result = ufs_alloc_fragments (inode, cgno, goal, request, err); |
417 | if (result) { | 431 | if (result) { |
432 | ufs_clear_frags(inode, result + oldcount, newcount - oldcount, | ||
433 | locked_page != NULL); | ||
418 | ufs_change_blocknr(inode, fragment - oldcount, oldcount, tmp, | 434 | ufs_change_blocknr(inode, fragment - oldcount, oldcount, tmp, |
419 | result, locked_page); | 435 | result, locked_page); |
420 | 436 | ||
421 | *p = cpu_to_fs32(sb, result); | 437 | *p = cpu_to_fs32(sb, result); |
422 | *err = 0; | 438 | *err = 0; |
423 | UFS_I(inode)->i_lastfrag = max_t(u32, UFS_I(inode)->i_lastfrag, fragment + count); | 439 | UFS_I(inode)->i_lastfrag = max_t(u32, UFS_I(inode)->i_lastfrag, fragment + count); |
424 | ufs_clear_frags(inode, result + oldcount, newcount - oldcount, | ||
425 | locked_page != NULL); | ||
426 | unlock_super(sb); | 440 | unlock_super(sb); |
427 | if (newcount < request) | 441 | if (newcount < request) |
428 | ufs_free_fragments (inode, result + newcount, request - newcount); | 442 | ufs_free_fragments (inode, result + newcount, request - newcount); |
diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index 2fbab0aab688..4295ca91cf85 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c | |||
@@ -242,7 +242,8 @@ repeat: | |||
242 | goal = tmp + uspi->s_fpb; | 242 | goal = tmp + uspi->s_fpb; |
243 | tmp = ufs_new_fragments (inode, p, fragment - blockoff, | 243 | tmp = ufs_new_fragments (inode, p, fragment - blockoff, |
244 | goal, required + blockoff, | 244 | goal, required + blockoff, |
245 | err, locked_page); | 245 | err, |
246 | phys != NULL ? locked_page : NULL); | ||
246 | } | 247 | } |
247 | /* | 248 | /* |
248 | * We will extend last allocated block | 249 | * We will extend last allocated block |
@@ -250,7 +251,7 @@ repeat: | |||
250 | else if (lastblock == block) { | 251 | else if (lastblock == block) { |
251 | tmp = ufs_new_fragments(inode, p, fragment - (blockoff - lastblockoff), | 252 | tmp = ufs_new_fragments(inode, p, fragment - (blockoff - lastblockoff), |
252 | fs32_to_cpu(sb, *p), required + (blockoff - lastblockoff), | 253 | fs32_to_cpu(sb, *p), required + (blockoff - lastblockoff), |
253 | err, locked_page); | 254 | err, phys != NULL ? locked_page : NULL); |
254 | } else /* (lastblock > block) */ { | 255 | } else /* (lastblock > block) */ { |
255 | /* | 256 | /* |
256 | * We will allocate new block before last allocated block | 257 | * We will allocate new block before last allocated block |
@@ -261,7 +262,8 @@ repeat: | |||
261 | goal = tmp + uspi->s_fpb; | 262 | goal = tmp + uspi->s_fpb; |
262 | } | 263 | } |
263 | tmp = ufs_new_fragments(inode, p, fragment - blockoff, | 264 | tmp = ufs_new_fragments(inode, p, fragment - blockoff, |
264 | goal, uspi->s_fpb, err, locked_page); | 265 | goal, uspi->s_fpb, err, |
266 | phys != NULL ? locked_page : NULL); | ||
265 | } | 267 | } |
266 | if (!tmp) { | 268 | if (!tmp) { |
267 | if ((!blockoff && *p) || | 269 | if ((!blockoff && *p) || |
@@ -438,9 +440,11 @@ int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buffer_head | |||
438 | * it much more readable: | 440 | * it much more readable: |
439 | */ | 441 | */ |
440 | #define GET_INODE_DATABLOCK(x) \ | 442 | #define GET_INODE_DATABLOCK(x) \ |
441 | ufs_inode_getfrag(inode, x, fragment, 1, &err, &phys, &new, bh_result->b_page) | 443 | ufs_inode_getfrag(inode, x, fragment, 1, &err, &phys, &new,\ |
444 | bh_result->b_page) | ||
442 | #define GET_INODE_PTR(x) \ | 445 | #define GET_INODE_PTR(x) \ |
443 | ufs_inode_getfrag(inode, x, fragment, uspi->s_fpb, &err, NULL, NULL, NULL) | 446 | ufs_inode_getfrag(inode, x, fragment, uspi->s_fpb, &err, NULL, NULL,\ |
447 | bh_result->b_page) | ||
444 | #define GET_INDIRECT_DATABLOCK(x) \ | 448 | #define GET_INDIRECT_DATABLOCK(x) \ |
445 | ufs_inode_getblock(inode, bh, x, fragment, \ | 449 | ufs_inode_getblock(inode, bh, x, fragment, \ |
446 | &err, &phys, &new, bh_result->b_page) | 450 | &err, &phys, &new, bh_result->b_page) |
diff --git a/fs/ufs/truncate.c b/fs/ufs/truncate.c index ea11d04c41a0..0437b0a6fe97 100644 --- a/fs/ufs/truncate.c +++ b/fs/ufs/truncate.c | |||
@@ -109,10 +109,10 @@ static int ufs_trunc_direct (struct inode * inode) | |||
109 | tmp = fs32_to_cpu(sb, *p); | 109 | tmp = fs32_to_cpu(sb, *p); |
110 | if (!tmp ) | 110 | if (!tmp ) |
111 | ufs_panic (sb, "ufs_trunc_direct", "internal error"); | 111 | ufs_panic (sb, "ufs_trunc_direct", "internal error"); |
112 | frag2 -= frag1; | ||
112 | frag1 = ufs_fragnum (frag1); | 113 | frag1 = ufs_fragnum (frag1); |
113 | frag2 = ufs_fragnum (frag2); | ||
114 | 114 | ||
115 | ufs_free_fragments (inode, tmp + frag1, frag2 - frag1); | 115 | ufs_free_fragments(inode, tmp + frag1, frag2); |
116 | mark_inode_dirty(inode); | 116 | mark_inode_dirty(inode); |
117 | frag_to_free = tmp + frag1; | 117 | frag_to_free = tmp + frag1; |
118 | 118 | ||