2 fs/ext3/iopen.c | 239 +++++++++++++++++++++++++++++++++++++
3 fs/ext3/iopen.h | 15 ++
4 fs/ext3/namei.c | 13 ++
5 fs/ext3/super.c | 17 ++
6 include/linux/ext3_fs.h | 2
7 7 files changed, 304 insertions(+), 1 deletion(-)
9 Index: linux-2.6.10/include/linux/ext3_fs.h
10 ===================================================================
11 --- linux-2.6.10.orig/include/linux/ext3_fs.h 2005-04-05 12:25:13.635136112 +0800
12 +++ linux-2.6.10/include/linux/ext3_fs.h 2005-04-05 12:25:13.801110880 +0800
14 #define EXT3_MOUNT_RESERVATION 0x10000 /* Preallocation */
15 #define EXT3_MOUNT_BARRIER 0x20000 /* Use block barriers */
16 #define EXT3_MOUNT_PDIROPS 0x800000/* Parallel dir operations */
17 +#define EXT3_MOUNT_IOPEN 0x40000 /* Allow access via iopen */
18 +#define EXT3_MOUNT_IOPEN_NOPRIV 0x80000 /* Make iopen world-readable */
20 /* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */
21 #ifndef _LINUX_EXT2_FS_H
22 Index: linux-2.6.10/fs/ext3/inode.c
23 ===================================================================
24 --- linux-2.6.10.orig/fs/ext3/inode.c 2005-04-05 12:25:13.726122280 +0800
25 +++ linux-2.6.10/fs/ext3/inode.c 2005-04-05 12:25:13.794111944 +0800
27 #include <linux/mpage.h>
28 #include <linux/uio.h>
36 ei->i_rsv_window.rsv_end = EXT3_RESERVE_WINDOW_NOT_ALLOCATED;
38 + if (ext3_iopen_get_inode(inode))
41 if (ext3_get_inode_loc(inode, &iloc, 0))
44 Index: linux-2.6.10/fs/ext3/super.c
45 ===================================================================
46 --- linux-2.6.10.orig/fs/ext3/super.c 2005-04-05 12:25:13.728121976 +0800
47 +++ linux-2.6.10/fs/ext3/super.c 2005-04-05 12:25:13.797111488 +0800
49 Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback,
50 Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
51 Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_pdirops,
52 + Opt_iopen, Opt_noiopen, Opt_iopen_nopriv,
53 Opt_ignore, Opt_barrier, Opt_err, Opt_resize,
57 {Opt_ignore, "usrquota"},
58 {Opt_barrier, "barrier=%u"},
59 {Opt_pdirops, "pdirops"},
60 + {Opt_iopen, "iopen"},
61 + {Opt_noiopen, "noiopen"},
62 + {Opt_iopen_nopriv, "iopen_nopriv"},
64 {Opt_resize, "resize"},
68 clear_opt(sbi->s_mount_opt, BARRIER);
71 + set_opt (sbi->s_mount_opt, IOPEN);
72 + clear_opt (sbi->s_mount_opt, IOPEN_NOPRIV);
75 + clear_opt (sbi->s_mount_opt, IOPEN);
76 + clear_opt (sbi->s_mount_opt, IOPEN_NOPRIV);
78 + case Opt_iopen_nopriv:
79 + set_opt (sbi->s_mount_opt, IOPEN);
80 + set_opt (sbi->s_mount_opt, IOPEN_NOPRIV);
85 Index: linux-2.6.10/fs/ext3/iopen.c
86 ===================================================================
87 --- linux-2.6.10.orig/fs/ext3/iopen.c 2005-04-05 19:01:49.158500672 +0800
88 +++ linux-2.6.10/fs/ext3/iopen.c 2005-04-05 12:25:13.791112400 +0800
91 + * linux/fs/ext3/iopen.c
93 + * Special support for open by inode number
95 + * Copyright (C) 2001 by Theodore Ts'o (tytso@alum.mit.edu).
97 + * This file may be redistributed under the terms of the GNU General
102 + * - there is only ever a single DCACHE_NFSD_DISCONNECTED dentry alias
103 + * for an inode at one time.
104 + * - there are never both connected and DCACHE_NFSD_DISCONNECTED dentry
105 + * aliases on an inode at the same time.
107 + * If we have any connected dentry aliases for an inode, use one of those
108 + * in iopen_lookup(). Otherwise, we instantiate a single NFSD_DISCONNECTED
109 + * dentry for this inode, which thereafter will be found by the dcache
110 + * when looking up this inode number in __iopen__, so we don't return here
111 + * until it is gone.
113 + * If we get an inode via a regular name lookup, then we "rename" the
114 + * NFSD_DISCONNECTED dentry to the proper name and parent. This ensures
115 + * existing users of the disconnected dentry will continue to use the same
116 + * dentry as the connected users, and there will never be both kinds of
117 + * dentry aliases at one time.
120 +#include <linux/sched.h>
121 +#include <linux/fs.h>
122 +#include <linux/ext3_jbd.h>
123 +#include <linux/jbd.h>
124 +#include <linux/ext3_fs.h>
125 +#include <linux/smp_lock.h>
126 +#include <linux/dcache.h>
127 +#include <linux/security.h>
131 +#define assert(test) J_ASSERT(test)
134 +#define IOPEN_NAME_LEN 32
137 + * This implements looking up an inode by number.
139 +static struct dentry *iopen_lookup(struct inode * dir, struct dentry *dentry,
140 + struct nameidata *nd)
142 + struct inode *inode;
144 + struct list_head *lp;
145 + struct dentry *alternate;
146 + char buf[IOPEN_NAME_LEN];
148 + if (dentry->d_name.len >= IOPEN_NAME_LEN)
149 + return ERR_PTR(-ENAMETOOLONG);
151 + memcpy(buf, dentry->d_name.name, dentry->d_name.len);
152 + buf[dentry->d_name.len] = 0;
154 + if (strcmp(buf, ".") == 0)
156 + else if (strcmp(buf, "..") == 0)
157 + ino = EXT3_ROOT_INO;
159 + ino = simple_strtoul(buf, 0, 0);
161 + if ((ino != EXT3_ROOT_INO &&
162 + //ino != EXT3_ACL_IDX_INO &&
163 + //ino != EXT3_ACL_DATA_INO &&
164 + ino < EXT3_FIRST_INO(dir->i_sb)) ||
165 + ino > le32_to_cpu(EXT3_SB(dir->i_sb)->s_es->s_inodes_count))
166 + return ERR_PTR(-ENOENT);
168 + inode = iget(dir->i_sb, ino);
170 + return ERR_PTR(-EACCES);
171 + if (is_bad_inode(inode)) {
173 + return ERR_PTR(-ENOENT);
176 + assert(list_empty(&dentry->d_alias)); /* d_instantiate */
177 + assert(d_unhashed(dentry)); /* d_rehash */
179 + /* preferrably return a connected dentry */
180 + spin_lock(&dcache_lock);
181 + list_for_each(lp, &inode->i_dentry) {
182 + alternate = list_entry(lp, struct dentry, d_alias);
183 + assert(!(alternate->d_flags & DCACHE_DISCONNECTED));
186 + if (!list_empty(&inode->i_dentry)) {
187 + alternate = list_entry(inode->i_dentry.next,
188 + struct dentry, d_alias);
189 + dget_locked(alternate);
190 + spin_lock(&alternate->d_lock);
191 + alternate->d_flags |= DCACHE_REFERENCED;
192 + spin_unlock(&alternate->d_lock);
194 + spin_unlock(&dcache_lock);
197 + dentry->d_flags |= DCACHE_DISCONNECTED;
199 + /* d_add(), but don't drop dcache_lock before adding dentry to inode */
200 + list_add(&dentry->d_alias, &inode->i_dentry); /* d_instantiate */
201 + dentry->d_inode = inode;
203 + __d_rehash(dentry); /* d_rehash */
204 + spin_unlock(&dcache_lock);
209 +#define do_switch(x,y) do { \
210 + __typeof__ (x) __tmp = x; \
211 + x = y; y = __tmp; } while (0)
213 +static inline void switch_names(struct dentry *dentry, struct dentry *target)
215 + const unsigned char *old_name, *new_name;
217 + memcpy(dentry->d_iname, target->d_iname, DNAME_INLINE_LEN_MIN);
218 + old_name = target->d_name.name;
219 + new_name = dentry->d_name.name;
220 + if (old_name == target->d_iname)
221 + old_name = dentry->d_iname;
222 + if (new_name == dentry->d_iname)
223 + new_name = target->d_iname;
224 + target->d_name.name = new_name;
225 + dentry->d_name.name = old_name;
228 +/* This function is spliced into ext3_lookup and does the move of a
229 + * disconnected dentry (if it exists) to a connected dentry.
231 +struct dentry *iopen_connect_dentry(struct dentry *dentry, struct inode *inode,
234 + struct dentry *tmp, *goal = NULL;
235 + struct list_head *lp;
237 + /* verify this dentry is really new */
238 + assert(dentry->d_inode == NULL);
239 + assert(list_empty(&dentry->d_alias)); /* d_instantiate */
241 + assert(d_unhashed(dentry)); /* d_rehash */
242 + assert(list_empty(&dentry->d_subdirs));
244 + spin_lock(&dcache_lock);
248 + /* preferrably return a connected dentry */
249 + list_for_each(lp, &inode->i_dentry) {
250 + tmp = list_entry(lp, struct dentry, d_alias);
251 + if (tmp->d_flags & DCACHE_DISCONNECTED) {
252 + assert(tmp->d_alias.next == &inode->i_dentry);
253 + assert(tmp->d_alias.prev == &inode->i_dentry);
261 + goto do_instantiate;
263 + /* Move the goal to the de hash queue */
264 + goal->d_flags &= ~ DCACHE_DISCONNECTED;
265 + security_d_instantiate(goal, inode);
266 + __d_rehash(dentry);
267 + __d_move(goal, dentry);
268 + spin_unlock(&dcache_lock);
273 + /* d_add(), but don't drop dcache_lock before adding dentry to inode */
275 + list_add(&dentry->d_alias, &inode->i_dentry); /* d_instantiate */
276 + dentry->d_inode = inode;
279 + __d_rehash(dentry); /* d_rehash */
280 + spin_unlock(&dcache_lock);
286 + * These are the special structures for the iopen pseudo directory.
289 +static struct inode_operations iopen_inode_operations = {
290 + lookup: iopen_lookup, /* BKL held */
293 +static struct file_operations iopen_file_operations = {
294 + read: generic_read_dir,
297 +static int match_dentry(struct dentry *dentry, const char *name)
301 + len = strlen(name);
302 + if (dentry->d_name.len != len)
304 + if (strncmp(dentry->d_name.name, name, len))
310 + * This function is spliced into ext3_lookup and returns 1 the file
311 + * name is __iopen__ and dentry has been filled in appropriately.
313 +int ext3_check_for_iopen(struct inode *dir, struct dentry *dentry)
315 + struct inode *inode;
317 + if (dir->i_ino != EXT3_ROOT_INO ||
318 + !test_opt(dir->i_sb, IOPEN) ||
319 + !match_dentry(dentry, "__iopen__"))
322 + inode = iget(dir->i_sb, EXT3_BAD_INO);
326 + d_add(dentry, inode);
331 + * This function is spliced into read_inode; it returns 1 if inode
332 + * number is the one for /__iopen__, in which case the inode is filled
333 + * in appropriately. Otherwise, this fuction returns 0.
335 +int ext3_iopen_get_inode(struct inode *inode)
337 + if (inode->i_ino != EXT3_BAD_INO)
340 + inode->i_mode = S_IFDIR | S_IRUSR | S_IXUSR;
341 + if (test_opt(inode->i_sb, IOPEN_NOPRIV))
342 + inode->i_mode |= 0777;
345 + inode->i_nlink = 1;
346 + inode->i_size = 4096;
347 + inode->i_atime = CURRENT_TIME;
348 + inode->i_ctime = CURRENT_TIME;
349 + inode->i_mtime = CURRENT_TIME;
350 + EXT3_I(inode)->i_dtime = 0;
351 + inode->i_blksize = PAGE_SIZE; /* This is the optimal IO size
352 + * (for stat), not the fs block
354 + inode->i_blocks = 0;
355 + inode->i_version = 1;
356 + inode->i_generation = 0;
358 + inode->i_op = &iopen_inode_operations;
359 + inode->i_fop = &iopen_file_operations;
360 + inode->i_mapping->a_ops = 0;
364 Index: linux-2.6.10/fs/ext3/iopen.h
365 ===================================================================
366 --- linux-2.6.10.orig/fs/ext3/iopen.h 2005-04-05 19:01:49.158500672 +0800
367 +++ linux-2.6.10/fs/ext3/iopen.h 2005-04-05 12:25:13.792112248 +0800
372 + * Special support for opening files by inode number.
374 + * Copyright (C) 2001 by Theodore Ts'o (tytso@alum.mit.edu).
376 + * This file may be redistributed under the terms of the GNU General
380 +extern int ext3_check_for_iopen(struct inode *dir, struct dentry *dentry);
381 +extern int ext3_iopen_get_inode(struct inode *inode);
382 +extern struct dentry *iopen_connect_dentry(struct dentry *dentry,
383 + struct inode *inode, int rehash);
384 Index: linux-2.6.10/fs/ext3/Makefile
385 ===================================================================
386 --- linux-2.6.10.orig/fs/ext3/Makefile 2004-12-25 05:33:52.000000000 +0800
387 +++ linux-2.6.10/fs/ext3/Makefile 2005-04-05 12:26:06.897039072 +0800
389 obj-$(CONFIG_EXT3_FS) += ext3.o
391 ext3-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \
392 - ioctl.o namei.o super.o symlink.o hash.o resize.o
393 + ioctl.o namei.o super.o symlink.o hash.o resize.o iopen.o
395 ext3-$(CONFIG_EXT3_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o
396 ext3-$(CONFIG_EXT3_FS_POSIX_ACL) += acl.o
397 Index: linux-2.6.10/fs/ext3/namei.c
398 ===================================================================
399 --- linux-2.6.10.orig/fs/ext3/namei.c 2005-04-05 12:25:13.633136416 +0800
400 +++ linux-2.6.10/fs/ext3/namei.c 2005-04-05 12:25:13.799111184 +0800
402 #include <linux/buffer_head.h>
403 #include <linux/smp_lock.h>
409 @@ -1140,6 +1141,9 @@
410 if (dentry->d_name.len > EXT3_NAME_LEN)
411 return ERR_PTR(-ENAMETOOLONG);
413 + if (ext3_check_for_iopen(dir, dentry))
416 bh = ext3_find_entry(dentry, &de, 0, &lock);
419 @@ -1151,10 +1155,8 @@
421 return ERR_PTR(-EACCES);
424 - return d_splice_alias(inode, dentry);
425 - d_add(dentry, inode);
428 + return iopen_connect_dentry(dentry, inode, 1);
432 @@ -2367,10 +2369,6 @@
436 - /* There's no need to set i_disksize: the fact that i_nlink is
437 - * zero will ensure that the right thing happens during any
440 ext3_orphan_add(handle, inode);
441 inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
442 ext3_mark_inode_dirty(handle, inode);
443 @@ -2497,6 +2495,23 @@
447 +/* Like ext3_add_nondir() except for call to iopen_connect_dentry */
448 +static int ext3_add_link(handle_t *handle, struct dentry *dentry,
449 + struct inode *inode)
451 + int err = ext3_add_entry(handle, dentry, inode);
453 + err = ext3_mark_inode_dirty(handle, inode);
455 + dput(iopen_connect_dentry(dentry, inode, 0));
459 + ext3_dec_count(handle, inode);
464 static int ext3_link (struct dentry * old_dentry,
465 struct inode * dir, struct dentry *dentry)
467 @@ -2520,7 +2535,8 @@
468 ext3_inc_count(handle, inode);
469 atomic_inc(&inode->i_count);
471 - err = ext3_add_nondir(handle, dentry, inode);
472 + err = ext3_add_link(handle, dentry, inode);
473 + ext3_orphan_del(handle,inode);
474 ext3_journal_stop(handle);
475 if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries))