aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-01-11 00:46:36 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2012-01-11 00:46:36 -0500
commit5cd9599bba428762025db6027764f1c59d0b1e1b (patch)
treecb59ea13f6e6de4350ca38338bf9633e89f8418a
parente343a895a9f342f239c5e3c5ffc6c0b1707e6244 (diff)
parentd668dc56631da067540b2494d2a1f29ff7b5f15a (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.h1
-rw-r--r--fs/autofs4/inode.c1
-rw-r--r--fs/autofs4/waitq.c40
-rw-r--r--fs/block_dev.c10
-rw-r--r--fs/coda/cnode.c38
-rw-r--r--fs/coda/coda_fs_i.h4
-rw-r--r--fs/coda/dir.c29
-rw-r--r--fs/coda/inode.c10
-rw-r--r--fs/dcache.c15
-rw-r--r--fs/hfsplus/super.c11
-rw-r--r--include/linux/dcache.h1
-rw-r--r--security/inode.c191
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
59static int autofs4_write(struct file *file, const void *addr, int bytes) 59static 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(&current->pending.signal, SIGPIPE); 67 sigpipe = sigismember(&current->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
184static int autofs4_getpath(struct autofs_sb_info *sbi, 188static 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;
521void __init bdev_cache_init(void) 520void __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*/
91int coda_cnode_make(struct inode **inode, struct CodaFid *fid, struct super_block *sb) 91struct 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 */
159int coda_cnode_makectl(struct inode **inode, struct super_block *sb) 156struct 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
52int coda_cnode_make(struct inode **, struct CodaFid *, struct super_block *); 52struct inode *coda_cnode_make(struct CodaFid *, struct super_block *);
53struct inode *coda_iget(struct super_block *sb, struct CodaFid *fid, struct coda_vattr *attr); 53struct inode *coda_iget(struct super_block *sb, struct CodaFid *fid, struct coda_vattr *attr);
54int coda_cnode_makectl(struct inode **inode, struct super_block *sb); 54struct inode *coda_cnode_makectl(struct super_block *sb);
55struct inode *coda_fid_to_inode(struct CodaFid *fid, struct super_block *sb); 55struct inode *coda_fid_to_inode(struct CodaFid *fid, struct super_block *sb);
56void coda_replace_fid(struct inode *, struct CodaFid *, struct CodaFid *); 56void 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 */
97static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry, struct nameidata *nd) 97static 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
127exit:
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)
243static void __dentry_lru_del(struct dentry *dentry) 243static 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 @@
25static struct vfsmount *mount; 25static struct vfsmount *mount;
26static int mount_count; 26static 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 */
32static ssize_t default_read_file(struct file *file, char __user *buf,
33 size_t count, loff_t *ppos)
34{
35 return 0;
36}
37
38static 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
44static 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
52static 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
59static 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 */
87static 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
105static 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
116static 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
122static inline int positive(struct dentry *dentry) 28static 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
148static 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 }
236exit: 135 d_instantiate(dentry, inode);
136 dget(dentry);
137 mutex_unlock(&dir->i_mutex);
138 return dentry;
139
140out1:
141 dput(dentry);
142 dentry = ERR_PTR(error);
143out:
144 mutex_unlock(&dir->i_mutex);
145 simple_release_fs(&mount, &mount_count);
237 return dentry; 146 return dentry;
238} 147}
239EXPORT_SYMBOL_GPL(securityfs_create_file); 148EXPORT_SYMBOL_GPL(securityfs_create_file);