diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-11 00:46:36 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-11 00:46:36 -0500 |
commit | 5cd9599bba428762025db6027764f1c59d0b1e1b (patch) | |
tree | cb59ea13f6e6de4350ca38338bf9633e89f8418a | |
parent | e343a895a9f342f239c5e3c5ffc6c0b1707e6244 (diff) | |
parent | d668dc56631da067540b2494d2a1f29ff7b5f15a (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
autofs4: deal with autofs4_write/autofs4_write races
autofs4: catatonic_mode vs. notify_daemon race
autofs4: autofs4_wait() vs. autofs4_catatonic_mode() race
hfsplus: creation of hidden dir on mount can fail
block_dev: Suppress bdev_cache_init() kmemleak warninig
fix shrink_dcache_parent() livelock
coda: switch coda_cnode_make() to sane API as well, clean coda_lookup()
coda: deal correctly with allocation failure from coda_cnode_makectl()
securityfs: fix object creation races
-rw-r--r-- | fs/autofs4/autofs_i.h | 1 | ||||
-rw-r--r-- | fs/autofs4/inode.c | 1 | ||||
-rw-r--r-- | fs/autofs4/waitq.c | 40 | ||||
-rw-r--r-- | fs/block_dev.c | 10 | ||||
-rw-r--r-- | fs/coda/cnode.c | 38 | ||||
-rw-r--r-- | fs/coda/coda_fs_i.h | 4 | ||||
-rw-r--r-- | fs/coda/dir.c | 29 | ||||
-rw-r--r-- | fs/coda/inode.c | 10 | ||||
-rw-r--r-- | fs/dcache.c | 15 | ||||
-rw-r--r-- | fs/hfsplus/super.c | 11 | ||||
-rw-r--r-- | include/linux/dcache.h | 1 | ||||
-rw-r--r-- | security/inode.c | 191 |
12 files changed, 137 insertions, 214 deletions
diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h index 5869d4e974a9..d8d8e7ba6a1e 100644 --- a/fs/autofs4/autofs_i.h +++ b/fs/autofs4/autofs_i.h | |||
@@ -116,6 +116,7 @@ struct autofs_sb_info { | |||
116 | int needs_reghost; | 116 | int needs_reghost; |
117 | struct super_block *sb; | 117 | struct super_block *sb; |
118 | struct mutex wq_mutex; | 118 | struct mutex wq_mutex; |
119 | struct mutex pipe_mutex; | ||
119 | spinlock_t fs_lock; | 120 | spinlock_t fs_lock; |
120 | struct autofs_wait_queue *queues; /* Wait queue pointer */ | 121 | struct autofs_wait_queue *queues; /* Wait queue pointer */ |
121 | spinlock_t lookup_lock; | 122 | spinlock_t lookup_lock; |
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c index 2ba44c79d548..e16980b00b8d 100644 --- a/fs/autofs4/inode.c +++ b/fs/autofs4/inode.c | |||
@@ -225,6 +225,7 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent) | |||
225 | sbi->min_proto = 0; | 225 | sbi->min_proto = 0; |
226 | sbi->max_proto = 0; | 226 | sbi->max_proto = 0; |
227 | mutex_init(&sbi->wq_mutex); | 227 | mutex_init(&sbi->wq_mutex); |
228 | mutex_init(&sbi->pipe_mutex); | ||
228 | spin_lock_init(&sbi->fs_lock); | 229 | spin_lock_init(&sbi->fs_lock); |
229 | sbi->queues = NULL; | 230 | sbi->queues = NULL; |
230 | spin_lock_init(&sbi->lookup_lock); | 231 | spin_lock_init(&sbi->lookup_lock); |
diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c index e1fbdeef85db..9ef5b2914407 100644 --- a/fs/autofs4/waitq.c +++ b/fs/autofs4/waitq.c | |||
@@ -56,26 +56,27 @@ void autofs4_catatonic_mode(struct autofs_sb_info *sbi) | |||
56 | mutex_unlock(&sbi->wq_mutex); | 56 | mutex_unlock(&sbi->wq_mutex); |
57 | } | 57 | } |
58 | 58 | ||
59 | static int autofs4_write(struct file *file, const void *addr, int bytes) | 59 | static int autofs4_write(struct autofs_sb_info *sbi, |
60 | struct file *file, const void *addr, int bytes) | ||
60 | { | 61 | { |
61 | unsigned long sigpipe, flags; | 62 | unsigned long sigpipe, flags; |
62 | mm_segment_t fs; | 63 | mm_segment_t fs; |
63 | const char *data = (const char *)addr; | 64 | const char *data = (const char *)addr; |
64 | ssize_t wr = 0; | 65 | ssize_t wr = 0; |
65 | 66 | ||
66 | /** WARNING: this is not safe for writing more than PIPE_BUF bytes! **/ | ||
67 | |||
68 | sigpipe = sigismember(¤t->pending.signal, SIGPIPE); | 67 | sigpipe = sigismember(¤t->pending.signal, SIGPIPE); |
69 | 68 | ||
70 | /* Save pointer to user space and point back to kernel space */ | 69 | /* Save pointer to user space and point back to kernel space */ |
71 | fs = get_fs(); | 70 | fs = get_fs(); |
72 | set_fs(KERNEL_DS); | 71 | set_fs(KERNEL_DS); |
73 | 72 | ||
73 | mutex_lock(&sbi->pipe_mutex); | ||
74 | while (bytes && | 74 | while (bytes && |
75 | (wr = file->f_op->write(file,data,bytes,&file->f_pos)) > 0) { | 75 | (wr = file->f_op->write(file,data,bytes,&file->f_pos)) > 0) { |
76 | data += wr; | 76 | data += wr; |
77 | bytes -= wr; | 77 | bytes -= wr; |
78 | } | 78 | } |
79 | mutex_lock(&sbi->pipe_mutex); | ||
79 | 80 | ||
80 | set_fs(fs); | 81 | set_fs(fs); |
81 | 82 | ||
@@ -110,6 +111,13 @@ static void autofs4_notify_daemon(struct autofs_sb_info *sbi, | |||
110 | 111 | ||
111 | pkt.hdr.proto_version = sbi->version; | 112 | pkt.hdr.proto_version = sbi->version; |
112 | pkt.hdr.type = type; | 113 | pkt.hdr.type = type; |
114 | mutex_lock(&sbi->wq_mutex); | ||
115 | |||
116 | /* Check if we have become catatonic */ | ||
117 | if (sbi->catatonic) { | ||
118 | mutex_unlock(&sbi->wq_mutex); | ||
119 | return; | ||
120 | } | ||
113 | switch (type) { | 121 | switch (type) { |
114 | /* Kernel protocol v4 missing and expire packets */ | 122 | /* Kernel protocol v4 missing and expire packets */ |
115 | case autofs_ptype_missing: | 123 | case autofs_ptype_missing: |
@@ -163,22 +171,18 @@ static void autofs4_notify_daemon(struct autofs_sb_info *sbi, | |||
163 | } | 171 | } |
164 | default: | 172 | default: |
165 | printk("autofs4_notify_daemon: bad type %d!\n", type); | 173 | printk("autofs4_notify_daemon: bad type %d!\n", type); |
174 | mutex_unlock(&sbi->wq_mutex); | ||
166 | return; | 175 | return; |
167 | } | 176 | } |
168 | 177 | ||
169 | /* Check if we have become catatonic */ | 178 | pipe = sbi->pipe; |
170 | mutex_lock(&sbi->wq_mutex); | 179 | get_file(pipe); |
171 | if (!sbi->catatonic) { | 180 | |
172 | pipe = sbi->pipe; | ||
173 | get_file(pipe); | ||
174 | } | ||
175 | mutex_unlock(&sbi->wq_mutex); | 181 | mutex_unlock(&sbi->wq_mutex); |
176 | 182 | ||
177 | if (pipe) { | 183 | if (autofs4_write(sbi, pipe, &pkt, pktsz)) |
178 | if (autofs4_write(pipe, &pkt, pktsz)) | 184 | autofs4_catatonic_mode(sbi); |
179 | autofs4_catatonic_mode(sbi); | 185 | fput(pipe); |
180 | fput(pipe); | ||
181 | } | ||
182 | } | 186 | } |
183 | 187 | ||
184 | static int autofs4_getpath(struct autofs_sb_info *sbi, | 188 | static int autofs4_getpath(struct autofs_sb_info *sbi, |
@@ -257,6 +261,9 @@ static int validate_request(struct autofs_wait_queue **wait, | |||
257 | struct autofs_wait_queue *wq; | 261 | struct autofs_wait_queue *wq; |
258 | struct autofs_info *ino; | 262 | struct autofs_info *ino; |
259 | 263 | ||
264 | if (sbi->catatonic) | ||
265 | return -ENOENT; | ||
266 | |||
260 | /* Wait in progress, continue; */ | 267 | /* Wait in progress, continue; */ |
261 | wq = autofs4_find_wait(sbi, qstr); | 268 | wq = autofs4_find_wait(sbi, qstr); |
262 | if (wq) { | 269 | if (wq) { |
@@ -289,6 +296,9 @@ static int validate_request(struct autofs_wait_queue **wait, | |||
289 | if (mutex_lock_interruptible(&sbi->wq_mutex)) | 296 | if (mutex_lock_interruptible(&sbi->wq_mutex)) |
290 | return -EINTR; | 297 | return -EINTR; |
291 | 298 | ||
299 | if (sbi->catatonic) | ||
300 | return -ENOENT; | ||
301 | |||
292 | wq = autofs4_find_wait(sbi, qstr); | 302 | wq = autofs4_find_wait(sbi, qstr); |
293 | if (wq) { | 303 | if (wq) { |
294 | *wait = wq; | 304 | *wait = wq; |
@@ -389,7 +399,7 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry, | |||
389 | 399 | ||
390 | ret = validate_request(&wq, sbi, &qstr, dentry, notify); | 400 | ret = validate_request(&wq, sbi, &qstr, dentry, notify); |
391 | if (ret <= 0) { | 401 | if (ret <= 0) { |
392 | if (ret == 0) | 402 | if (ret != -EINTR) |
393 | mutex_unlock(&sbi->wq_mutex); | 403 | mutex_unlock(&sbi->wq_mutex); |
394 | kfree(qstr.name); | 404 | kfree(qstr.name); |
395 | return ret; | 405 | return ret; |
diff --git a/fs/block_dev.c b/fs/block_dev.c index 69a5b6fbee2b..afe74dda632b 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
@@ -25,7 +25,6 @@ | |||
25 | #include <linux/uio.h> | 25 | #include <linux/uio.h> |
26 | #include <linux/namei.h> | 26 | #include <linux/namei.h> |
27 | #include <linux/log2.h> | 27 | #include <linux/log2.h> |
28 | #include <linux/kmemleak.h> | ||
29 | #include <linux/cleancache.h> | 28 | #include <linux/cleancache.h> |
30 | #include <asm/uaccess.h> | 29 | #include <asm/uaccess.h> |
31 | #include "internal.h" | 30 | #include "internal.h" |
@@ -521,7 +520,7 @@ static struct super_block *blockdev_superblock __read_mostly; | |||
521 | void __init bdev_cache_init(void) | 520 | void __init bdev_cache_init(void) |
522 | { | 521 | { |
523 | int err; | 522 | int err; |
524 | struct vfsmount *bd_mnt; | 523 | static struct vfsmount *bd_mnt; |
525 | 524 | ||
526 | bdev_cachep = kmem_cache_create("bdev_cache", sizeof(struct bdev_inode), | 525 | bdev_cachep = kmem_cache_create("bdev_cache", sizeof(struct bdev_inode), |
527 | 0, (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT| | 526 | 0, (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT| |
@@ -533,12 +532,7 @@ void __init bdev_cache_init(void) | |||
533 | bd_mnt = kern_mount(&bd_type); | 532 | bd_mnt = kern_mount(&bd_type); |
534 | if (IS_ERR(bd_mnt)) | 533 | if (IS_ERR(bd_mnt)) |
535 | panic("Cannot create bdev pseudo-fs"); | 534 | panic("Cannot create bdev pseudo-fs"); |
536 | /* | 535 | blockdev_superblock = bd_mnt->mnt_sb; /* For writeback */ |
537 | * This vfsmount structure is only used to obtain the | ||
538 | * blockdev_superblock, so tell kmemleak not to report it. | ||
539 | */ | ||
540 | kmemleak_not_leak(bd_mnt); | ||
541 | blockdev_superblock = bd_mnt->mnt_sb; /* For writeback */ | ||
542 | } | 536 | } |
543 | 537 | ||
544 | /* | 538 | /* |
diff --git a/fs/coda/cnode.c b/fs/coda/cnode.c index 6475877b0763..911cf30d057d 100644 --- a/fs/coda/cnode.c +++ b/fs/coda/cnode.c | |||
@@ -88,24 +88,21 @@ struct inode * coda_iget(struct super_block * sb, struct CodaFid * fid, | |||
88 | - link the two up if this is needed | 88 | - link the two up if this is needed |
89 | - fill in the attributes | 89 | - fill in the attributes |
90 | */ | 90 | */ |
91 | int coda_cnode_make(struct inode **inode, struct CodaFid *fid, struct super_block *sb) | 91 | struct inode *coda_cnode_make(struct CodaFid *fid, struct super_block *sb) |
92 | { | 92 | { |
93 | struct coda_vattr attr; | 93 | struct coda_vattr attr; |
94 | struct inode *inode; | ||
94 | int error; | 95 | int error; |
95 | 96 | ||
96 | /* We get inode numbers from Venus -- see venus source */ | 97 | /* We get inode numbers from Venus -- see venus source */ |
97 | error = venus_getattr(sb, fid, &attr); | 98 | error = venus_getattr(sb, fid, &attr); |
98 | if ( error ) { | 99 | if (error) |
99 | *inode = NULL; | 100 | return ERR_PTR(error); |
100 | return error; | ||
101 | } | ||
102 | 101 | ||
103 | *inode = coda_iget(sb, fid, &attr); | 102 | inode = coda_iget(sb, fid, &attr); |
104 | if ( IS_ERR(*inode) ) { | 103 | if (IS_ERR(inode)) |
105 | printk("coda_cnode_make: coda_iget failed\n"); | 104 | printk("coda_cnode_make: coda_iget failed\n"); |
106 | return PTR_ERR(*inode); | 105 | return inode; |
107 | } | ||
108 | return 0; | ||
109 | } | 106 | } |
110 | 107 | ||
111 | 108 | ||
@@ -156,19 +153,16 @@ struct inode *coda_fid_to_inode(struct CodaFid *fid, struct super_block *sb) | |||
156 | } | 153 | } |
157 | 154 | ||
158 | /* the CONTROL inode is made without asking attributes from Venus */ | 155 | /* the CONTROL inode is made without asking attributes from Venus */ |
159 | int coda_cnode_makectl(struct inode **inode, struct super_block *sb) | 156 | struct inode *coda_cnode_makectl(struct super_block *sb) |
160 | { | 157 | { |
161 | int error = -ENOMEM; | 158 | struct inode *inode = new_inode(sb); |
162 | 159 | if (inode) { | |
163 | *inode = new_inode(sb); | 160 | inode->i_ino = CTL_INO; |
164 | if (*inode) { | 161 | inode->i_op = &coda_ioctl_inode_operations; |
165 | (*inode)->i_ino = CTL_INO; | 162 | inode->i_fop = &coda_ioctl_operations; |
166 | (*inode)->i_op = &coda_ioctl_inode_operations; | 163 | inode->i_mode = 0444; |
167 | (*inode)->i_fop = &coda_ioctl_operations; | 164 | return inode; |
168 | (*inode)->i_mode = 0444; | ||
169 | error = 0; | ||
170 | } | 165 | } |
171 | 166 | return ERR_PTR(-ENOMEM); | |
172 | return error; | ||
173 | } | 167 | } |
174 | 168 | ||
diff --git a/fs/coda/coda_fs_i.h b/fs/coda/coda_fs_i.h index e35071b1de0e..b24fdfd8a3f0 100644 --- a/fs/coda/coda_fs_i.h +++ b/fs/coda/coda_fs_i.h | |||
@@ -49,9 +49,9 @@ struct coda_file_info { | |||
49 | #define C_DYING 0x4 /* from venus (which died) */ | 49 | #define C_DYING 0x4 /* from venus (which died) */ |
50 | #define C_PURGE 0x8 | 50 | #define C_PURGE 0x8 |
51 | 51 | ||
52 | int coda_cnode_make(struct inode **, struct CodaFid *, struct super_block *); | 52 | struct inode *coda_cnode_make(struct CodaFid *, struct super_block *); |
53 | struct inode *coda_iget(struct super_block *sb, struct CodaFid *fid, struct coda_vattr *attr); | 53 | struct inode *coda_iget(struct super_block *sb, struct CodaFid *fid, struct coda_vattr *attr); |
54 | int coda_cnode_makectl(struct inode **inode, struct super_block *sb); | 54 | struct inode *coda_cnode_makectl(struct super_block *sb); |
55 | struct inode *coda_fid_to_inode(struct CodaFid *fid, struct super_block *sb); | 55 | struct inode *coda_fid_to_inode(struct CodaFid *fid, struct super_block *sb); |
56 | void coda_replace_fid(struct inode *, struct CodaFid *, struct CodaFid *); | 56 | void coda_replace_fid(struct inode *, struct CodaFid *, struct CodaFid *); |
57 | 57 | ||
diff --git a/fs/coda/dir.c b/fs/coda/dir.c index 83d2fd8ec24b..177515829062 100644 --- a/fs/coda/dir.c +++ b/fs/coda/dir.c | |||
@@ -96,12 +96,11 @@ const struct file_operations coda_dir_operations = { | |||
96 | /* access routines: lookup, readlink, permission */ | 96 | /* access routines: lookup, readlink, permission */ |
97 | static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry, struct nameidata *nd) | 97 | static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry, struct nameidata *nd) |
98 | { | 98 | { |
99 | struct inode *inode = NULL; | 99 | struct super_block *sb = dir->i_sb; |
100 | struct CodaFid resfid = { { 0, } }; | ||
101 | int type = 0; | ||
102 | int error = 0; | ||
103 | const char *name = entry->d_name.name; | 100 | const char *name = entry->d_name.name; |
104 | size_t length = entry->d_name.len; | 101 | size_t length = entry->d_name.len; |
102 | struct inode *inode; | ||
103 | int type = 0; | ||
105 | 104 | ||
106 | if (length > CODA_MAXNAMLEN) { | 105 | if (length > CODA_MAXNAMLEN) { |
107 | printk(KERN_ERR "name too long: lookup, %s (%*s)\n", | 106 | printk(KERN_ERR "name too long: lookup, %s (%*s)\n", |
@@ -111,23 +110,21 @@ static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry, struc | |||
111 | 110 | ||
112 | /* control object, create inode on the fly */ | 111 | /* control object, create inode on the fly */ |
113 | if (coda_isroot(dir) && coda_iscontrol(name, length)) { | 112 | if (coda_isroot(dir) && coda_iscontrol(name, length)) { |
114 | error = coda_cnode_makectl(&inode, dir->i_sb); | 113 | inode = coda_cnode_makectl(sb); |
115 | type = CODA_NOCACHE; | 114 | type = CODA_NOCACHE; |
116 | goto exit; | 115 | } else { |
116 | struct CodaFid fid = { { 0, } }; | ||
117 | int error = venus_lookup(sb, coda_i2f(dir), name, length, | ||
118 | &type, &fid); | ||
119 | inode = !error ? coda_cnode_make(&fid, sb) : ERR_PTR(error); | ||
117 | } | 120 | } |
118 | 121 | ||
119 | error = venus_lookup(dir->i_sb, coda_i2f(dir), name, length, | 122 | if (!IS_ERR(inode) && (type & CODA_NOCACHE)) |
120 | &type, &resfid); | ||
121 | if (!error) | ||
122 | error = coda_cnode_make(&inode, &resfid, dir->i_sb); | ||
123 | |||
124 | if (error && error != -ENOENT) | ||
125 | return ERR_PTR(error); | ||
126 | |||
127 | exit: | ||
128 | if (inode && (type & CODA_NOCACHE)) | ||
129 | coda_flag_inode(inode, C_VATTR | C_PURGE); | 123 | coda_flag_inode(inode, C_VATTR | C_PURGE); |
130 | 124 | ||
125 | if (inode == ERR_PTR(-ENOENT)) | ||
126 | inode = NULL; | ||
127 | |||
131 | return d_splice_alias(inode, entry); | 128 | return d_splice_alias(inode, entry); |
132 | } | 129 | } |
133 | 130 | ||
diff --git a/fs/coda/inode.c b/fs/coda/inode.c index 1c08a8cd673a..5e2e1b3f068d 100644 --- a/fs/coda/inode.c +++ b/fs/coda/inode.c | |||
@@ -204,10 +204,12 @@ static int coda_fill_super(struct super_block *sb, void *data, int silent) | |||
204 | printk("coda_read_super: rootfid is %s\n", coda_f2s(&fid)); | 204 | printk("coda_read_super: rootfid is %s\n", coda_f2s(&fid)); |
205 | 205 | ||
206 | /* make root inode */ | 206 | /* make root inode */ |
207 | error = coda_cnode_make(&root, &fid, sb); | 207 | root = coda_cnode_make(&fid, sb); |
208 | if ( error || !root ) { | 208 | if (IS_ERR(root)) { |
209 | printk("Failure of coda_cnode_make for root: error %d\n", error); | 209 | error = PTR_ERR(root); |
210 | goto error; | 210 | printk("Failure of coda_cnode_make for root: error %d\n", error); |
211 | root = NULL; | ||
212 | goto error; | ||
211 | } | 213 | } |
212 | 214 | ||
213 | printk("coda_read_super: rootinode is %ld dev %s\n", | 215 | printk("coda_read_super: rootinode is %ld dev %s\n", |
diff --git a/fs/dcache.c b/fs/dcache.c index 3c6d3113a255..616fedff011a 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -243,6 +243,7 @@ static void dentry_lru_add(struct dentry *dentry) | |||
243 | static void __dentry_lru_del(struct dentry *dentry) | 243 | static void __dentry_lru_del(struct dentry *dentry) |
244 | { | 244 | { |
245 | list_del_init(&dentry->d_lru); | 245 | list_del_init(&dentry->d_lru); |
246 | dentry->d_flags &= ~DCACHE_SHRINK_LIST; | ||
246 | dentry->d_sb->s_nr_dentry_unused--; | 247 | dentry->d_sb->s_nr_dentry_unused--; |
247 | dentry_stat.nr_unused--; | 248 | dentry_stat.nr_unused--; |
248 | } | 249 | } |
@@ -806,6 +807,7 @@ relock: | |||
806 | spin_unlock(&dentry->d_lock); | 807 | spin_unlock(&dentry->d_lock); |
807 | } else { | 808 | } else { |
808 | list_move_tail(&dentry->d_lru, &tmp); | 809 | list_move_tail(&dentry->d_lru, &tmp); |
810 | dentry->d_flags |= DCACHE_SHRINK_LIST; | ||
809 | spin_unlock(&dentry->d_lock); | 811 | spin_unlock(&dentry->d_lock); |
810 | if (!--count) | 812 | if (!--count) |
811 | break; | 813 | break; |
@@ -1097,14 +1099,19 @@ resume: | |||
1097 | 1099 | ||
1098 | /* | 1100 | /* |
1099 | * move only zero ref count dentries to the dispose list. | 1101 | * move only zero ref count dentries to the dispose list. |
1102 | * | ||
1103 | * Those which are presently on the shrink list, being processed | ||
1104 | * by shrink_dentry_list(), shouldn't be moved. Otherwise the | ||
1105 | * loop in shrink_dcache_parent() might not make any progress | ||
1106 | * and loop forever. | ||
1100 | */ | 1107 | */ |
1101 | if (!dentry->d_count) { | 1108 | if (dentry->d_count) { |
1109 | dentry_lru_del(dentry); | ||
1110 | } else if (!(dentry->d_flags & DCACHE_SHRINK_LIST)) { | ||
1102 | dentry_lru_move_list(dentry, dispose); | 1111 | dentry_lru_move_list(dentry, dispose); |
1112 | dentry->d_flags |= DCACHE_SHRINK_LIST; | ||
1103 | found++; | 1113 | found++; |
1104 | } else { | ||
1105 | dentry_lru_del(dentry); | ||
1106 | } | 1114 | } |
1107 | |||
1108 | /* | 1115 | /* |
1109 | * We can return to the caller if we have found some (this | 1116 | * We can return to the caller if we have found some (this |
1110 | * ensures forward progress). We'll be coming back to find | 1117 | * ensures forward progress). We'll be coming back to find |
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c index edf0a801446b..427682ca9e48 100644 --- a/fs/hfsplus/super.c +++ b/fs/hfsplus/super.c | |||
@@ -499,9 +499,16 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) | |||
499 | if (!sbi->hidden_dir) { | 499 | if (!sbi->hidden_dir) { |
500 | mutex_lock(&sbi->vh_mutex); | 500 | mutex_lock(&sbi->vh_mutex); |
501 | sbi->hidden_dir = hfsplus_new_inode(sb, S_IFDIR); | 501 | sbi->hidden_dir = hfsplus_new_inode(sb, S_IFDIR); |
502 | hfsplus_create_cat(sbi->hidden_dir->i_ino, root, &str, | 502 | if (!sbi->hidden_dir) { |
503 | sbi->hidden_dir); | 503 | mutex_unlock(&sbi->vh_mutex); |
504 | err = -ENOMEM; | ||
505 | goto out_put_root; | ||
506 | } | ||
507 | err = hfsplus_create_cat(sbi->hidden_dir->i_ino, root, | ||
508 | &str, sbi->hidden_dir); | ||
504 | mutex_unlock(&sbi->vh_mutex); | 509 | mutex_unlock(&sbi->vh_mutex); |
510 | if (err) | ||
511 | goto out_put_hidden_dir; | ||
505 | 512 | ||
506 | hfsplus_mark_inode_dirty(sbi->hidden_dir, | 513 | hfsplus_mark_inode_dirty(sbi->hidden_dir, |
507 | HFSPLUS_I_CAT_DIRTY); | 514 | HFSPLUS_I_CAT_DIRTY); |
diff --git a/include/linux/dcache.h b/include/linux/dcache.h index a47bda5f76db..31f73220e7d7 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h | |||
@@ -203,6 +203,7 @@ struct dentry_operations { | |||
203 | 203 | ||
204 | #define DCACHE_CANT_MOUNT 0x0100 | 204 | #define DCACHE_CANT_MOUNT 0x0100 |
205 | #define DCACHE_GENOCIDE 0x0200 | 205 | #define DCACHE_GENOCIDE 0x0200 |
206 | #define DCACHE_SHRINK_LIST 0x0400 | ||
206 | 207 | ||
207 | #define DCACHE_NFSFS_RENAMED 0x1000 | 208 | #define DCACHE_NFSFS_RENAMED 0x1000 |
208 | /* this dentry has been "silly renamed" and has to be deleted on the last | 209 | /* this dentry has been "silly renamed" and has to be deleted on the last |
diff --git a/security/inode.c b/security/inode.c index 90a70a67d835..43ce6e19015f 100644 --- a/security/inode.c +++ b/security/inode.c | |||
@@ -25,100 +25,6 @@ | |||
25 | static struct vfsmount *mount; | 25 | static struct vfsmount *mount; |
26 | static int mount_count; | 26 | static int mount_count; |
27 | 27 | ||
28 | /* | ||
29 | * TODO: | ||
30 | * I think I can get rid of these default_file_ops, but not quite sure... | ||
31 | */ | ||
32 | static ssize_t default_read_file(struct file *file, char __user *buf, | ||
33 | size_t count, loff_t *ppos) | ||
34 | { | ||
35 | return 0; | ||
36 | } | ||
37 | |||
38 | static ssize_t default_write_file(struct file *file, const char __user *buf, | ||
39 | size_t count, loff_t *ppos) | ||
40 | { | ||
41 | return count; | ||
42 | } | ||
43 | |||
44 | static int default_open(struct inode *inode, struct file *file) | ||
45 | { | ||
46 | if (inode->i_private) | ||
47 | file->private_data = inode->i_private; | ||
48 | |||
49 | return 0; | ||
50 | } | ||
51 | |||
52 | static const struct file_operations default_file_ops = { | ||
53 | .read = default_read_file, | ||
54 | .write = default_write_file, | ||
55 | .open = default_open, | ||
56 | .llseek = noop_llseek, | ||
57 | }; | ||
58 | |||
59 | static struct inode *get_inode(struct super_block *sb, umode_t mode, dev_t dev) | ||
60 | { | ||
61 | struct inode *inode = new_inode(sb); | ||
62 | |||
63 | if (inode) { | ||
64 | inode->i_ino = get_next_ino(); | ||
65 | inode->i_mode = mode; | ||
66 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; | ||
67 | switch (mode & S_IFMT) { | ||
68 | default: | ||
69 | init_special_inode(inode, mode, dev); | ||
70 | break; | ||
71 | case S_IFREG: | ||
72 | inode->i_fop = &default_file_ops; | ||
73 | break; | ||
74 | case S_IFDIR: | ||
75 | inode->i_op = &simple_dir_inode_operations; | ||
76 | inode->i_fop = &simple_dir_operations; | ||
77 | |||
78 | /* directory inodes start off with i_nlink == 2 (for "." entry) */ | ||
79 | inc_nlink(inode); | ||
80 | break; | ||
81 | } | ||
82 | } | ||
83 | return inode; | ||
84 | } | ||
85 | |||
86 | /* SMP-safe */ | ||
87 | static int mknod(struct inode *dir, struct dentry *dentry, | ||
88 | umode_t mode, dev_t dev) | ||
89 | { | ||
90 | struct inode *inode; | ||
91 | int error = -ENOMEM; | ||
92 | |||
93 | if (dentry->d_inode) | ||
94 | return -EEXIST; | ||
95 | |||
96 | inode = get_inode(dir->i_sb, mode, dev); | ||
97 | if (inode) { | ||
98 | d_instantiate(dentry, inode); | ||
99 | dget(dentry); | ||
100 | error = 0; | ||
101 | } | ||
102 | return error; | ||
103 | } | ||
104 | |||
105 | static int mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) | ||
106 | { | ||
107 | int res; | ||
108 | |||
109 | mode = (mode & (S_IRWXUGO | S_ISVTX)) | S_IFDIR; | ||
110 | res = mknod(dir, dentry, mode, 0); | ||
111 | if (!res) | ||
112 | inc_nlink(dir); | ||
113 | return res; | ||
114 | } | ||
115 | |||
116 | static int create(struct inode *dir, struct dentry *dentry, umode_t mode) | ||
117 | { | ||
118 | mode = (mode & S_IALLUGO) | S_IFREG; | ||
119 | return mknod(dir, dentry, mode, 0); | ||
120 | } | ||
121 | |||
122 | static inline int positive(struct dentry *dentry) | 28 | static inline int positive(struct dentry *dentry) |
123 | { | 29 | { |
124 | return dentry->d_inode && !d_unhashed(dentry); | 30 | return dentry->d_inode && !d_unhashed(dentry); |
@@ -145,38 +51,6 @@ static struct file_system_type fs_type = { | |||
145 | .kill_sb = kill_litter_super, | 51 | .kill_sb = kill_litter_super, |
146 | }; | 52 | }; |
147 | 53 | ||
148 | static int create_by_name(const char *name, umode_t mode, | ||
149 | struct dentry *parent, | ||
150 | struct dentry **dentry) | ||
151 | { | ||
152 | int error = 0; | ||
153 | |||
154 | *dentry = NULL; | ||
155 | |||
156 | /* If the parent is not specified, we create it in the root. | ||
157 | * We need the root dentry to do this, which is in the super | ||
158 | * block. A pointer to that is in the struct vfsmount that we | ||
159 | * have around. | ||
160 | */ | ||
161 | if (!parent) | ||
162 | parent = mount->mnt_root; | ||
163 | |||
164 | mutex_lock(&parent->d_inode->i_mutex); | ||
165 | *dentry = lookup_one_len(name, parent, strlen(name)); | ||
166 | if (!IS_ERR(*dentry)) { | ||
167 | if (S_ISDIR(mode)) | ||
168 | error = mkdir(parent->d_inode, *dentry, mode); | ||
169 | else | ||
170 | error = create(parent->d_inode, *dentry, mode); | ||
171 | if (error) | ||
172 | dput(*dentry); | ||
173 | } else | ||
174 | error = PTR_ERR(*dentry); | ||
175 | mutex_unlock(&parent->d_inode->i_mutex); | ||
176 | |||
177 | return error; | ||
178 | } | ||
179 | |||
180 | /** | 54 | /** |
181 | * securityfs_create_file - create a file in the securityfs filesystem | 55 | * securityfs_create_file - create a file in the securityfs filesystem |
182 | * | 56 | * |
@@ -209,31 +83,66 @@ struct dentry *securityfs_create_file(const char *name, umode_t mode, | |||
209 | struct dentry *parent, void *data, | 83 | struct dentry *parent, void *data, |
210 | const struct file_operations *fops) | 84 | const struct file_operations *fops) |
211 | { | 85 | { |
212 | struct dentry *dentry = NULL; | 86 | struct dentry *dentry; |
87 | int is_dir = S_ISDIR(mode); | ||
88 | struct inode *dir, *inode; | ||
213 | int error; | 89 | int error; |
214 | 90 | ||
91 | if (!is_dir) { | ||
92 | BUG_ON(!fops); | ||
93 | mode = (mode & S_IALLUGO) | S_IFREG; | ||
94 | } | ||
95 | |||
215 | pr_debug("securityfs: creating file '%s'\n",name); | 96 | pr_debug("securityfs: creating file '%s'\n",name); |
216 | 97 | ||
217 | error = simple_pin_fs(&fs_type, &mount, &mount_count); | 98 | error = simple_pin_fs(&fs_type, &mount, &mount_count); |
218 | if (error) { | 99 | if (error) |
219 | dentry = ERR_PTR(error); | 100 | return ERR_PTR(error); |
220 | goto exit; | 101 | |
102 | if (!parent) | ||
103 | parent = mount->mnt_root; | ||
104 | |||
105 | dir = parent->d_inode; | ||
106 | |||
107 | mutex_lock(&dir->i_mutex); | ||
108 | dentry = lookup_one_len(name, parent, strlen(name)); | ||
109 | if (IS_ERR(dentry)) | ||
110 | goto out; | ||
111 | |||
112 | if (dentry->d_inode) { | ||
113 | error = -EEXIST; | ||
114 | goto out1; | ||
221 | } | 115 | } |
222 | 116 | ||
223 | error = create_by_name(name, mode, parent, &dentry); | 117 | inode = new_inode(dir->i_sb); |
224 | if (error) { | 118 | if (!inode) { |
225 | dentry = ERR_PTR(error); | 119 | error = -ENOMEM; |
226 | simple_release_fs(&mount, &mount_count); | 120 | goto out1; |
227 | goto exit; | ||
228 | } | 121 | } |
229 | 122 | ||
230 | if (dentry->d_inode) { | 123 | inode->i_ino = get_next_ino(); |
231 | if (fops) | 124 | inode->i_mode = mode; |
232 | dentry->d_inode->i_fop = fops; | 125 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; |
233 | if (data) | 126 | inode->i_private = data; |
234 | dentry->d_inode->i_private = data; | 127 | if (is_dir) { |
128 | inode->i_op = &simple_dir_inode_operations; | ||
129 | inode->i_fop = &simple_dir_operations; | ||
130 | inc_nlink(inode); | ||
131 | inc_nlink(dir); | ||
132 | } else { | ||
133 | inode->i_fop = fops; | ||
235 | } | 134 | } |
236 | exit: | 135 | d_instantiate(dentry, inode); |
136 | dget(dentry); | ||
137 | mutex_unlock(&dir->i_mutex); | ||
138 | return dentry; | ||
139 | |||
140 | out1: | ||
141 | dput(dentry); | ||
142 | dentry = ERR_PTR(error); | ||
143 | out: | ||
144 | mutex_unlock(&dir->i_mutex); | ||
145 | simple_release_fs(&mount, &mount_count); | ||
237 | return dentry; | 146 | return dentry; |
238 | } | 147 | } |
239 | EXPORT_SYMBOL_GPL(securityfs_create_file); | 148 | EXPORT_SYMBOL_GPL(securityfs_create_file); |