- mds_reint_create() should take same inode create lock (2926)
- correct journal credits calculated for CANCEL_UNLINK_LOG (2931)
- don't close files for self_export to avoid uninitialized obd (2936)
- - let lustre could be mounted with the same name for node and mds (2939)
-
+ - allow MDS with the same name as client node (2939)
+ - hold dentry reference for closed log files for unlink (2325)
+ - reserve space for all logs during transactions (2059)
+ - don't evict page beyond end of stripe extent (2925)
+ - don't oops on a deleted current working directory (2399)
+ - handle hard links to targets without a parent properly (2517)
+
2004-03-04 Cluster File Systems, Inc. <info@clusterfs.com>
* version 1.2.0
* bug fixes
#ifdef __KERNEL__
#include <linux/obd.h>
+#include <linux/obd_class.h>
typedef void (*fsfilt_cb_t)(struct obd_device *obd, __u64 last_rcvd,
void *data, int error);
struct list_head fs_list;
struct module *fs_owner;
char *fs_type;
- void *(* fs_start)(struct inode *inode, int op, void *desc_private);
+ void *(* fs_start)(struct inode *inode, int op, void *desc_private,
+ int logs);
void *(* fs_brw_start)(int objcount, struct fsfilt_objinfo *fso,
int niocount, struct niobuf_local *nb,
- void *desc_private);
+ void *desc_private, int logs);
int (* fs_commit)(struct inode *inode, void *handle,int force_sync);
int (* fs_commit_async)(struct inode *inode, void *handle,
void **wait_handle);
int force_sync);
int (* fs_read_record)(struct file *, void *, int size, loff_t *);
int (* fs_setup)(struct super_block *sb);
+ int (* fs_get_op_len)(int, struct fsfilt_objinfo *, int);
};
extern int fsfilt_register_ops(struct fsfilt_operations *fs_ops);
#define FSFILT_OP_MKNOD 7
#define FSFILT_OP_SETATTR 8
#define FSFILT_OP_LINK 9
-#define FSFILT_OP_CREATE_LOG 10
-#define FSFILT_OP_UNLINK_LOG 11
-#define FSFILT_OP_CANCEL_UNLINK_LOG 12
+#define FSFILT_OP_CANCEL_UNLINK 10
-static inline void *fsfilt_start(struct obd_device *obd, struct inode *inode,
- int op, struct obd_trans_info *oti)
+static inline void *fsfilt_start_log(struct obd_device *obd,
+ struct inode *inode, int op,
+ struct obd_trans_info *oti, int logs)
{
unsigned long now = jiffies;
void *parent_handle = oti ? oti->oti_handle : NULL;
- void *handle = obd->obd_fsops->fs_start(inode, op, parent_handle);
- CDEBUG(D_INFO, "started handle %p (%p)\n", handle, parent_handle);
+ void *handle = obd->obd_fsops->fs_start(inode, op, parent_handle, logs);
+ CDEBUG(D_HA, "started handle %p (%p)\n", handle, parent_handle);
if (oti != NULL) {
if (parent_handle == NULL) {
oti->oti_handle = handle;
} else if (handle != parent_handle) {
CERROR("mismatch: parent %p, handle %p, oti %p\n",
- parent_handle, handle, oti->oti_handle);
+ parent_handle, handle, oti);
LBUG();
}
}
return handle;
}
-static inline void *fsfilt_brw_start(struct obd_device *obd, int objcount,
- struct fsfilt_objinfo *fso, int niocount,
- struct niobuf_local *nb,
- struct obd_trans_info *oti)
+static inline void *fsfilt_start(struct obd_device *obd, struct inode *inode,
+ int op, struct obd_trans_info *oti)
+{
+ return fsfilt_start_log(obd, inode, op, oti, 0);
+}
+
+static inline void *fsfilt_brw_start_log(struct obd_device *obd,
+ int objcount,
+ struct fsfilt_objinfo *fso,
+ int niocount, struct niobuf_local *nb,
+ struct obd_trans_info *oti, int logs)
{
unsigned long now = jiffies;
void *parent_handle = oti ? oti->oti_handle : NULL;
- void *handle;
-
- handle = obd->obd_fsops->fs_brw_start(objcount, fso, niocount, nb,
- parent_handle);
+ void *handle = obd->obd_fsops->fs_brw_start(objcount, fso, niocount, nb,
+ parent_handle, logs);
CDEBUG(D_HA, "started handle %p (%p)\n", handle, parent_handle);
if (oti != NULL) {
oti->oti_handle = handle;
} else if (handle != parent_handle) {
CERROR("mismatch: parent %p, handle %p, oti %p\n",
- parent_handle, handle, oti->oti_handle);
+ parent_handle, handle, oti);
LBUG();
}
}
if (time_after(jiffies, now + 15 * HZ))
CERROR("long journal start time %lus\n", (jiffies - now) / HZ);
+
return handle;
}
+static inline void *fsfilt_brw_start(struct obd_device *obd, int objcount,
+ struct fsfilt_objinfo *fso, int niocount,
+ struct niobuf_local *nb,
+ struct obd_trans_info *oti)
+{
+ return fsfilt_brw_start_log(obd, objcount, fso, niocount, nb, oti, 0);
+}
+
static inline int fsfilt_commit(struct obd_device *obd, struct inode *inode,
void *handle, int force_sync)
{
unsigned long now = jiffies;
int rc = obd->obd_fsops->fs_commit(inode, handle, force_sync);
- CDEBUG(D_INFO, "committing handle %p\n", handle);
+ CDEBUG(D_HA, "committing handle %p\n", handle);
+
if (time_after(jiffies, now + 15 * HZ))
CERROR("long journal start time %lus\n", (jiffies - now) / HZ);
+
return rc;
}
static inline int fsfilt_commit_async(struct obd_device *obd,
- struct inode *inode,
- void *handle,
- void **wait_handle)
+ struct inode *inode, void *handle,
+ void **wait_handle)
{
unsigned long now = jiffies;
int rc = obd->obd_fsops->fs_commit_async(inode, handle, wait_handle);
+
CDEBUG(D_HA, "committing handle %p (async)\n", *wait_handle);
if (time_after(jiffies, now + 15 * HZ))
CERROR("long journal start time %lus\n", (jiffies - now) / HZ);
+
return rc;
}
-static inline int fsfilt_commit_wait(struct obd_device *obd, struct inode *inode,
- void *handle)
+static inline int fsfilt_commit_wait(struct obd_device *obd,
+ struct inode *inode, void *handle)
{
unsigned long now = jiffies;
int rc = obd->obd_fsops->fs_commit_wait(inode, handle);
void *handle, fsfilt_cb_t cb_func,
void *cb_data)
{
- return obd->obd_fsops->fs_add_journal_cb(obd, last_rcvd, handle,
- cb_func, cb_data);
+ return obd->obd_fsops->fs_add_journal_cb(obd, last_rcvd,
+ handle, cb_func, cb_data);
}
/* very similar to obd_statfs(), but caller already holds obd_osfs_lock */
__u64 obd_last_committed;
struct fsfilt_operations *obd_fsops;
spinlock_t obd_osfs_lock;
- struct llog_ctxt *obd_llog_ctxt[LLOG_MAX_CTXTS];
struct obd_statfs obd_osfs;
unsigned long obd_osfs_age;
struct obd_run_ctxt obd_ctxt;
+ struct llog_ctxt *obd_llog_ctxt[LLOG_MAX_CTXTS];
struct obd_device *obd_observer;
struct obd_export *obd_self_export;
--- /dev/null
+--- ./fs/dcache.c.orig 2004-01-30 14:54:45.000000000 -0700
++++ ./fs/dcache.c 2004-02-20 14:49:18.000000000 -0700
+@@ -348,8 +348,20 @@
+ dentry_stat.nr_unused--;
+
+ /* Unused dentry with a count? */
+- if (atomic_read(&dentry->d_count))
++ if (atomic_read(&dentry->d_count)) {
++ struct inode *inode = dentry->d_inode;
++ printk(KERN_CRIT "dentry %*s %p->%lu/%u(%p/%s) ct %d\n",
++ dentry->d_name.len, dentry->d_name.name, dentry,
++ inode ? inode->i_ino : 0,
++ inode ? inode->i_generation : 0, inode,
++ inode ? inode->i_sb ?
++ inode->i_sb->s_type->name : "" : "",
++ atomic_read(&dentry->d_count));
++ spin_unlock(&dcache_lock);
++ set_task_state(current, TASK_UNINTERRUPTIBLE);
++ schedule();
+ BUG();
++ }
+
+ prune_one_dentry(dentry);
+ if (!--count)
--- /dev/null
+ fs/ext3/ialloc.c | 3
+ fs/ext3/inode.c | 3
+ fs/ext3/namei.c | 582 +++++++++++++++++++++++++++++++++++++---------
+ fs/ext3/super.c | 14 +
+ include/linux/ext3_fs.h | 1
+ include/linux/ext3_fs_i.h | 6
+ 6 files changed, 500 insertions(+), 109 deletions(-)
+
+Index: linux-2.4.20/fs/ext3/namei.c
+===================================================================
+--- linux-2.4.20.orig/fs/ext3/namei.c Wed Mar 17 15:37:09 2004
++++ linux-2.4.20/fs/ext3/namei.c Wed Mar 17 15:37:56 2004
+@@ -51,6 +51,9 @@
+ {
+ struct buffer_head *bh;
+
++ /* with parallel dir operations all appends
++ * have to be serialized -bzzz */
++ down(&EXT3_I(inode)->i_append_sem);
+ *block = inode->i_size >> inode->i_sb->s_blocksize_bits;
+
+ if ((bh = ext3_bread(handle, inode, *block, 1, err))) {
+@@ -58,6 +61,8 @@
+ EXT3_I(inode)->i_disksize = inode->i_size;
+ ext3_journal_get_write_access(handle,bh);
+ }
++ up(&EXT3_I(inode)->i_append_sem);
++
+ return bh;
+ }
+
+@@ -134,6 +139,8 @@
+ struct buffer_head *bh;
+ struct dx_entry *entries;
+ struct dx_entry *at;
++ unsigned long leaf;
++ unsigned int curidx;
+ };
+
+ struct dx_map_entry
+@@ -142,6 +149,30 @@
+ u32 offs;
+ };
+
++/* FIXME: this should be reworked using bb_spin_lock
++ * introduced in -mm tree
++ */
++#define BH_DXLock 25
++
++static inline void dx_lock_bh(struct buffer_head volatile *bh)
++{
++#ifdef CONFIG_SMP
++ while (test_and_set_bit(BH_DXLock, &bh->b_state)) {
++ while (test_bit(BH_DXLock, &bh->b_state))
++ cpu_relax();
++ }
++#endif
++}
++
++static inline void dx_unlock_bh(struct buffer_head *bh)
++{
++#ifdef CONFIG_SMP
++ smp_mb__before_clear_bit();
++ clear_bit(BH_DXLock, &bh->b_state);
++#endif
++}
++
++
+ #ifdef CONFIG_EXT3_INDEX
+ static inline unsigned dx_get_block (struct dx_entry *entry);
+ static void dx_set_block (struct dx_entry *entry, unsigned value);
+@@ -153,7 +184,7 @@
+ static void dx_set_limit (struct dx_entry *entries, unsigned value);
+ static unsigned dx_root_limit (struct inode *dir, unsigned infosize);
+ static unsigned dx_node_limit (struct inode *dir);
+-static struct dx_frame *dx_probe(struct dentry *dentry,
++static struct dx_frame *dx_probe(struct qstr *name,
+ struct inode *dir,
+ struct dx_hash_info *hinfo,
+ struct dx_frame *frame,
+@@ -165,15 +196,18 @@
+ static struct ext3_dir_entry_2 *dx_move_dirents (char *from, char *to,
+ struct dx_map_entry *offsets, int count);
+ static struct ext3_dir_entry_2* dx_pack_dirents (char *base, int size);
+-static void dx_insert_block (struct dx_frame *frame, u32 hash, u32 block);
++static void dx_insert_block (struct inode *, struct dx_frame *, u32, u32, u32);
+ static int ext3_htree_next_block(struct inode *dir, __u32 hash,
+ struct dx_frame *frame,
+ struct dx_frame *frames, int *err,
+ __u32 *start_hash);
+ static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry,
+- struct ext3_dir_entry_2 **res_dir, int *err);
++ struct ext3_dir_entry_2 **res_dir, int *err,
++ int rwlock, void **lock);
+ static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry,
+ struct inode *inode);
++static inline void *ext3_lock_htree(struct inode *, unsigned long, int);
++static inline void ext3_unlock_htree(struct inode *, void *);
+
+ /*
+ * Future: use high four bits of block for coalesce-on-delete flags
+@@ -306,6 +340,94 @@
+ #endif /* DX_DEBUG */
+
+ /*
++ * dx_find_position
++ *
++ * search position of specified hash in index
++ *
++ */
++
++struct dx_entry * dx_find_position(struct dx_entry * entries, u32 hash)
++{
++ struct dx_entry *p, *q, *m;
++ int count;
++
++ count = dx_get_count(entries);
++ p = entries + 1;
++ q = entries + count - 1;
++ while (p <= q)
++ {
++ m = p + (q - p)/2;
++ if (dx_get_hash(m) > hash)
++ q = m - 1;
++ else
++ p = m + 1;
++ }
++ return p - 1;
++}
++
++/*
++ * returns 1 if path is unchanged
++ */
++int dx_check_path(struct dx_frame *frame, u32 hash)
++{
++ struct dx_entry *p;
++ int ret = 1;
++
++ dx_lock_bh(frame->bh);
++ p = dx_find_position(frame->entries, hash);
++ if (frame->leaf != dx_get_block(p))
++ ret = 0;
++ dx_unlock_bh(frame->bh);
++
++ return ret;
++}
++
++/*
++ * 0 - changed
++ * 1 - hasn't changed
++ */
++static int
++dx_check_full_path(struct dx_frame *frames, struct dx_hash_info *hinfo)
++{
++ struct dx_entry *p;
++ struct dx_frame *frame = frames;
++ u32 leaf;
++
++ /* check first level */
++ dx_lock_bh(frame->bh);
++ p = dx_find_position(frame->entries, hinfo->hash);
++ leaf = dx_get_block(p);
++ dx_unlock_bh(frame->bh);
++
++ if (leaf != frame->leaf)
++ return 0;
++
++ /* is there 2nd level? */
++ frame++;
++ if (frame->bh == NULL)
++ return 1;
++
++ /* check second level */
++ dx_lock_bh(frame->bh);
++
++ /* probably 1st level got changed, check it */
++ if (!dx_check_path(frames, hinfo->hash)) {
++ /* path changed */
++ dx_unlock_bh(frame->bh);
++ return 0;
++ }
++
++ p = dx_find_position(frame->entries, hinfo->hash);
++ leaf = dx_get_block(p);
++ dx_unlock_bh(frame->bh);
++
++ if (leaf != frame->leaf)
++ return 0;
++
++ return 1;
++}
++
++/*
+ * Probe for a directory leaf block to search.
+ *
+ * dx_probe can return ERR_BAD_DX_DIR, which means there was a format
+@@ -315,19 +437,20 @@
+ * back to userspace.
+ */
+ static struct dx_frame *
+-dx_probe(struct dentry *dentry, struct inode *dir,
++dx_probe(struct qstr *name, struct inode *dir,
+ struct dx_hash_info *hinfo, struct dx_frame *frame_in, int *err)
+ {
+- unsigned count, indirect;
+- struct dx_entry *at, *entries, *p, *q, *m;
++ unsigned indirect;
++ struct dx_entry *at, *entries;
+ struct dx_root *root;
+ struct buffer_head *bh;
+ struct dx_frame *frame = frame_in;
+ u32 hash;
++ unsigned int curidx;
+
+ frame->bh = NULL;
+- if (dentry)
+- dir = dentry->d_parent->d_inode;
++ frame[1].bh = NULL;
++
+ if (!(bh = ext3_bread (NULL,dir, 0, 0, err)))
+ goto fail;
+ root = (struct dx_root *) bh->b_data;
+@@ -343,8 +466,8 @@
+ }
+ hinfo->hash_version = root->info.hash_version;
+ hinfo->seed = dir->i_sb->u.ext3_sb.s_hash_seed;
+- if (dentry)
+- ext3fs_dirhash(dentry->d_name.name, dentry->d_name.len, hinfo);
++ if (name)
++ ext3fs_dirhash(name->name, name->len, hinfo);
+ hash = hinfo->hash;
+
+ if (root->info.unused_flags & 1) {
+@@ -356,7 +479,19 @@
+ goto fail;
+ }
+
++repeat:
++ curidx = 0;
++ entries = (struct dx_entry *) (((char *)&root->info) +
++ root->info.info_length);
++ assert(dx_get_limit(entries) == dx_root_limit(dir,
++ root->info.info_length));
++ dxtrace (printk("Look up %x", hash));
++ dx_lock_bh(bh);
++ /* indirect must be initialized under bh lock because
++ * 2nd level creation procedure may change it and dx_probe()
++ * will suggest htree is still single-level -bzzz */
+ if ((indirect = root->info.indirect_levels) > 1) {
++ dx_unlock_bh(bh);
+ ext3_warning(dir->i_sb, __FUNCTION__,
+ "Unimplemented inode hash depth: %#06x",
+ root->info.indirect_levels);
+@@ -364,56 +499,46 @@
+ *err = ERR_BAD_DX_DIR;
+ goto fail;
+ }
+-
+- entries = (struct dx_entry *) (((char *)&root->info) +
+- root->info.info_length);
+- assert(dx_get_limit(entries) == dx_root_limit(dir,
+- root->info.info_length));
+- dxtrace (printk("Look up %x", hash));
++
+ while (1)
+ {
+- count = dx_get_count(entries);
+- assert (count && count <= dx_get_limit(entries));
+- p = entries + 1;
+- q = entries + count - 1;
+- while (p <= q)
+- {
+- m = p + (q - p)/2;
+- dxtrace(printk("."));
+- if (dx_get_hash(m) > hash)
+- q = m - 1;
+- else
+- p = m + 1;
+- }
+-
+- if (0) // linear search cross check
+- {
+- unsigned n = count - 1;
+- at = entries;
+- while (n--)
+- {
+- dxtrace(printk(","));
+- if (dx_get_hash(++at) > hash)
+- {
+- at--;
+- break;
+- }
+- }
+- assert (at == p - 1);
+- }
+-
+- at = p - 1;
+- dxtrace(printk(" %x->%u\n", at == entries? 0: dx_get_hash(at), dx_get_block(at)));
++ at = dx_find_position(entries, hinfo->hash);
++ dxtrace(printk(" %x->%u\n",
++ at == entries? 0: dx_get_hash(at),
++ dx_get_block(at)));
+ frame->bh = bh;
+ frame->entries = entries;
+ frame->at = at;
+- if (!indirect--) return frame;
+- if (!(bh = ext3_bread (NULL,dir, dx_get_block(at), 0, err)))
++ frame->curidx = curidx;
++ frame->leaf = dx_get_block(at);
++ if (!indirect--) {
++ dx_unlock_bh(bh);
++ return frame;
++ }
++
++ /* step into next htree level */
++ curidx = dx_get_block(at);
++ dx_unlock_bh(bh);
++ if (!(bh = ext3_bread (NULL,dir, frame->leaf, 0, err)))
+ goto fail2;
++
++ dx_lock_bh(bh);
++ /* splitting may change root index block and move
++ * hash we're looking for into another index block
++ * so, we have to check this situation and repeat
++ * from begining if path got changed -bzzz */
++ if (!dx_check_path(frame, hash)) {
++ dx_unlock_bh(bh);
++ bh = frame->bh;
++ indirect++;
++ goto repeat;
++ }
++
+ at = entries = ((struct dx_node *) bh->b_data)->entries;
+ assert (dx_get_limit(entries) == dx_node_limit (dir));
+ frame++;
+ }
++ dx_unlock_bh(bh);
+ fail2:
+ while (frame >= frame_in) {
+ brelse(frame->bh);
+@@ -427,8 +552,7 @@
+ {
+ if (frames[0].bh == NULL)
+ return;
+-
+- if (((struct dx_root *) frames[0].bh->b_data)->info.indirect_levels)
++ if (frames[1].bh != NULL)
+ brelse(frames[1].bh);
+ brelse(frames[0].bh);
+ }
+@@ -470,8 +594,10 @@
+ * nodes need to be read.
+ */
+ while (1) {
+- if (++(p->at) < p->entries + dx_get_count(p->entries))
++ if (++(p->at) < p->entries + dx_get_count(p->entries)) {
++ p->leaf = dx_get_block(p->at);
+ break;
++ }
+ if (p == frames)
+ return 0;
+ num_frames++;
+@@ -497,13 +623,17 @@
+ * block so no check is necessary
+ */
+ while (num_frames--) {
+- if (!(bh = ext3_bread(NULL, dir, dx_get_block(p->at),
+- 0, err)))
++ u32 idx;
++
++ idx = p->leaf = dx_get_block(p->at);
++ if (!(bh = ext3_bread(NULL, dir, idx, 0, err)))
+ return -1; /* Failure */
+ p++;
+ brelse (p->bh);
+ p->bh = bh;
+ p->at = p->entries = ((struct dx_node *) bh->b_data)->entries;
++ p->curidx = idx;
++ p->leaf = dx_get_block(p->at);
+ }
+ return 1;
+ }
+@@ -543,7 +673,7 @@
+ dir = dir_file->f_dentry->d_inode;
+ hinfo.hash = start_hash;
+ hinfo.minor_hash = 0;
+- frame = dx_probe(0, dir_file->f_dentry->d_inode, &hinfo, frames, &err);
++ frame = dx_probe(NULL, dir_file->f_dentry->d_inode, &hinfo, frames, &err);
+ if (!frame)
+ return err;
+
+@@ -625,7 +755,8 @@
+ count++;
+ }
+ /* XXX: do we need to check rec_len == 0 case? -Chris */
+- de = (struct ext3_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
++ de = (struct ext3_dir_entry_2 *)((char*)de +
++ le16_to_cpu(de->rec_len));
+ }
+ return count;
+ }
+@@ -658,7 +789,8 @@
+ } while(more);
+ }
+
+-static void dx_insert_block(struct dx_frame *frame, u32 hash, u32 block)
++static void dx_insert_block(struct inode *dir, struct dx_frame *frame,
++ u32 hash, u32 block, u32 idx)
+ {
+ struct dx_entry *entries = frame->entries;
+ struct dx_entry *old = frame->at, *new = old + 1;
+@@ -670,6 +802,7 @@
+ dx_set_hash(new, hash);
+ dx_set_block(new, block);
+ dx_set_count(entries, count + 1);
++
+ }
+ #endif
+
+@@ -752,7 +885,8 @@
+
+
+ static struct buffer_head * ext3_find_entry (struct dentry *dentry,
+- struct ext3_dir_entry_2 ** res_dir)
++ struct ext3_dir_entry_2 ** res_dir,
++ int rwlock, void **lock)
+ {
+ struct super_block * sb;
+ struct buffer_head * bh_use[NAMEI_RA_SIZE];
+@@ -768,6 +902,7 @@
+ int namelen;
+ const u8 *name;
+ unsigned blocksize;
++ int do_not_use_dx = 0;
+
+ *res_dir = NULL;
+ sb = dir->i_sb;
+@@ -776,9 +911,10 @@
+ name = dentry->d_name.name;
+ if (namelen > EXT3_NAME_LEN)
+ return NULL;
++repeat:
+ #ifdef CONFIG_EXT3_INDEX
+ if (is_dx(dir)) {
+- bh = ext3_dx_find_entry(dentry, res_dir, &err);
++ bh = ext3_dx_find_entry(dentry, res_dir, &err, rwlock, lock);
+ /*
+ * On success, or if the error was file not found,
+ * return. Otherwise, fall back to doing a search the
+@@ -787,8 +923,14 @@
+ if (bh || (err != ERR_BAD_DX_DIR))
+ return bh;
+ dxtrace(printk("ext3_find_entry: dx failed, falling back\n"));
++ do_not_use_dx = 1;
+ }
+ #endif
++ *lock = ext3_lock_htree(dir, 0, rwlock);
++ if (is_dx(dir) && !do_not_use_dx) {
++ ext3_unlock_htree(dir, *lock);
++ goto repeat;
++ }
+ nblocks = dir->i_size >> EXT3_BLOCK_SIZE_BITS(sb);
+ start = EXT3_I(dir)->i_dir_start_lookup;
+ if (start >= nblocks)
+@@ -860,12 +1002,17 @@
+ /* Clean up the read-ahead blocks */
+ for (; ra_ptr < ra_max; ra_ptr++)
+ brelse (bh_use[ra_ptr]);
++ if (!ret) {
++ ext3_unlock_htree(dir, *lock);
++ *lock = NULL;
++ }
+ return ret;
+ }
+
+ #ifdef CONFIG_EXT3_INDEX
+ static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry,
+- struct ext3_dir_entry_2 **res_dir, int *err)
++ struct ext3_dir_entry_2 **res_dir, int *err,
++ int rwlock, void **lock)
+ {
+ struct super_block * sb;
+ struct dx_hash_info hinfo;
+@@ -880,11 +1027,22 @@
+ struct inode *dir = dentry->d_parent->d_inode;
+
+ sb = dir->i_sb;
+- if (!(frame = dx_probe (dentry, 0, &hinfo, frames, err)))
++repeat:
++ if (!(frame = dx_probe (&dentry->d_name, dir, &hinfo, frames, err)))
+ return NULL;
++
++ *lock = ext3_lock_htree(dir, frame->leaf, rwlock);
++ /* while locking leaf we just found may get splitted
++ * so, we need another leaf. check this */
++ if (!dx_check_full_path(frames, &hinfo)) {
++ ext3_unlock_htree(dir, *lock);
++ dx_release(frames);
++ goto repeat;
++ }
++
+ hash = hinfo.hash;
+ do {
+- block = dx_get_block(frame->at);
++ block = frame->leaf;
+ if (!(bh = ext3_bread (NULL,dir, block, 0, err)))
+ goto errout;
+ de = (struct ext3_dir_entry_2 *) bh->b_data;
+@@ -918,6 +1076,8 @@
+ *err = -ENOENT;
+ errout:
+ dxtrace(printk("%s not found\n", name));
++ ext3_unlock_htree(dir, *lock);
++ *lock = NULL;
+ dx_release (frames);
+ return NULL;
+ }
+@@ -928,6 +1088,7 @@
+ struct inode * inode;
+ struct ext3_dir_entry_2 * de;
+ struct buffer_head * bh;
++ void *lock = NULL;
+
+ if (dentry->d_name.len > EXT3_NAME_LEN)
+ return ERR_PTR(-ENAMETOOLONG);
+@@ -935,10 +1096,11 @@
+ if (ext3_check_for_iopen(dir, dentry))
+ return NULL;
+
+- bh = ext3_find_entry(dentry, &de);
++ bh = ext3_find_entry(dentry, &de, 0, &lock);
+ inode = NULL;
+ if (bh) {
+ unsigned long ino = le32_to_cpu(de->inode);
++ ext3_unlock_htree(dir, lock);
+ brelse (bh);
+ inode = iget(dir->i_sb, ino);
+
+@@ -975,7 +1137,8 @@
+ unsigned rec_len = 0;
+
+ while (count--) {
+- struct ext3_dir_entry_2 *de = (struct ext3_dir_entry_2 *) (from + map->offs);
++ struct ext3_dir_entry_2 *de =
++ (struct ext3_dir_entry_2 *) (from + map->offs);
+ rec_len = EXT3_DIR_REC_LEN(de->name_len);
+ memcpy (to, de, rec_len);
+ ((struct ext3_dir_entry_2 *) to)->rec_len = rec_len;
+@@ -988,7 +1151,8 @@
+
+ static struct ext3_dir_entry_2* dx_pack_dirents(char *base, int size)
+ {
+- struct ext3_dir_entry_2 *next, *to, *prev, *de = (struct ext3_dir_entry_2 *) base;
++ struct ext3_dir_entry_2 *next, *to, *prev;
++ struct ext3_dir_entry_2 *de = (struct ext3_dir_entry_2 *) base;
+ unsigned rec_len = 0;
+
+ prev = to = de;
+@@ -1010,7 +1174,8 @@
+
+ static struct ext3_dir_entry_2 *do_split(handle_t *handle, struct inode *dir,
+ struct buffer_head **bh,struct dx_frame *frame,
+- struct dx_hash_info *hinfo, int *error)
++ struct dx_hash_info *hinfo, void **target,
++ int *error)
+ {
+ unsigned blocksize = dir->i_sb->s_blocksize;
+ unsigned count, continued;
+@@ -1057,23 +1222,30 @@
+ hash2 = map[split].hash;
+ continued = hash2 == map[split - 1].hash;
+ dxtrace(printk("Split block %i at %x, %i/%i\n",
+- dx_get_block(frame->at), hash2, split, count-split));
+-
++ frame->leaf, hash2, split, count-split));
++
+ /* Fancy dance to stay within two buffers */
+ de2 = dx_move_dirents(data1, data2, map + split, count - split);
+ de = dx_pack_dirents(data1,blocksize);
+ de->rec_len = cpu_to_le16(data1 + blocksize - (char *) de);
+ de2->rec_len = cpu_to_le16(data2 + blocksize - (char *) de2);
+- dxtrace(dx_show_leaf (hinfo, (struct ext3_dir_entry_2 *) data1, blocksize, 1));
+- dxtrace(dx_show_leaf (hinfo, (struct ext3_dir_entry_2 *) data2, blocksize, 1));
++ dxtrace(dx_show_leaf(hinfo,(struct ext3_dir_entry_2*) data1, blocksize, 1));
++ dxtrace(dx_show_leaf(hinfo,(struct ext3_dir_entry_2*) data2, blocksize, 1));
+
+ /* Which block gets the new entry? */
++ *target = NULL;
+ if (hinfo->hash >= hash2)
+ {
+ swap(*bh, bh2);
+ de = de2;
+- }
+- dx_insert_block (frame, hash2 + continued, newblock);
++
++ /* entry will be stored into new block
++ * we have to lock it before add_dirent_to_buf */
++ *target = ext3_lock_htree(dir, newblock, 1);
++ }
++ dx_lock_bh(frame->bh);
++ dx_insert_block (dir, frame, hash2 + continued, newblock, frame->curidx);
++ dx_unlock_bh(frame->bh);
+ err = ext3_journal_dirty_metadata (handle, bh2);
+ if (err)
+ goto journal_error;
+@@ -1147,7 +1319,8 @@
+ nlen = EXT3_DIR_REC_LEN(de->name_len);
+ rlen = le16_to_cpu(de->rec_len);
+ if (de->inode) {
+- struct ext3_dir_entry_2 *de1 = (struct ext3_dir_entry_2 *)((char *)de + nlen);
++ struct ext3_dir_entry_2 *de1 =
++ (struct ext3_dir_entry_2 *)((char *)de + nlen);
+ de1->rec_len = cpu_to_le16(rlen - nlen);
+ de->rec_len = cpu_to_le16(nlen);
+ de = de1;
+@@ -1205,7 +1378,8 @@
+ unsigned blocksize;
+ struct dx_hash_info hinfo;
+ u32 block;
+-
++ void *lock, *new_lock;
++
+ blocksize = dir->i_sb->s_blocksize;
+ dxtrace(printk("Creating index\n"));
+ retval = ext3_journal_get_write_access(handle, bh);
+@@ -1216,7 +1390,6 @@
+ }
+ root = (struct dx_root *) bh->b_data;
+
+- EXT3_I(dir)->i_flags |= EXT3_INDEX_FL;
+ bh2 = ext3_append (handle, dir, &block, &retval);
+ if (!(bh2)) {
+ brelse(bh);
+@@ -1224,6 +1397,8 @@
+ }
+ data1 = bh2->b_data;
+
++ lock = ext3_lock_htree(dir, block, 1);
++
+ /* The 0th block becomes the root, move the dirents out */
+ de = (struct ext3_dir_entry_2 *) &root->dotdot;
+ de = (struct ext3_dir_entry_2 *) ((char *)de + de->rec_len);
+@@ -1253,13 +1428,25 @@
+ frame->entries = entries;
+ frame->at = entries;
+ frame->bh = bh;
++ frame->curidx = 0;
++ frame->leaf = 0;
++ frame[1].bh = NULL;
+ bh = bh2;
+- de = do_split(handle,dir, &bh, frame, &hinfo, &retval);
++ de = do_split(handle,dir, &bh, frame, &hinfo, &new_lock, &retval);
+ dx_release (frames);
+ if (!(de))
+- return retval;
++ goto cleanup;
++
++ retval = add_dirent_to_buf(handle, dentry, inode, de, bh);
++cleanup:
++ if (new_lock)
++ ext3_unlock_htree(dir, new_lock);
++ /* we mark directory indexed in order to
++ * avoid races while htree being created -bzzz */
++ EXT3_I(dir)->i_flags |= EXT3_INDEX_FL;
++ ext3_unlock_htree(dir, lock);
+
+- return add_dirent_to_buf(handle, dentry, inode, de, bh);
++ return retval;
+ }
+ #endif
+
+@@ -1288,11 +1475,13 @@
+ unsigned blocksize;
+ unsigned nlen, rlen;
+ u32 block, blocks;
++ void *lock;
+
+ sb = dir->i_sb;
+ blocksize = sb->s_blocksize;
+ if (!dentry->d_name.len)
+ return -EINVAL;
++repeat:
+ #ifdef CONFIG_EXT3_INDEX
+ if (is_dx(dir)) {
+ retval = ext3_dx_add_entry(handle, dentry, inode);
+@@ -1303,36 +1492,53 @@
+ ext3_mark_inode_dirty(handle, dir);
+ }
+ #endif
++ lock = ext3_lock_htree(dir, 0, 1);
++ if (is_dx(dir)) {
++ /* we got lock for block 0
++ * probably previous holder of the lock
++ * created htree -bzzz */
++ ext3_unlock_htree(dir, lock);
++ goto repeat;
++ }
++
+ blocks = dir->i_size >> sb->s_blocksize_bits;
+ for (block = 0, offset = 0; block < blocks; block++) {
+ bh = ext3_bread(handle, dir, block, 0, &retval);
+- if(!bh)
++ if(!bh) {
++ ext3_unlock_htree(dir, lock);
+ return retval;
++ }
+ retval = add_dirent_to_buf(handle, dentry, inode, 0, bh);
+- if (retval != -ENOSPC)
++ if (retval != -ENOSPC) {
++ ext3_unlock_htree(dir, lock);
+ return retval;
++ }
+
+ #ifdef CONFIG_EXT3_INDEX
+ if (blocks == 1 && !dx_fallback &&
+- EXT3_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_DIR_INDEX))
+- return make_indexed_dir(handle, dentry, inode, bh);
++ EXT3_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_DIR_INDEX)) {
++ retval = make_indexed_dir(handle, dentry, inode, bh);
++ ext3_unlock_htree(dir, lock);
++ return retval;
++ }
+ #endif
+ brelse(bh);
+ }
+ bh = ext3_append(handle, dir, &block, &retval);
+- if (!bh)
++ if (!bh) {
++ ext3_unlock_htree(dir, lock);
+ return retval;
++ }
+ de = (struct ext3_dir_entry_2 *) bh->b_data;
+ de->inode = 0;
+ de->rec_len = cpu_to_le16(rlen = blocksize);
+ nlen = 0;
+- return add_dirent_to_buf(handle, dentry, inode, de, bh);
++ retval = add_dirent_to_buf(handle, dentry, inode, de, bh);
++ ext3_unlock_htree(dir, lock);
++ return retval;
+ }
+
+ #ifdef CONFIG_EXT3_INDEX
+-/*
+- * Returns 0 for success, or a negative error value
+- */
+ static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry,
+ struct inode *inode)
+ {
+@@ -1344,15 +1550,28 @@
+ struct super_block * sb = dir->i_sb;
+ struct ext3_dir_entry_2 *de;
+ int err;
+-
+- frame = dx_probe(dentry, 0, &hinfo, frames, &err);
++ int curidx;
++ void *idx_lock, *leaf_lock, *newleaf_lock;
++
++repeat:
++ frame = dx_probe(&dentry->d_name, dir, &hinfo, frames, &err);
+ if (!frame)
+ return err;
+- entries = frame->entries;
+- at = frame->at;
+
+- if (!(bh = ext3_bread(handle,dir, dx_get_block(frame->at), 0, &err)))
++ /* we're going to chage leaf, so lock it first */
++ leaf_lock = ext3_lock_htree(dir, frame->leaf, 1);
++
++ /* while locking leaf we just found may get splitted
++ * so we need to check this */
++ if (!dx_check_full_path(frames, &hinfo)) {
++ ext3_unlock_htree(dir, leaf_lock);
++ dx_release(frames);
++ goto repeat;
++ }
++ if (!(bh = ext3_bread(handle,dir, frame->leaf, 0, &err))) {
++ printk("can't ext3_bread(%d) = %d\n", (int) frame->leaf, err);
+ goto cleanup;
++ }
+
+ BUFFER_TRACE(bh, "get_write_access");
+ err = ext3_journal_get_write_access(handle, bh);
+@@ -1365,6 +1584,35 @@
+ goto cleanup;
+ }
+
++ /* our leaf has no enough space. hence, we have to
++ * split it. so lock index for this leaf first */
++ curidx = frame->curidx;
++ idx_lock = ext3_lock_htree(dir, curidx, 1);
++
++ /* now check did path get changed? */
++ dx_release(frames);
++
++ frame = dx_probe(&dentry->d_name, dentry->d_parent->d_inode,
++ &hinfo, frames, &err);
++ if (!frame) {
++ /* FIXME: error handling here */
++ brelse(bh);
++ ext3_unlock_htree(dir, idx_lock);
++ return err;
++ }
++
++ if (frame->curidx != curidx) {
++ /* path has been changed. we have to drop old lock
++ * and repeat */
++ brelse(bh);
++ ext3_unlock_htree(dir, idx_lock);
++ ext3_unlock_htree(dir, leaf_lock);
++ dx_release(frames);
++ goto repeat;
++ }
++ entries = frame->entries;
++ at = frame->at;
++
+ /* Block full, should compress but for now just split */
+ dxtrace(printk("using %u of %u node entries\n",
+ dx_get_count(entries), dx_get_limit(entries)));
+@@ -1376,7 +1624,8 @@
+ struct dx_entry *entries2;
+ struct dx_node *node2;
+ struct buffer_head *bh2;
+-
++ void *nb_lock;
++
+ if (levels && (dx_get_count(frames->entries) ==
+ dx_get_limit(frames->entries))) {
+ ext3_warning(sb, __FUNCTION__,
+@@ -1387,6 +1636,7 @@
+ bh2 = ext3_append (handle, dir, &newblock, &err);
+ if (!(bh2))
+ goto cleanup;
++ nb_lock = ext3_lock_htree(dir, newblock, 1);
+ node2 = (struct dx_node *)(bh2->b_data);
+ entries2 = node2->entries;
+ node2->fake.rec_len = cpu_to_le16(sb->s_blocksize);
+@@ -1398,27 +1648,73 @@
+ if (levels) {
+ unsigned icount1 = icount/2, icount2 = icount - icount1;
+ unsigned hash2 = dx_get_hash(entries + icount1);
++ void *ri_lock;
++
++ /* we have to protect root htree index against
++ * another dx_add_entry() which would want to
++ * split it too -bzzz */
++ ri_lock = ext3_lock_htree(dir, 0, 1);
++
++ /* as root index block blocked we must repeat
++ * searching for current position of our 2nd index -bzzz */
++ dx_lock_bh(frame->bh);
++ frames->at = dx_find_position(frames->entries, hinfo.hash);
++ dx_unlock_bh(frame->bh);
++
+ dxtrace(printk("Split index %i/%i\n", icount1, icount2));
+-
+- BUFFER_TRACE(frame->bh, "get_write_access"); /* index root */
++
++ BUFFER_TRACE(frame->bh, "get_write_access");
+ err = ext3_journal_get_write_access(handle,
+ frames[0].bh);
+ if (err)
+ goto journal_error;
+-
++
++ /* copy index into new one */
+ memcpy ((char *) entries2, (char *) (entries + icount1),
+ icount2 * sizeof(struct dx_entry));
+- dx_set_count (entries, icount1);
+ dx_set_count (entries2, icount2);
+ dx_set_limit (entries2, dx_node_limit(dir));
+
+ /* Which index block gets the new entry? */
+ if (at - entries >= icount1) {
++ /* unlock index we won't use */
++ ext3_unlock_htree(dir, idx_lock);
++ idx_lock = nb_lock;
+ frame->at = at = at - entries - icount1 + entries2;
+- frame->entries = entries = entries2;
++ frame->entries = entries2;
++ frame->curidx = curidx = newblock;
+ swap(frame->bh, bh2);
++ } else {
++ /* we'll use old index,so new one may be freed */
++ ext3_unlock_htree(dir, nb_lock);
+ }
+- dx_insert_block (frames + 0, hash2, newblock);
++
++ /* NOTE: very subtle piece of code
++ * competing dx_probe() may find 2nd level index in root
++ * index, then we insert new index here and set new count
++ * in that 2nd level index. so, dx_probe() may see 2nd
++ * level index w/o hash it looks for. the solution is
++ * to check root index after we locked just founded 2nd
++ * level index -bzzz */
++ dx_lock_bh(frames[0].bh);
++ dx_insert_block (dir, frames + 0, hash2, newblock, 0);
++ dx_unlock_bh(frames[0].bh);
++
++ /* now old and new 2nd level index blocks contain
++ * all pointers, so dx_probe() may find it in the both.
++ * it's OK -bzzz */
++
++ dx_lock_bh(frame->bh);
++ dx_set_count(entries, icount1);
++ dx_unlock_bh(frame->bh);
++
++ /* now old 2nd level index block points to first half
++ * of leafs. it's importand that dx_probe() must
++ * check root index block for changes under
++ * dx_lock_bh(frame->bh) -bzzz */
++
++ ext3_unlock_htree(dir, ri_lock);
++
+ dxtrace(dx_show_index ("node", frames[1].entries));
+ dxtrace(dx_show_index ("node",
+ ((struct dx_node *) bh2->b_data)->entries));
+@@ -1427,38 +1723,61 @@
+ goto journal_error;
+ brelse (bh2);
+ } else {
++ unsigned long leaf = frame->leaf;
++
+ dxtrace(printk("Creating second level index...\n"));
+ memcpy((char *) entries2, (char *) entries,
+ icount * sizeof(struct dx_entry));
+ dx_set_limit(entries2, dx_node_limit(dir));
+
+ /* Set up root */
++ dx_lock_bh(frames[0].bh);
+ dx_set_count(entries, 1);
+ dx_set_block(entries + 0, newblock);
+ ((struct dx_root *) frames[0].bh->b_data)->info.indirect_levels = 1;
++ dx_unlock_bh(frames[0].bh);
+
+ /* Add new access path frame */
+ frame = frames + 1;
+ frame->at = at = at - entries + entries2;
+ frame->entries = entries = entries2;
+ frame->bh = bh2;
++ frame->curidx = newblock;
++ frame->leaf = leaf;
+ err = ext3_journal_get_write_access(handle,
+ frame->bh);
+ if (err)
+ goto journal_error;
++
++ /* first level index was root. it's already initialized */
++ /* we my unlock it now */
++ ext3_unlock_htree(dir, idx_lock);
++
++ /* current index is just created 2nd level index */
++ curidx = newblock;
++ idx_lock = nb_lock;
+ }
+ ext3_journal_dirty_metadata(handle, frames[0].bh);
+ }
+- de = do_split(handle, dir, &bh, frame, &hinfo, &err);
++ de = do_split(handle, dir, &bh, frame, &hinfo, &newleaf_lock, &err);
+ if (!de)
+ goto cleanup;
++
++ /* index splitted */
++ ext3_unlock_htree(dir, idx_lock);
++
+ err = add_dirent_to_buf(handle, dentry, inode, de, bh);
++
++ if (newleaf_lock)
++ ext3_unlock_htree(dir, newleaf_lock);
++
+ bh = 0;
+ goto cleanup;
+
+ journal_error:
+ ext3_std_error(dir->i_sb, err);
+ cleanup:
++ ext3_unlock_htree(dir, leaf_lock);
+ if (bh)
+ brelse(bh);
+ dx_release(frames);
+@@ -1902,6 +2221,7 @@
+ struct buffer_head * bh;
+ struct ext3_dir_entry_2 * de;
+ handle_t *handle;
++ void *lock;
+
+ handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS);
+ if (IS_ERR(handle)) {
+@@ -1909,7 +2229,7 @@
+ }
+
+ retval = -ENOENT;
+- bh = ext3_find_entry (dentry, &de);
++ bh = ext3_find_entry (dentry, &de, 1, &lock);
+ if (!bh)
+ goto end_rmdir;
+
+@@ -1920,14 +2240,19 @@
+ DQUOT_INIT(inode);
+
+ retval = -EIO;
+- if (le32_to_cpu(de->inode) != inode->i_ino)
++ if (le32_to_cpu(de->inode) != inode->i_ino) {
++ ext3_unlock_htree(dir, lock);
+ goto end_rmdir;
++ }
+
+ retval = -ENOTEMPTY;
+- if (!empty_dir (inode))
++ if (!empty_dir (inode)) {
++ ext3_unlock_htree(dir, lock);
+ goto end_rmdir;
++ }
+
+ retval = ext3_delete_entry(handle, dir, de, bh);
++ ext3_unlock_htree(dir, lock);
+ if (retval)
+ goto end_rmdir;
+ if (inode->i_nlink != 2)
+@@ -1956,6 +2281,7 @@
+ struct buffer_head * bh;
+ struct ext3_dir_entry_2 * de;
+ handle_t *handle;
++ void *lock;
+
+ handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS);
+ if (IS_ERR(handle)) {
+@@ -1966,7 +2292,7 @@
+ handle->h_sync = 1;
+
+ retval = -ENOENT;
+- bh = ext3_find_entry (dentry, &de);
++ bh = ext3_find_entry (dentry, &de, 1, &lock);
+ if (!bh)
+ goto end_unlink;
+
+@@ -1974,8 +2300,10 @@
+ DQUOT_INIT(inode);
+
+ retval = -EIO;
+- if (le32_to_cpu(de->inode) != inode->i_ino)
++ if (le32_to_cpu(de->inode) != inode->i_ino) {
++ ext3_unlock_htree(dir, lock);
+ goto end_unlink;
++ }
+
+ if (!inode->i_nlink) {
+ ext3_warning (inode->i_sb, "ext3_unlink",
+@@ -1984,6 +2312,7 @@
+ inode->i_nlink = 1;
+ }
+ retval = ext3_delete_entry(handle, dir, de, bh);
++ ext3_unlock_htree(dir, lock);
+ if (retval)
+ goto end_unlink;
+ dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+@@ -2121,6 +2450,7 @@
+ struct buffer_head * old_bh, * new_bh, * dir_bh;
+ struct ext3_dir_entry_2 * old_de, * new_de;
+ int retval;
++ void *lock1 = NULL, *lock2 = NULL, *lock3 = NULL;
+
+ old_bh = new_bh = dir_bh = NULL;
+
+@@ -2133,7 +2463,10 @@
+ if (IS_SYNC(old_dir) || IS_SYNC(new_dir))
+ handle->h_sync = 1;
+
+- old_bh = ext3_find_entry (old_dentry, &old_de);
++ if (old_dentry->d_parent == new_dentry->d_parent)
++ down(&EXT3_I(old_dentry->d_parent->d_inode)->i_rename_sem);
++
++ old_bh = ext3_find_entry (old_dentry, &old_de, 1, &lock1 /* FIXME */);
+ /*
+ * Check for inode number is _not_ due to possible IO errors.
+ * We might rmdir the source, keep it as pwd of some process
+@@ -2146,7 +2479,7 @@
+ goto end_rename;
+
+ new_inode = new_dentry->d_inode;
+- new_bh = ext3_find_entry (new_dentry, &new_de);
++ new_bh = ext3_find_entry (new_dentry, &new_de, 1, &lock2 /* FIXME */);
+ if (new_bh) {
+ if (!new_inode) {
+ brelse (new_bh);
+@@ -2209,7 +2542,7 @@
+ struct buffer_head *old_bh2;
+ struct ext3_dir_entry_2 *old_de2;
+
+- old_bh2 = ext3_find_entry(old_dentry, &old_de2);
++ old_bh2 = ext3_find_entry(old_dentry, &old_de2, 1, &lock3 /* FIXME */);
+ if (old_bh2) {
+ retval = ext3_delete_entry(handle, old_dir,
+ old_de2, old_bh2);
+@@ -2252,6 +2585,14 @@
+ retval = 0;
+
+ end_rename:
++ if (lock1)
++ ext3_unlock_htree(old_dentry->d_parent->d_inode, lock1);
++ if (lock2)
++ ext3_unlock_htree(new_dentry->d_parent->d_inode, lock2);
++ if (lock3)
++ ext3_unlock_htree(old_dentry->d_parent->d_inode, lock3);
++ if (old_dentry->d_parent == new_dentry->d_parent)
++ up(&EXT3_I(old_dentry->d_parent->d_inode)->i_rename_sem);
+ brelse (dir_bh);
+ brelse (old_bh);
+ brelse (new_bh);
+@@ -2260,6 +2601,29 @@
+ }
+
+ /*
++ * this locking primitives are used to protect parts
++ * of dir's htree. protection unit is block: leaf or index
++ */
++static inline void *ext3_lock_htree(struct inode *dir,
++ unsigned long value, int rwlock)
++{
++ void *lock;
++
++ if (!test_opt(dir->i_sb, PDIROPS))
++ return NULL;
++ lock = dynlock_lock(&EXT3_I(dir)->i_htree_lock, value, 1, GFP_KERNEL);
++ return lock;
++}
++
++static inline void ext3_unlock_htree(struct inode *dir,
++ void *lock)
++{
++ if (!test_opt(dir->i_sb, PDIROPS) || !lock)
++ return;
++ dynlock_unlock(&EXT3_I(dir)->i_htree_lock, lock);
++}
++
++/*
+ * directories can handle most operations...
+ */
+ struct inode_operations ext3_dir_inode_operations = {
+Index: linux-2.4.20/fs/ext3/super.c
+===================================================================
+--- linux-2.4.20.orig/fs/ext3/super.c Wed Mar 17 15:37:09 2004
++++ linux-2.4.20/fs/ext3/super.c Wed Mar 17 15:37:10 2004
+@@ -796,6 +796,8 @@
+ return 0;
+ }
+ }
++ else if (!strcmp (this_char, "pdirops"))
++ set_opt (sbi->s_mount_opt, PDIROPS);
+ else if (!strcmp (this_char, "grpid") ||
+ !strcmp (this_char, "bsdgroups"))
+ set_opt (*mount_options, GRPID);
+@@ -822,6 +824,9 @@
+ if (want_numeric(value, "sb", sb_block))
+ return 0;
+ }
++ else if (!strcmp (this_char, "pdirops")) {
++ set_opt (sbi->s_mount_opt, PDIROPS);
++ }
+ #ifdef CONFIG_JBD_DEBUG
+ else if (!strcmp (this_char, "ro-after")) {
+ unsigned long v;
+@@ -985,6 +990,10 @@
+ ext3_check_inodes_bitmap (sb);
+ }
+ #endif
++#ifdef S_PDIROPS
++ if (test_opt (sb, PDIROPS))
++ sb->s_flags |= S_PDIROPS;
++#endif
+ setup_ro_after(sb);
+ return res;
+ }
+@@ -1484,6 +1493,11 @@
+ test_opt(sb,DATA_FLAGS) == EXT3_MOUNT_ORDERED_DATA ? "ordered":
+ "writeback");
+
++ if (test_opt(sb, PDIROPS)) {
++ printk (KERN_INFO "EXT3-fs: mounted filesystem with parallel dirops\n");
++ sb->s_flags |= S_PDIROPS;
++ }
++
+ return sb;
+
+ failed_mount3:
+Index: linux-2.4.20/fs/ext3/inode.c
+===================================================================
+--- linux-2.4.20.orig/fs/ext3/inode.c Wed Mar 17 15:37:09 2004
++++ linux-2.4.20/fs/ext3/inode.c Wed Mar 17 15:37:10 2004
+@@ -2435,6 +2435,9 @@
+ } else if (S_ISDIR(inode->i_mode)) {
+ inode->i_op = &ext3_dir_inode_operations;
+ inode->i_fop = &ext3_dir_operations;
++ dynlock_init(&EXT3_I(inode)->i_htree_lock);
++ sema_init(&EXT3_I(inode)->i_rename_sem, 1);
++ sema_init(&EXT3_I(inode)->i_append_sem, 1);
+ } else if (S_ISLNK(inode->i_mode)) {
+ if (ext3_inode_is_fast_symlink(inode))
+ inode->i_op = &ext3_fast_symlink_inode_operations;
+Index: linux-2.4.20/fs/ext3/ialloc.c
+===================================================================
+--- linux-2.4.20.orig/fs/ext3/ialloc.c Wed Mar 17 15:37:09 2004
++++ linux-2.4.20/fs/ext3/ialloc.c Wed Mar 17 15:37:10 2004
+@@ -601,6 +601,9 @@
+ return ERR_PTR(-EDQUOT);
+ }
+ ext3_debug ("allocating inode %lu\n", inode->i_ino);
++ dynlock_init(&EXT3_I(inode)->i_htree_lock);
++ sema_init(&EXT3_I(inode)->i_rename_sem, 1);
++ sema_init(&EXT3_I(inode)->i_append_sem, 1);
+ return inode;
+
+ fail:
+Index: linux-2.4.20/include/linux/ext3_fs.h
+===================================================================
+--- linux-2.4.20.orig/include/linux/ext3_fs.h Wed Mar 17 15:37:09 2004
++++ linux-2.4.20/include/linux/ext3_fs.h Wed Mar 17 15:37:10 2004
+@@ -306,6 +306,7 @@
+ /*
+ * Mount flags
+ */
++#define EXT3_MOUNT_PDIROPS 0x800000/* Parallel dir operations */
+ #define EXT3_MOUNT_CHECK 0x0001 /* Do mount-time checks */
+ #define EXT3_MOUNT_GRPID 0x0004 /* Create files with directory's group */
+ #define EXT3_MOUNT_DEBUG 0x0008 /* Some debugging messages */
+Index: linux-2.4.20/include/linux/ext3_fs_i.h
+===================================================================
+--- linux-2.4.20.orig/include/linux/ext3_fs_i.h Thu Nov 22 11:46:19 2001
++++ linux-2.4.20/include/linux/ext3_fs_i.h Wed Mar 17 15:37:10 2004
+@@ -17,6 +17,7 @@
+ #define _LINUX_EXT3_FS_I
+
+ #include <linux/rwsem.h>
++#include <linux/dynlocks.h>
+
+ /*
+ * second extended file system inode data in memory
+@@ -73,6 +74,11 @@
+ * by other means, so we have truncate_sem.
+ */
+ struct rw_semaphore truncate_sem;
++
++ /* following fields for parallel directory operations -bzzz */
++ struct dynlock i_htree_lock;
++ struct semaphore i_append_sem;
++ struct semaphore i_rename_sem;
+ };
+
+ #endif /* _LINUX_EXT3_FS_I */
--- /dev/null
+--- linux-2.4.24-l32/mm/filemap.c.inode_ramax 2004-03-14 13:16:21.000000000 -0800
++++ linux-2.4.24-l32/mm/filemap.c 2004-03-16 10:57:14.000000000 -0800
+@@ -1226,6 +1226,8 @@
+
+ static inline int get_max_readahead(struct inode * inode)
+ {
++ if (inode->i_mapping->a_ops->max_readahead)
++ return inode->i_mapping->a_ops->max_readahead(inode);
+ if (!inode->i_dev || !max_readahead[MAJOR(inode->i_dev)])
+ return vm_max_readahead;
+ return max_readahead[MAJOR(inode->i_dev)][MINOR(inode->i_dev)];
+--- linux-2.4.24-l32/include/linux/fs.h.inode_ramax 2004-03-14 13:15:49.000000000 -0800
++++ linux-2.4.24-l32/include/linux/fs.h 2004-03-15 11:56:56.000000000 -0800
+@@ -410,6 +410,8 @@
+ #define KERNEL_HAS_DIRECT_FILEIO /* Unfortunate kludge due to lack of foresight */
+ int (*direct_fileIO)(int, struct file *, struct kiobuf *, unsigned long, int);
+ void (*removepage)(struct page *); /* called when page gets removed from the inode */
++#define KERNEL_HAS_AS_MAX_READAHEAD
++ int (*max_readahead)(struct inode *);
+ };
+
+ struct address_space {
include/linux/ext3_fs.h | 2
8 files changed, 318 insertions(+), 2 deletions(-)
-Index: linux-2.4.22-uml/Documentation/filesystems/ext2.txt
+Index: lum/Documentation/filesystems/ext2.txt
===================================================================
---- linux-2.4.22-uml.orig/Documentation/filesystems/ext2.txt 2001-07-11 16:44:45.000000000 -0600
-+++ linux-2.4.22-uml/Documentation/filesystems/ext2.txt 2004-01-30 14:18:10.000000000 -0700
+--- lum.orig/Documentation/filesystems/ext2.txt 2001-07-11 16:44:45.000000000 -0600
++++ lum/Documentation/filesystems/ext2.txt 2004-03-09 16:46:38.000000000 -0700
@@ -35,6 +35,22 @@
sb=n Use alternate superblock at this location.
grpquota,noquota,quota,usrquota Quota options are silently ignored by ext2.
-Index: linux-2.4.22-uml/fs/ext3/Makefile
+Index: lum/fs/ext3/Makefile
===================================================================
---- linux-2.4.22-uml.orig/fs/ext3/Makefile 2004-01-30 14:17:58.000000000 -0700
-+++ linux-2.4.22-uml/fs/ext3/Makefile 2004-01-30 14:18:10.000000000 -0700
+--- lum.orig/fs/ext3/Makefile 2004-01-30 14:54:50.000000000 -0700
++++ lum/fs/ext3/Makefile 2004-03-09 16:46:39.000000000 -0700
@@ -11,7 +11,7 @@
export-objs := ext3-exports.o
ioctl.o namei.o super.o symlink.o hash.o ext3-exports.o
obj-m := $(O_TARGET)
-Index: linux-2.4.22-uml/fs/ext3/inode.c
+Index: lum/fs/ext3/inode.c
===================================================================
---- linux-2.4.22-uml.orig/fs/ext3/inode.c 2004-01-30 14:17:59.000000000 -0700
-+++ linux-2.4.22-uml/fs/ext3/inode.c 2004-01-30 14:18:10.000000000 -0700
+--- lum.orig/fs/ext3/inode.c 2004-01-30 14:54:55.000000000 -0700
++++ lum/fs/ext3/inode.c 2004-03-09 16:46:41.000000000 -0700
@@ -31,6 +31,7 @@
#include <linux/highuid.h>
#include <linux/quotaops.h>
if(ext3_get_inode_loc(inode, &iloc))
goto bad_inode;
bh = iloc.bh;
-Index: linux-2.4.22-uml/fs/ext3/iopen.c
+Index: lum/fs/ext3/iopen.c
===================================================================
---- linux-2.4.22-uml.orig/fs/ext3/iopen.c 2004-01-30 14:18:10.000000000 -0700
-+++ linux-2.4.22-uml/fs/ext3/iopen.c 2004-01-30 14:18:10.000000000 -0700
-@@ -0,0 +1,258 @@
+--- lum.orig/fs/ext3/iopen.c 2004-03-09 16:46:37.000000000 -0700
++++ lum/fs/ext3/iopen.c 2004-03-09 16:48:03.000000000 -0700
+@@ -0,0 +1,282 @@
+/*
+ * linux/fs/ext3/iopen.c
+ *
+
+/* This function is spliced into ext3_lookup and does the move of a
+ * disconnected dentry (if it exists) to a connected dentry.
-+ * Caller must hold dcache_lock.
+ */
-+struct dentry *iopen_connect_dentry(struct dentry *de, struct inode *inode)
++struct dentry *iopen_connect_dentry(struct dentry *dentry, struct inode *inode,
++ int rehash)
+{
+ struct dentry *tmp, *goal = NULL;
+ struct list_head *lp;
+
++ /* verify this dentry is really new */
++ assert(dentry->d_inode == NULL);
++ assert(list_empty(&dentry->d_alias)); /* d_instantiate */
++ if (rehash)
++ assert(list_empty(&dentry->d_hash)); /* d_rehash */
++ assert(list_empty(&dentry->d_subdirs));
++
++ spin_lock(&dcache_lock);
++ if (!inode)
++ goto do_rehash;
++
+ /* preferrably return a connected dentry */
+ list_for_each(lp, &inode->i_dentry) {
+ tmp = list_entry(lp, struct dentry, d_alias);
+ }
+
+ if (!goal)
-+ return NULL;
++ goto do_instantiate;
+
+ /* Move the goal to the de hash queue - like d_move() */
+ goal->d_flags &= ~DCACHE_NFSD_DISCONNECTED;
+ list_del_init(&goal->d_hash);
+
+ list_del(&goal->d_child);
-+ list_del(&de->d_child);
++ list_del(&dentry->d_child);
+
+ /* Switch the parents and the names.. */
-+ switch_names(goal, de);
-+ do_switch(goal->d_parent, de->d_parent);
-+ do_switch(goal->d_name.len, de->d_name.len);
-+ do_switch(goal->d_name.hash, de->d_name.hash);
++ switch_names(goal, dentry);
++ do_switch(goal->d_parent, dentry->d_parent);
++ do_switch(goal->d_name.len, dentry->d_name.len);
++ do_switch(goal->d_name.hash, dentry->d_name.hash);
+
+ /* And add them back to the (new) parent lists */
+ list_add(&goal->d_child, &goal->d_parent->d_subdirs);
-+ list_add(&de->d_child, &de->d_parent->d_subdirs);
++ list_add(&dentry->d_child, &dentry->d_parent->d_subdirs);
+ __d_rehash(goal, 0);
++ spin_unlock(&dcache_lock);
++ iput(inode);
+
+ return goal;
++
++ /* d_add(), but don't drop dcache_lock before adding dentry to inode */
++do_instantiate:
++ list_add(&dentry->d_alias, &inode->i_dentry); /* d_instantiate */
++ dentry->d_inode = inode;
++do_rehash:
++ if (rehash)
++ __d_rehash(dentry, 0); /* d_rehash */
++ spin_unlock(&dcache_lock);
++
++ return NULL;
+}
+
+/*
+
+ return 1;
+}
-Index: linux-2.4.22-uml/fs/ext3/iopen.h
+Index: lum/fs/ext3/iopen.h
===================================================================
---- linux-2.4.22-uml.orig/fs/ext3/iopen.h 2004-01-30 14:18:10.000000000 -0700
-+++ linux-2.4.22-uml/fs/ext3/iopen.h 2004-01-30 14:18:10.000000000 -0700
+--- lum.orig/fs/ext3/iopen.h 2004-03-09 16:46:37.000000000 -0700
++++ lum/fs/ext3/iopen.h 2004-03-09 16:48:03.000000000 -0700
@@ -0,0 +1,15 @@
+/*
+ * iopen.h
+
+extern int ext3_check_for_iopen(struct inode *dir, struct dentry *dentry);
+extern int ext3_iopen_get_inode(struct inode *inode);
-+extern struct dentry *iopen_connect_dentry(struct dentry *de,
-+ struct inode *inode);
-Index: linux-2.4.22-uml/fs/ext3/namei.c
++extern struct dentry *iopen_connect_dentry(struct dentry *dentry,
++ struct inode *inode, int rehash);
+Index: lum/fs/ext3/namei.c
===================================================================
---- linux-2.4.22-uml.orig/fs/ext3/namei.c 2004-01-30 14:17:59.000000000 -0700
-+++ linux-2.4.22-uml/fs/ext3/namei.c 2004-01-30 14:19:44.000000000 -0700
+--- lum.orig/fs/ext3/namei.c 2004-01-30 14:54:53.000000000 -0700
++++ lum/fs/ext3/namei.c 2004-03-09 16:49:25.000000000 -0700
@@ -35,7 +35,7 @@
#include <linux/string.h>
#include <linux/locks.h>
/*
* define how far ahead to read directories while searching them.
-@@ -927,10 +927,14 @@
- struct inode * inode;
- struct ext3_dir_entry_2 * de;
- struct buffer_head * bh;
-+ struct dentry *alternate = NULL;
-
+@@ -931,6 +931,9 @@
if (dentry->d_name.len > EXT3_NAME_LEN)
return ERR_PTR(-ENAMETOOLONG);
bh = ext3_find_entry(dentry, &de);
inode = NULL;
if (bh) {
-@@ -942,7 +946,28 @@
+@@ -942,8 +945,8 @@
return ERR_PTR(-EACCES);
}
}
- d_add(dentry, inode);
+- return NULL;
+
-+ /* verify this dentry is really new */
-+ assert(!dentry->d_inode);
-+ assert(list_empty(&dentry->d_alias)); /* d_instantiate */
-+ assert(list_empty(&dentry->d_hash)); /* d_rehash */
-+ assert(list_empty(&dentry->d_subdirs));
-+
-+ spin_lock(&dcache_lock);
-+ if (inode && (alternate = iopen_connect_dentry(dentry, inode))) {
-+ spin_unlock(&dcache_lock);
-+ iput(inode);
-+ return alternate;
++ return iopen_connect_dentry(dentry, inode, 1);
+ }
+
+ #define S_SHIFT 12
+@@ -1932,10 +1935,6 @@
+ inode->i_nlink);
+ inode->i_version = ++event;
+ inode->i_nlink = 0;
+- /* There's no need to set i_disksize: the fact that i_nlink is
+- * zero will ensure that the right thing happens during any
+- * recovery. */
+- inode->i_size = 0;
+ ext3_orphan_add(handle, inode);
+ dir->i_nlink--;
+ inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+@@ -2086,6 +2085,23 @@
+ return err;
+ }
+
++/* Like ext3_add_nondir() except for call to iopen_connect_dentry */
++static int ext3_add_link(handle_t *handle, struct dentry *dentry,
++ struct inode *inode)
++{
++ int err = ext3_add_entry(handle, dentry, inode);
++ if (!err) {
++ err = ext3_mark_inode_dirty(handle, inode);
++ if (err == 0) {
++ (void)iopen_connect_dentry(dentry, inode, 0);
++ return 0;
++ }
+ }
++ ext3_dec_count(handle, inode);
++ iput(inode);
++ return err;
++}
+
-+ /* d_add(), but don't drop dcache_lock before adding dentry to inode */
-+ if (inode) /* d_instantiate */
-+ list_add(&dentry->d_alias, &inode->i_dentry);
-+ dentry->d_inode = inode;
-+
-+ __d_rehash(dentry, 0); /* d_rehash */
-+ spin_unlock(&dcache_lock);
-+
- return NULL;
- }
+ static int ext3_link (struct dentry * old_dentry,
+ struct inode * dir, struct dentry *dentry)
+ {
+@@ -2113,7 +2129,8 @@
+ ext3_inc_count(handle, inode);
+ atomic_inc(&inode->i_count);
-Index: linux-2.4.22-uml/fs/ext3/super.c
+- err = ext3_add_nondir(handle, dentry, inode);
++ err = ext3_add_link(handle, dentry, inode);
++ ext3_orphan_del(handle, inode);
+ ext3_journal_stop(handle, dir);
+ return err;
+ }
+Index: lum/fs/ext3/super.c
===================================================================
---- linux-2.4.22-uml.orig/fs/ext3/super.c Sun Nov 16 01:19:22 2003
-+++ linux-2.4.22-uml/fs/ext3/super.c Sun Nov 16 01:27:31 2003
-@@ -839,6 +839,18 @@
+--- lum.orig/fs/ext3/super.c 2004-01-30 14:54:53.000000000 -0700
++++ lum/fs/ext3/super.c 2004-03-09 16:46:45.000000000 -0700
+@@ -742,6 +742,18 @@
|| !strcmp (this_char, "quota")
|| !strcmp (this_char, "usrquota"))
/* Don't do anything ;-) */ ;
else if (!strcmp (this_char, "journal")) {
/* @@@ FIXME */
/* Eventually we will want to be able to create
-Index: linux-2.4.22-uml/include/linux/ext3_fs.h
+Index: lum/include/linux/ext3_fs.h
===================================================================
---- linux-2.4.22-uml.orig/include/linux/ext3_fs.h 2004-01-30 14:17:59.000000000 -0700
-+++ linux-2.4.22-uml/include/linux/ext3_fs.h 2004-01-30 14:18:10.000000000 -0700
+--- lum.orig/include/linux/ext3_fs.h 2004-01-30 14:54:53.000000000 -0700
++++ lum/include/linux/ext3_fs.h 2004-03-09 16:46:46.000000000 -0700
@@ -322,6 +322,8 @@
#define EXT3_MOUNT_UPDATE_JOURNAL 0x1000 /* Update the journal format */
#define EXT3_MOUNT_NO_UID32 0x2000 /* Disable 32-bit UIDs */
include/linux/ext3_fs.h | 2
8 files changed, 318 insertions(+), 2 deletions(-)
-Index: linux-2.4.21-chaos/Documentation/filesystems/ext2.txt
+Index: linux-ia64/Documentation/filesystems/ext2.txt
===================================================================
---- linux-2.4.21-chaos.orig/Documentation/filesystems/ext2.txt 2002-05-08 01:53:59.000000000 +0400
-+++ linux-2.4.21-chaos/Documentation/filesystems/ext2.txt 2003-12-12 16:19:04.000000000 +0300
-@@ -35,6 +35,22 @@
+--- linux-ia64.orig/Documentation/filesystems/ext2.txt 2004-03-17 15:47:15.000000000 -0800
++++ linux-ia64/Documentation/filesystems/ext2.txt 2004-03-17 18:03:15.000000000 -0800
+@@ -35,6 +35,22 @@ resgid=n The group ID which may use th
sb=n Use alternate superblock at this location.
grpquota,noquota,quota,usrquota Quota options are silently ignored by ext2.
-Index: linux-2.4.21-chaos/fs/ext3/Makefile
+Index: linux-ia64/fs/ext3/Makefile
===================================================================
---- linux-2.4.21-chaos.orig/fs/ext3/Makefile 2003-12-12 16:18:36.000000000 +0300
-+++ linux-2.4.21-chaos/fs/ext3/Makefile 2003-12-12 16:19:04.000000000 +0300
-@@ -11,7 +11,7 @@
+--- linux-ia64.orig/fs/ext3/Makefile 2004-03-17 18:03:14.000000000 -0800
++++ linux-ia64/fs/ext3/Makefile 2004-03-17 18:03:15.000000000 -0800
+@@ -11,7 +11,7 @@ O_TARGET := ext3.o
export-objs := ext3-exports.o
ioctl.o namei.o super.o symlink.o hash.o ext3-exports.o
obj-m := $(O_TARGET)
-Index: linux-2.4.21-chaos/fs/ext3/inode.c
+Index: linux-ia64/fs/ext3/inode.c
===================================================================
---- linux-2.4.21-chaos.orig/fs/ext3/inode.c 2003-12-12 16:19:02.000000000 +0300
-+++ linux-2.4.21-chaos/fs/ext3/inode.c 2003-12-12 16:19:05.000000000 +0300
+--- linux-ia64.orig/fs/ext3/inode.c 2004-03-17 18:03:15.000000000 -0800
++++ linux-ia64/fs/ext3/inode.c 2004-03-17 18:10:36.000000000 -0800
@@ -34,6 +34,7 @@
#include <linux/highuid.h>
#include <linux/quotaops.h>
/*
* SEARCH_FROM_ZERO forces each block allocation to search from the start
-@@ -2430,6 +2431,9 @@
+@@ -2430,6 +2431,9 @@ void ext3_read_inode(struct inode * inod
struct buffer_head *bh;
int block;
if(ext3_get_inode_loc(inode, &iloc))
goto bad_inode;
bh = iloc.bh;
-Index: linux-2.4.21-chaos/fs/ext3/iopen.c
+Index: linux-ia64/fs/ext3/iopen.c
===================================================================
---- linux-2.4.21-chaos.orig/fs/ext3/iopen.c 2003-01-30 13:24:37.000000000 +0300
-+++ linux-2.4.21-chaos/fs/ext3/iopen.c 2003-12-12 16:19:05.000000000 +0300
-@@ -0,0 +1,258 @@
-+/*
-+ * linux/fs/ext3/iopen.c
-+ *
-+ * Special support for open by inode number
-+ *
-+ * Copyright (C) 2001 by Theodore Ts'o (tytso@alum.mit.edu).
-+ *
-+ * This file may be redistributed under the terms of the GNU General
-+ * Public License.
-+ *
+--- linux-ia64.orig/fs/ext3/iopen.c 2004-03-17 18:02:08.000000000 -0800
++++ linux-ia64/fs/ext3/iopen.c 2004-03-17 18:10:58.000000000 -0800
+@@ -8,3 +8,275 @@
+ * This file may be redistributed under the terms of the GNU General
+ * Public License.
+ *
+ *
+ * Invariants:
+ * - there is only ever a single DCACHE_NFSD_DISCONNECTED dentry alias
+
+/* This function is spliced into ext3_lookup and does the move of a
+ * disconnected dentry (if it exists) to a connected dentry.
-+ * Caller must hold dcache_lock.
+ */
-+struct dentry *iopen_connect_dentry(struct dentry *de, struct inode *inode)
++struct dentry *iopen_connect_dentry(struct dentry *dentry, struct inode *inode,
++ int rehash)
+{
+ struct dentry *tmp, *goal = NULL;
+ struct list_head *lp;
+
++ /* verify this dentry is really new */
++ assert(dentry->d_inode == NULL);
++ assert(list_empty(&dentry->d_alias)); /* d_instantiate */
++ if (rehash)
++ assert(list_empty(&dentry->d_hash)); /* d_rehash */
++ assert(list_empty(&dentry->d_subdirs));
++
++ spin_lock(&dcache_lock);
++ if (!inode)
++ goto do_rehash;
++
+ /* preferrably return a connected dentry */
+ list_for_each(lp, &inode->i_dentry) {
+ tmp = list_entry(lp, struct dentry, d_alias);
+ }
+
+ if (!goal)
-+ return NULL;
++ goto do_instantiate;
+
+ /* Move the goal to the de hash queue - like d_move() */
+ goal->d_flags &= ~DCACHE_NFSD_DISCONNECTED;
+ list_del_init(&goal->d_hash);
+
+ list_del(&goal->d_child);
-+ list_del(&de->d_child);
++ list_del(&dentry->d_child);
+
+ /* Switch the parents and the names.. */
-+ switch_names(goal, de);
-+ do_switch(goal->d_parent, de->d_parent);
-+ do_switch(goal->d_name.len, de->d_name.len);
-+ do_switch(goal->d_name.hash, de->d_name.hash);
++ switch_names(goal, dentry);
++ do_switch(goal->d_parent, dentry->d_parent);
++ do_switch(goal->d_name.len, dentry->d_name.len);
++ do_switch(goal->d_name.hash, dentry->d_name.hash);
+
+ /* And add them back to the (new) parent lists */
+ list_add(&goal->d_child, &goal->d_parent->d_subdirs);
-+ list_add(&de->d_child, &de->d_parent->d_subdirs);
++ list_add(&dentry->d_child, &dentry->d_parent->d_subdirs);
+ __d_rehash(goal, 0);
++ spin_unlock(&dcache_lock);
++ iput(inode);
+
+ return goal;
++
++ /* d_add(), but don't drop dcache_lock before adding dentry to inode */
++do_instantiate:
++ list_add(&dentry->d_alias, &inode->i_dentry); /* d_instantiate */
++ dentry->d_inode = inode;
++do_rehash:
++ if (rehash)
++ __d_rehash(dentry, 0); /* d_rehash */
++ spin_unlock(&dcache_lock);
++
++ return NULL;
+}
+
+/*
+
+ return 1;
+}
-Index: linux-2.4.21-chaos/fs/ext3/iopen.h
+Index: linux-ia64/fs/ext3/iopen.h
===================================================================
---- linux-2.4.21-chaos.orig/fs/ext3/iopen.h 2003-01-30 13:24:37.000000000 +0300
-+++ linux-2.4.21-chaos/fs/ext3/iopen.h 2003-12-12 16:19:05.000000000 +0300
+--- linux-ia64.orig/fs/ext3/iopen.h 2004-03-17 15:47:15.000000000 -0800
++++ linux-ia64/fs/ext3/iopen.h 2004-03-17 18:03:15.000000000 -0800
@@ -0,0 +1,15 @@
+/*
+ * iopen.h
+
+extern int ext3_check_for_iopen(struct inode *dir, struct dentry *dentry);
+extern int ext3_iopen_get_inode(struct inode *inode);
-+extern struct dentry *iopen_connect_dentry(struct dentry *de,
-+ struct inode *inode);
-Index: linux-2.4.21-chaos/fs/ext3/namei.c
++extern struct dentry *iopen_connect_dentry(struct dentry *dentry,
++ struct inode *inode, int rehash);
+Index: linux-ia64/fs/ext3/namei.c
===================================================================
---- linux-2.4.21-chaos.orig/fs/ext3/namei.c 2003-12-12 16:18:59.000000000 +0300
-+++ linux-2.4.21-chaos/fs/ext3/namei.c 2003-12-12 16:19:05.000000000 +0300
+--- linux-ia64.orig/fs/ext3/namei.c 2004-03-17 18:03:15.000000000 -0800
++++ linux-ia64/fs/ext3/namei.c 2004-03-17 18:10:35.000000000 -0800
@@ -36,7 +36,7 @@
#include <linux/string.h>
#include <linux/locks.h>
/*
* define how far ahead to read directories while searching them.
-@@ -922,10 +922,14 @@
- struct inode * inode;
- struct ext3_dir_entry_2 * de;
- struct buffer_head * bh;
-+ struct dentry *alternate = NULL;
-
+@@ -932,6 +932,9 @@ static struct dentry *ext3_lookup(struct
if (dentry->d_name.len > EXT3_NAME_LEN)
return ERR_PTR(-ENAMETOOLONG);
bh = ext3_find_entry(dentry, &de);
inode = NULL;
if (bh) {
-@@ -943,7 +948,28 @@
+@@ -943,8 +946,8 @@ static struct dentry *ext3_lookup(struct
return ERR_PTR(-EACCES);
}
}
- d_add(dentry, inode);
+- return NULL;
+
-+ /* verify this dentry is really new */
-+ assert(!dentry->d_inode);
-+ assert(list_empty(&dentry->d_alias)); /* d_instantiate */
-+ assert(list_empty(&dentry->d_hash)); /* d_rehash */
-+ assert(list_empty(&dentry->d_subdirs));
-+
-+ spin_lock(&dcache_lock);
-+ if (inode && (alternate = iopen_connect_dentry(dentry, inode))) {
-+ spin_unlock(&dcache_lock);
-+ iput(inode);
-+ return alternate;
++ return iopen_connect_dentry(dentry, inode, 1);
+ }
+
+ #define S_SHIFT 12
+@@ -1935,10 +1938,6 @@ static int ext3_rmdir (struct inode * di
+ inode->i_nlink);
+ inode->i_version = ++event;
+ inode->i_nlink = 0;
+- /* There's no need to set i_disksize: the fact that i_nlink is
+- * zero will ensure that the right thing happens during any
+- * recovery. */
+- inode->i_size = 0;
+ ext3_orphan_add(handle, inode);
+ dir->i_nlink--;
+ inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+@@ -2057,6 +2056,23 @@ out_stop:
+ return err;
+ }
+
++/* Like ext3_add_nondir() except for call to iopen_connect_dentry */
++static int ext3_add_link(handle_t *handle, struct dentry *dentry,
++ struct inode *inode)
++{
++ int err = ext3_add_entry(handle, dentry, inode);
++ if (!err) {
++ err = ext3_mark_inode_dirty(handle, inode);
++ if (err == 0) {
++ (void)iopen_connect_dentry(dentry, inode, 0);
++ return 0;
++ }
+ }
++ ext3_dec_count(handle, inode);
++ iput(inode);
++ return err;
++}
+
-+ /* d_add(), but don't drop dcache_lock before adding dentry to inode */
-+ if (inode) /* d_instantiate */
-+ list_add(&dentry->d_alias, &inode->i_dentry);
-+ dentry->d_inode = inode;
-+
-+ __d_rehash(dentry, 0); /* d_rehash */
-+ spin_unlock(&dcache_lock);
-+
- return NULL;
- }
+ static int ext3_link (struct dentry * old_dentry,
+ struct inode * dir, struct dentry *dentry)
+ {
+@@ -2084,7 +2100,8 @@ static int ext3_link (struct dentry * ol
+ ext3_inc_count(handle, inode);
+ atomic_inc(&inode->i_count);
-Index: linux-2.4.21-chaos/fs/ext3/super.c
+- err = ext3_add_nondir(handle, dentry, inode);
++ err = ext3_add_link(handle, dentry, inode);
++ ext3_orphan_del(handle, inode);
+ ext3_journal_stop(handle, dir);
+ return err;
+ }
+Index: linux-ia64/fs/ext3/super.c
===================================================================
---- linux-2.4.21-chaos.orig/fs/ext3/super.c 2003-12-12 16:18:51.000000000 +0300
-+++ linux-2.4.21-chaos/fs/ext3/super.c 2003-12-12 16:19:05.000000000 +0300
-@@ -890,6 +890,18 @@
+--- linux-ia64.orig/fs/ext3/super.c 2004-03-17 18:03:14.000000000 -0800
++++ linux-ia64/fs/ext3/super.c 2004-03-17 18:10:35.000000000 -0800
+@@ -891,6 +891,18 @@ static int parse_options (char * options
|| !strcmp (this_char, "quota")
|| !strcmp (this_char, "usrquota"))
/* Don't do anything ;-) */ ;
else if (!strcmp (this_char, "journal")) {
/* @@@ FIXME */
/* Eventually we will want to be able to create
-Index: linux-2.4.21-chaos/include/linux/ext3_fs.h
+Index: linux-ia64/include/linux/ext3_fs.h
===================================================================
---- linux-2.4.21-chaos.orig/include/linux/ext3_fs.h 2003-12-12 16:19:01.000000000 +0300
-+++ linux-2.4.21-chaos/include/linux/ext3_fs.h 2003-12-12 16:19:05.000000000 +0300
-@@ -328,6 +328,8 @@
+--- linux-ia64.orig/include/linux/ext3_fs.h 2004-03-17 18:03:15.000000000 -0800
++++ linux-ia64/include/linux/ext3_fs.h 2004-03-17 18:03:15.000000000 -0800
+@@ -328,6 +328,8 @@ struct ext3_inode {
#define EXT3_MOUNT_XATTR_USER 0x4000 /* Extended user attributes */
#define EXT3_MOUNT_POSIX_ACL 0x8000 /* POSIX Access Control Lists */
#define EXT3_MOUNT_ASYNCDEL 0x20000 /* Delayed deletion */
sb=n Use alternate superblock at this location.
-+iopen Makes an invisible pseudo-directory called
++iopen Makes an invisible pseudo-directory called
+ __iopen__ available in the root directory
+ of the filesystem. Allows open-by-inode-
+ number. i.e., inode 3145 can be accessed
===================================================================
--- linux-2.6.3-mm4.orig/fs/ext3/iopen.c 2004-03-08 14:58:44.413198848 +0800
+++ linux-2.6.3-mm4/fs/ext3/iopen.c 2004-03-08 14:58:44.576174072 +0800
-@@ -0,0 +1,223 @@
-+
-+
+@@ -0,0 +1,218 @@
+/*
+ * linux/fs/ext3/iopen.c
+ *
+ * Special support for open by inode number
+ *
+ * Copyright (C) 2001 by Theodore Ts'o (tytso@alum.mit.edu).
-+ *
++ *
+ * This file may be redistributed under the terms of the GNU General
+ * Public License.
+ */
+/*
+ * This implements looking up an inode by number.
+ */
-+static struct dentry *iopen_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd)
++static struct dentry *iopen_lookup(struct inode *dir, struct dentry *dentry,
++ struct nameidata *nd)
+{
+ struct inode * inode;
+ unsigned long ino;
-+ struct list_head *lp;
-+ struct dentry *alternate;
++ struct list_head *lp;
++ struct dentry *alternate;
+ char buf[IOPEN_NAME_LEN];
+
+ if (dentry->d_name.len >= IOPEN_NAME_LEN)
+ else
+ ino = simple_strtoul(buf, 0, 0);
+
-+ if ((ino != EXT3_ROOT_INO &&
-+ //ino != EXT3_ACL_IDX_INO &&
-+ //ino != EXT3_ACL_DATA_INO &&
-+ ino < EXT3_FIRST_INO(dir->i_sb)) ||
++ if ((ino != EXT3_ROOT_INO && ino < EXT3_FIRST_INO(dir->i_sb)) ||
+ ino > le32_to_cpu(EXT3_SB(dir->i_sb)->s_es->s_inodes_count))
+ return ERR_PTR(-ENOENT);
+
+ return ERR_PTR(-ENOENT);
+ }
+
-+ /* preferrably return a connected dentry */
-+ spin_lock(&dcache_lock);
-+ list_for_each(lp, &inode->i_dentry) {
-+ alternate = list_entry(lp, struct dentry, d_alias);
-+ assert(!(alternate->d_flags & DCACHE_DISCONNECTED));
-+ }
-+
-+ if (!list_empty(&inode->i_dentry)) {
-+ alternate = list_entry(inode->i_dentry.next,
-+ struct dentry, d_alias);
-+ dget_locked(alternate);
-+ alternate->d_vfs_flags |= DCACHE_REFERENCED;
-+ iput(inode);
-+ spin_unlock(&dcache_lock);
-+ return alternate;
-+ }
-+ dentry->d_flags |= DCACHE_DISCONNECTED;
-+ spin_unlock(&dcache_lock);
++ /* preferrably return a connected dentry */
++ spin_lock(&dcache_lock);
++ list_for_each(lp, &inode->i_dentry) {
++ alternate = list_entry(lp, struct dentry, d_alias);
++ assert(!(alternate->d_flags & DCACHE_DISCONNECTED));
++ }
++
++ if (!list_empty(&inode->i_dentry)) {
++ alternate = list_entry(inode->i_dentry.next,
++ struct dentry, d_alias);
++ dget_locked(alternate);
++ alternate->d_vfs_flags |= DCACHE_REFERENCED;
++ iput(inode);
++ spin_unlock(&dcache_lock);
++ return alternate;
++ }
++ dentry->d_flags |= DCACHE_DISCONNECTED;
++ spin_unlock(&dcache_lock);
+
+ d_add(dentry, inode);
+ return NULL;
+{
+ const unsigned char *old_name, *new_name;
+
-+ memcpy(dentry->d_iname, target->d_iname, DNAME_INLINE_LEN);
++ memcpy(dentry->d_iname, target->d_iname, DNAME_INLINE_LEN);
+ old_name = target->d_name.name;
+ new_name = dentry->d_name.name;
+ if (old_name == target->d_iname)
+
+struct dentry *iopen_connect_dentry(struct dentry *de, struct inode *inode)
+{
-+ struct dentry *tmp, *goal = NULL;
-+ struct list_head *lp;
-+
-+ /* preferrably return a connected dentry */
-+ spin_lock(&dcache_lock);
-+ /* verify this dentry is really new */
-+ assert(!de->d_inode);
-+ assert(list_empty(&de->d_subdirs));
-+ assert(list_empty(&de->d_alias));
-+
-+
-+ list_for_each(lp, &inode->i_dentry) {
-+ tmp = list_entry(lp, struct dentry, d_alias);
-+ if (tmp->d_flags & DCACHE_DISCONNECTED) {
-+ assert(tmp->d_alias.next == &inode->i_dentry);
-+ assert(tmp->d_alias.prev == &inode->i_dentry);
-+ goal = tmp;
-+ dget_locked(goal);
-+ break;
-+ }
-+ }
-+ spin_unlock(&dcache_lock);
-+
-+ if (!goal)
-+ return NULL;
-+
-+ goal->d_flags &= ~DCACHE_DISCONNECTED;
++ struct dentry *tmp, *goal = NULL;
++ struct list_head *lp;
++
++ /* preferrably return a connected dentry */
++ spin_lock(&dcache_lock);
++ /* verify this dentry is really new */
++ assert(!de->d_inode);
++ assert(list_empty(&de->d_subdirs));
++ assert(list_empty(&de->d_alias));
++
++ list_for_each(lp, &inode->i_dentry) {
++ tmp = list_entry(lp, struct dentry, d_alias);
++ if (tmp->d_flags & DCACHE_DISCONNECTED) {
++ assert(tmp->d_alias.next == &inode->i_dentry);
++ assert(tmp->d_alias.prev == &inode->i_dentry);
++ goal = tmp;
++ dget_locked(goal);
++ break;
++ }
++ }
++ spin_unlock(&dcache_lock);
++
++ if (!goal)
++ return NULL;
++
++ goal->d_flags &= ~DCACHE_DISCONNECTED;
+ d_rehash(de);
+ d_move(goal, de);
+
-+ return goal;
++ return goal;
+}
+
+/*
+
+ inode = iget(dir->i_sb, EXT3_BAD_INO);
+
-+ if (!inode)
++ if (!inode)
+ return 0;
+ d_add(dentry, inode);
+ return 1;
+ EXT3_I(inode)->i_dtime = 0;
+ inode->i_blksize = PAGE_SIZE; /* This is the optimal IO size
+ * (for stat), not the fs block
-+ * size */
++ * size */
+ inode->i_blocks = 0;
+ inode->i_version = 1;
+ inode->i_generation = 0;
+ * iopen.h
+ *
+ * Special support for opening files by inode number.
-+ *
++ *
+ * Copyright (C) 2001 by Theodore Ts'o (tytso@alum.mit.edu).
-+ *
++ *
+ * This file may be redistributed under the terms of the GNU General
+ * Public License.
+ */
#endif
+struct dentry *iopen_connect_dentry(struct dentry *de, struct inode *inode);
-+
++
static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd)
{
struct inode * inode;
struct ext3_dir_entry_2 * de;
struct buffer_head * bh;
-+ struct dentry *alternate = NULL;
++ struct dentry *alternate = NULL;
if (dentry->d_name.len > EXT3_NAME_LEN)
return ERR_PTR(-ENAMETOOLONG);
+ * Bruce Fields <bfields@umich.edu>
+ * Copyright (c) 2002 The Regents of the Unviersity of Michigan
+ *
-+ * $Id: linux-2.6.3-CITI_NFS4_ALL.patch,v 1.2 2004/03/17 01:04:13 nic Exp $
++ * Id: linux-2.6.3-CITI_NFS4_ALL.patch,v 1.2.4.1 2004/03/17 23:55:23 adilger Exp $
+ *
+ */
+
--- /dev/null Fri Aug 30 17:31:37 2002
+++ linux-2.4.18-18.8.0-l12-braam/include/linux/lustre_version.h Thu Feb 13 07:58:33 2003
@@ -0,0 +1 @@
-+#define LUSTRE_KERNEL_VERSION 32
++#define LUSTRE_KERNEL_VERSION 34
_
+ &dentry->d_name, 0, NULL);
+ d_invalidate(dentry);
+ dput(dentry);
-+ if (IS_ERR(new)) {
++ if (IS_ERR(new)) {
+ err = PTR_ERR(new);
+ break;
+ }
+ &dentry->d_name, 0, NULL);
+ d_invalidate(dentry);
+ dput(dentry);
-+ if (IS_ERR(new)) {
++ if (IS_ERR(new)) {
+ err = PTR_ERR(new);
+ break;
+ }
+ &dentry->d_name, 0, NULL);
+ d_invalidate(dentry);
+ dput(dentry);
-+ if (IS_ERR(new)) {
++ if (IS_ERR(new)) {
+ err = PTR_ERR(new);
+ break;
+ }
kernel/ksyms.c | 1
13 files changed, 591 insertions(+), 133 deletions(-)
---- linux-2.4.20-hp4-pnnl13/fs/exec.c~vfs_intent-2.4.20-hp 2003-09-13 15:19:27.000000000 +0400
-+++ linux-2.4.20-hp4-pnnl13-alexey/fs/exec.c 2003-09-14 17:33:51.000000000 +0400
-@@ -116,8 +116,10 @@ asmlinkage long sys_uselib(const char *
+Index: linux/fs/exec.c
+===================================================================
+--- linux.orig/fs/exec.c Wed Mar 17 13:00:38 2004
++++ linux/fs/exec.c Wed Mar 17 13:11:25 2004
+@@ -115,8 +115,10 @@
struct file * file;
struct nameidata nd;
int error;
if (error)
goto out;
-@@ -129,7 +131,8 @@ asmlinkage long sys_uselib(const char *
+@@ -128,7 +130,8 @@
if (error)
goto exit;
error = PTR_ERR(file);
if (IS_ERR(file))
goto out;
-@@ -372,8 +375,10 @@ struct file *open_exec(const char *name)
+@@ -371,8 +374,10 @@
struct inode *inode;
struct file *file;
int err = 0;
file = ERR_PTR(err);
if (!err) {
inode = nd.dentry->d_inode;
-@@ -385,7 +390,8 @@ struct file *open_exec(const char *name)
+@@ -384,7 +389,8 @@
err = -EACCES;
file = ERR_PTR(err);
if (!err) {
if (!IS_ERR(file)) {
err = deny_write_access(file);
if (err) {
-@@ -397,6 +403,7 @@ out:
+@@ -396,6 +402,7 @@
return file;
}
}
path_release(&nd);
}
goto out;
-@@ -1128,7 +1135,7 @@ int do_coredump(long signr, struct pt_re
+@@ -1120,7 +1127,7 @@
goto close_fail;
if (!file->f_op->write)
goto close_fail;
goto close_fail;
retval = binfmt->core_dump(signr, regs, file);
---- linux-2.4.20-hp4-pnnl13/fs/dcache.c~vfs_intent-2.4.20-hp 2002-11-29 02:53:15.000000000 +0300
-+++ linux-2.4.20-hp4-pnnl13-alexey/fs/dcache.c 2003-09-14 17:33:51.000000000 +0400
-@@ -181,6 +181,13 @@ int d_invalidate(struct dentry * dentry)
+Index: linux/fs/dcache.c
+===================================================================
+--- linux.orig/fs/dcache.c Thu Nov 28 18:53:15 2002
++++ linux/fs/dcache.c Wed Mar 17 13:11:25 2004
+@@ -181,6 +181,13 @@
spin_unlock(&dcache_lock);
return 0;
}
/*
* Check whether to do a partial shrink_dcache
* to get rid of unused child entries.
-@@ -830,13 +837,19 @@ void d_delete(struct dentry * dentry)
+@@ -830,13 +837,19 @@
* Adds a dentry to the hash according to its name.
*/
}
#define do_switch(x,y) do { \
---- linux-2.4.20-hp4-pnnl13/fs/namespace.c~vfs_intent-2.4.20-hp 2002-11-29 02:53:15.000000000 +0300
-+++ linux-2.4.20-hp4-pnnl13-alexey/fs/namespace.c 2003-09-14 17:33:51.000000000 +0400
-@@ -99,6 +99,7 @@ static void detach_mnt(struct vfsmount *
+Index: linux/fs/namespace.c
+===================================================================
+--- linux.orig/fs/namespace.c Thu Nov 28 18:53:15 2002
++++ linux/fs/namespace.c Wed Mar 17 13:11:25 2004
+@@ -99,6 +99,7 @@
{
old_nd->dentry = mnt->mnt_mountpoint;
old_nd->mnt = mnt->mnt_parent;
mnt->mnt_parent = mnt;
mnt->mnt_mountpoint = mnt->mnt_root;
list_del_init(&mnt->mnt_child);
-@@ -110,6 +111,7 @@ static void attach_mnt(struct vfsmount *
+@@ -110,6 +111,7 @@
{
mnt->mnt_parent = mntget(nd->mnt);
mnt->mnt_mountpoint = dget(nd->dentry);
list_add(&mnt->mnt_hash, mount_hashtable+hash(nd->mnt, nd->dentry));
list_add(&mnt->mnt_child, &nd->mnt->mnt_mounts);
nd->dentry->d_mounted++;
-@@ -485,14 +487,17 @@ static int do_loopback(struct nameidata
+@@ -485,14 +487,17 @@
{
struct nameidata old_nd;
struct vfsmount *mnt = NULL;
down_write(¤t->namespace->sem);
err = -EINVAL;
-@@ -515,6 +520,7 @@ static int do_loopback(struct nameidata
+@@ -515,6 +520,7 @@
}
up_write(¤t->namespace->sem);
path_release(&old_nd);
return err;
}
-@@ -698,6 +704,7 @@ long do_mount(char * dev_name, char * di
+@@ -698,6 +704,7 @@
unsigned long flags, void *data_page)
{
struct nameidata nd;
int retval = 0;
int mnt_flags = 0;
-@@ -722,10 +729,11 @@ long do_mount(char * dev_name, char * di
+@@ -722,10 +729,11 @@
flags &= ~(MS_NOSUID|MS_NOEXEC|MS_NODEV);
/* ... and get the mountpoint */
if (flags & MS_REMOUNT)
retval = do_remount(&nd, flags & ~MS_REMOUNT, mnt_flags,
data_page);
-@@ -736,6 +744,8 @@ long do_mount(char * dev_name, char * di
+@@ -736,6 +744,8 @@
else
retval = do_add_mount(&nd, type_page, flags, mnt_flags,
dev_name, data_page);
path_release(&nd);
return retval;
}
-@@ -901,6 +911,8 @@ asmlinkage long sys_pivot_root(const cha
+@@ -901,6 +911,8 @@
{
struct vfsmount *tmp;
struct nameidata new_nd, old_nd, parent_nd, root_parent, user_nd;
int error;
if (!capable(CAP_SYS_ADMIN))
-@@ -908,14 +920,14 @@ asmlinkage long sys_pivot_root(const cha
+@@ -908,14 +920,14 @@
lock_kernel();
if (error)
goto out1;
-@@ -970,8 +982,10 @@ out2:
+@@ -970,8 +982,10 @@
up(&old_nd.dentry->d_inode->i_zombie);
up_write(¤t->namespace->sem);
path_release(&user_nd);
path_release(&new_nd);
out0:
unlock_kernel();
---- linux-2.4.20-hp4-pnnl13/fs/namei.c~vfs_intent-2.4.20-hp 2003-09-13 15:19:23.000000000 +0400
-+++ linux-2.4.20-hp4-pnnl13-alexey/fs/namei.c 2003-09-14 17:33:51.000000000 +0400
+Index: linux/fs/namei.c
+===================================================================
+--- linux.orig/fs/namei.c Wed Mar 17 13:00:37 2004
++++ linux/fs/namei.c Wed Mar 17 13:12:31 2004
@@ -94,6 +94,13 @@
* XEmacs seems to be relying on it...
*/
/* In order to reduce some races, while at the same time doing additional
* checking and hopefully speeding things up, we copy filenames to the
* kernel data space before using them..
-@@ -260,10 +267,19 @@ void path_release(struct nameidata *nd)
+@@ -260,10 +267,19 @@
* Internal lookup() using the new generic dcache.
* SMP-safe
*/
if (dentry && dentry->d_op && dentry->d_op->d_revalidate) {
if (!dentry->d_op->d_revalidate(dentry, flags) && !d_invalidate(dentry)) {
dput(dentry);
-@@ -281,11 +297,15 @@ static struct dentry * cached_lookup(str
+@@ -281,11 +297,15 @@
* make sure that nobody added the entry to the dcache in the meantime..
* SMP-safe
*/
down(&dir->i_sem);
/*
* First re-do the cached lookup just in case it was created
-@@ -300,6 +320,9 @@ static struct dentry * real_lookup(struc
+@@ -300,6 +320,9 @@
result = ERR_PTR(-ENOMEM);
if (dentry) {
lock_kernel();
result = dir->i_op->lookup(dir, dentry);
unlock_kernel();
if (result)
-@@ -321,6 +344,15 @@ static struct dentry * real_lookup(struc
+@@ -321,6 +344,15 @@
dput(result);
result = ERR_PTR(-ENOENT);
}
}
return result;
}
-@@ -332,7 +364,8 @@ static struct dentry * real_lookup(struc
+@@ -332,7 +364,8 @@
* Without that kind of total limit, nasty chains of consecutive
* symlinks can cause almost arbitrarily long lookups.
*/
{
int err;
if (current->link_count >= 5)
-@@ -346,10 +379,18 @@ static inline int do_follow_link(struct
+@@ -346,10 +379,18 @@
current->link_count++;
current->total_link_count++;
UPDATE_ATIME(dentry->d_inode);
path_release(nd);
return -ELOOP;
}
-@@ -379,15 +420,26 @@ int follow_up(struct vfsmount **mnt, str
+@@ -379,15 +420,26 @@
return __follow_up(mnt, dentry);
}
dput(*dentry);
mntput(mounted->mnt_parent);
*dentry = dget(mounted->mnt_root);
-@@ -399,7 +451,7 @@ static inline int __follow_down(struct v
+@@ -399,7 +451,7 @@
int follow_down(struct vfsmount **mnt, struct dentry **dentry)
{
}
static inline void follow_dotdot(struct nameidata *nd)
-@@ -435,7 +487,7 @@ static inline void follow_dotdot(struct
+@@ -435,7 +487,7 @@
mntput(nd->mnt);
nd->mnt = parent;
}
;
}
-@@ -447,7 +499,8 @@ static inline void follow_dotdot(struct
+@@ -447,7 +499,8 @@
*
* We expect 'base' to be positive and a directory.
*/
{
struct dentry *dentry;
struct inode *inode;
-@@ -520,15 +573,15 @@ int link_path_walk(const char * name, st
+@@ -520,15 +573,15 @@
break;
}
/* This does the actual lookups.. */
;
err = -ENOENT;
-@@ -540,7 +593,7 @@ int link_path_walk(const char * name, st
+@@ -540,7 +593,7 @@
goto out_dput;
if (inode->i_op->follow_link) {
dput(dentry);
if (err)
goto return_err;
-@@ -556,7 +609,7 @@ int link_path_walk(const char * name, st
+@@ -556,7 +609,7 @@
nd->dentry = dentry;
}
err = -ENOTDIR;
break;
continue;
/* here ends the main loop */
-@@ -583,19 +636,19 @@ last_component:
+@@ -583,19 +636,19 @@
if (err < 0)
break;
}
dput(dentry);
if (err)
goto return_err;
-@@ -609,7 +662,8 @@ last_component:
+@@ -609,7 +662,8 @@
goto no_inode;
if (lookup_flags & LOOKUP_DIRECTORY) {
err = -ENOTDIR;
break;
}
goto return_base;
-@@ -633,6 +687,25 @@ return_reval:
+@@ -633,6 +687,27 @@
* Check the cached dentry for staleness.
*/
dentry = nd->dentry;
+ &dentry->d_name, 0, NULL);
+ d_invalidate(dentry);
+ dput(dentry);
-+ if (IS_ERR(new)) {
++ if (IS_ERR(new)) {
+ err = PTR_ERR(new);
+ break;
+ }
+ nd->dentry = new;
+ }
++ if (!nd->dentry->d_inode)
++ goto no_inode;
+ } else
if (dentry && dentry->d_op && dentry->d_op->d_revalidate) {
err = -ESTALE;
if (!dentry->d_op->d_revalidate(dentry, 0)) {
-@@ -646,15 +719,28 @@ out_dput:
+@@ -646,15 +721,28 @@
dput(dentry);
break;
}
}
/* SMP-safe */
-@@ -739,6 +825,17 @@ walk_init_root(const char *name, struct
+@@ -739,6 +827,17 @@
}
/* SMP-safe */
int path_lookup(const char *path, unsigned flags, struct nameidata *nd)
{
int error = 0;
-@@ -753,6 +850,7 @@ int path_init(const char *name, unsigned
+@@ -753,6 +852,7 @@
{
nd->last_type = LAST_ROOT; /* if there are only slashes... */
nd->flags = flags;
if (*name=='/')
return walk_init_root(name,nd);
read_lock(¤t->fs->lock);
-@@ -767,7 +865,8 @@ int path_init(const char *name, unsigned
+@@ -767,7 +867,8 @@
* needs parent already locked. Doesn't follow mounts.
* SMP-safe.
*/
{
struct dentry * dentry;
struct inode *inode;
-@@ -790,13 +889,16 @@ struct dentry * lookup_hash(struct qstr
+@@ -790,13 +891,16 @@
goto out;
}
dentry = inode->i_op->lookup(inode, new);
unlock_kernel();
if (!dentry)
-@@ -808,6 +910,12 @@ out:
+@@ -808,6 +912,12 @@
return dentry;
}
/* SMP-safe */
struct dentry * lookup_one_len(const char * name, struct dentry * base, int len)
{
-@@ -829,7 +937,7 @@ struct dentry * lookup_one_len(const cha
+@@ -829,7 +939,7 @@
}
this.hash = end_name_hash(hash);
access:
return ERR_PTR(-EACCES);
}
-@@ -860,6 +968,23 @@ int __user_walk(const char *name, unsign
+@@ -860,6 +970,23 @@
return err;
}
/*
* It's inline, so penalty for filesystems that don't use sticky bit is
* minimal.
-@@ -955,7 +1080,8 @@ static inline int lookup_flags(unsigned
+@@ -955,7 +1082,8 @@
return retval;
}
{
int error;
-@@ -968,12 +1094,15 @@ int vfs_create(struct inode *dir, struct
+@@ -968,12 +1096,15 @@
goto exit_lock;
error = -EACCES; /* shouldn't it be ENOSYS? */
unlock_kernel();
exit_lock:
up(&dir->i_zombie);
-@@ -982,6 +1111,11 @@ exit_lock:
+@@ -982,6 +1113,11 @@
return error;
}
/*
* open_namei()
*
-@@ -996,7 +1130,8 @@ exit_lock:
+@@ -996,7 +1132,8 @@
* for symlinks (where the permissions are checked later).
* SMP-safe
*/
{
int acc_mode, error = 0;
struct inode *inode;
-@@ -1006,11 +1141,14 @@ int open_namei(const char * pathname, in
+@@ -1006,11 +1143,14 @@
acc_mode = ACC_MODE(flag);
if (error)
return error;
dentry = nd->dentry;
-@@ -1020,6 +1158,10 @@ int open_namei(const char * pathname, in
+@@ -1020,6 +1160,10 @@
/*
* Create - we need to know the parent.
*/
error = path_lookup(pathname, LOOKUP_PARENT, nd);
if (error)
return error;
-@@ -1035,7 +1177,7 @@ int open_namei(const char * pathname, in
+@@ -1035,7 +1179,7 @@
dir = nd->dentry;
down(&dir->d_inode->i_sem);
do_last:
error = PTR_ERR(dentry);
-@@ -1044,11 +1186,12 @@ do_last:
+@@ -1044,11 +1188,12 @@
goto exit;
}
up(&dir->d_inode->i_sem);
dput(nd->dentry);
nd->dentry = dentry;
-@@ -1073,7 +1216,7 @@ do_last:
+@@ -1073,7 +1218,7 @@
error = -ELOOP;
if (flag & O_NOFOLLOW)
goto exit_dput;
}
error = -ENOENT;
if (!dentry->d_inode)
-@@ -1152,7 +1295,7 @@ ok:
+@@ -1152,7 +1297,7 @@
if (!error) {
DQUOT_INIT(inode);
}
put_write_access(inode);
if (error)
-@@ -1164,8 +1307,10 @@ ok:
+@@ -1164,8 +1309,10 @@
return 0;
exit_dput:
path_release(nd);
return error;
-@@ -1184,7 +1329,16 @@ do_link:
+@@ -1184,7 +1331,16 @@
* are done. Procfs-like symlinks just set LAST_BIND.
*/
UPDATE_ATIME(dentry->d_inode);
dput(dentry);
if (error)
return error;
-@@ -1206,13 +1360,20 @@ do_link:
+@@ -1206,13 +1362,20 @@
}
dir = nd->dentry;
down(&dir->d_inode->i_sem);
{
struct dentry *dentry;
-@@ -1220,7 +1381,7 @@ static struct dentry *lookup_create(stru
+@@ -1220,7 +1383,7 @@
dentry = ERR_PTR(-EEXIST);
if (nd->last_type != LAST_NORM)
goto fail;
if (IS_ERR(dentry))
goto fail;
if (!is_dir && nd->last.name[nd->last.len] && !dentry->d_inode)
-@@ -1276,7 +1437,16 @@ asmlinkage long sys_mknod(const char * f
+@@ -1276,7 +1439,20 @@
error = path_lookup(tmp, LOOKUP_PARENT, &nd);
if (error)
goto out;
- dentry = lookup_create(&nd, 0);
+
++ if (nd.last_type != LAST_NORM) {
++ error = -EEXIST;
++ goto out2;
++ }
+ if (nd.dentry->d_inode->i_op->mknod_raw) {
+ struct inode_operations *op = nd.dentry->d_inode->i_op;
+ error = op->mknod_raw(&nd, mode, dev);
error = PTR_ERR(dentry);
if (!IS_POSIXACL(nd.dentry->d_inode))
-@@ -1298,6 +1468,7 @@ asmlinkage long sys_mknod(const char * f
+@@ -1298,6 +1474,7 @@
dput(dentry);
}
up(&nd.dentry->d_inode->i_sem);
path_release(&nd);
out:
putname(tmp);
-@@ -1345,7 +1516,14 @@ asmlinkage long sys_mkdir(const char * p
+@@ -1345,7 +1522,18 @@
error = path_lookup(tmp, LOOKUP_PARENT, &nd);
if (error)
goto out;
- dentry = lookup_create(&nd, 1);
++ if (nd.last_type != LAST_NORM) {
++ error = -EEXIST;
++ goto out2;
++ }
+ if (nd.dentry->d_inode->i_op->mkdir_raw) {
+ struct inode_operations *op = nd.dentry->d_inode->i_op;
+ error = op->mkdir_raw(&nd, mode);
error = PTR_ERR(dentry);
if (!IS_ERR(dentry)) {
if (!IS_POSIXACL(nd.dentry->d_inode))
-@@ -1354,6 +1532,7 @@ asmlinkage long sys_mkdir(const char * p
+@@ -1354,6 +1542,7 @@
dput(dentry);
}
up(&nd.dentry->d_inode->i_sem);
path_release(&nd);
out:
putname(tmp);
-@@ -1454,8 +1633,16 @@ asmlinkage long sys_rmdir(const char * p
+@@ -1454,8 +1643,16 @@
error = -EBUSY;
goto exit1;
}
error = PTR_ERR(dentry);
if (!IS_ERR(dentry)) {
error = vfs_rmdir(nd.dentry->d_inode, dentry);
-@@ -1513,8 +1700,15 @@ asmlinkage long sys_unlink(const char *
+@@ -1513,8 +1710,15 @@
error = -EISDIR;
if (nd.last_type != LAST_NORM)
goto exit1;
error = PTR_ERR(dentry);
if (!IS_ERR(dentry)) {
/* Why not before? Because we want correct error value */
-@@ -1581,15 +1775,23 @@ asmlinkage long sys_symlink(const char *
+@@ -1581,15 +1785,27 @@
error = path_lookup(to, LOOKUP_PARENT, &nd);
if (error)
goto out;
- dentry = lookup_create(&nd, 0);
++ if (nd.last_type != LAST_NORM) {
++ error = -EEXIST;
++ goto out2;
++ }
+ if (nd.dentry->d_inode->i_op->symlink_raw) {
+ struct inode_operations *op = nd.dentry->d_inode->i_op;
+ error = op->symlink_raw(&nd, from);
putname(to);
}
putname(from);
-@@ -1665,7 +1867,14 @@ asmlinkage long sys_link(const char * ol
+@@ -1665,7 +1881,18 @@
error = -EXDEV;
if (old_nd.mnt != nd.mnt)
goto out_release;
- new_dentry = lookup_create(&nd, 0);
++ if (nd.last_type != LAST_NORM) {
++ error = -EEXIST;
++ goto out_release;
++ }
+ if (nd.dentry->d_inode->i_op->link_raw) {
+ struct inode_operations *op = nd.dentry->d_inode->i_op;
+ error = op->link_raw(&old_nd, &nd);
error = PTR_ERR(new_dentry);
if (!IS_ERR(new_dentry)) {
error = vfs_link(old_nd.dentry, nd.dentry->d_inode, new_dentry);
-@@ -1709,7 +1918,7 @@ exit:
+@@ -1709,7 +1936,7 @@
* locking].
*/
int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
{
int error;
struct inode *target;
-@@ -1788,7 +1997,7 @@ out_unlock:
+@@ -1788,7 +2015,7 @@
}
int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry,
{
int error;
-@@ -1876,9 +2085,18 @@ static inline int do_rename(const char *
+@@ -1876,9 +2103,18 @@
if (newnd.last_type != LAST_NORM)
goto exit2;
error = PTR_ERR(old_dentry);
if (IS_ERR(old_dentry))
goto exit3;
-@@ -1894,16 +2112,16 @@ static inline int do_rename(const char *
+@@ -1894,16 +2130,16 @@
if (newnd.last.name[newnd.last.len])
goto exit4;
}
dput(new_dentry);
exit4:
dput(old_dentry);
-@@ -1954,20 +2172,28 @@ out:
+@@ -1954,20 +2190,28 @@
}
static inline int
out:
if (current->link_count || res || nd->last_type!=LAST_NORM)
return res;
-@@ -1989,7 +2215,13 @@ fail:
+@@ -1989,7 +2233,13 @@
int vfs_follow_link(struct nameidata *nd, const char *link)
{
}
/* get the link contents into pagecache */
-@@ -2031,7 +2263,7 @@ int page_follow_link(struct dentry *dent
+@@ -2031,7 +2281,7 @@
{
struct page *page = NULL;
char *s = page_getlink(dentry, &page);
if (page) {
kunmap(page);
page_cache_release(page);
---- linux-2.4.20-hp4-pnnl13/fs/open.c~vfs_intent-2.4.20-hp 2002-11-29 02:53:15.000000000 +0300
-+++ linux-2.4.20-hp4-pnnl13-alexey/fs/open.c 2003-09-14 17:33:51.000000000 +0400
+Index: linux/fs/open.c
+===================================================================
+--- linux.orig/fs/open.c Thu Nov 28 18:53:15 2002
++++ linux/fs/open.c Wed Mar 17 13:11:25 2004
@@ -19,6 +19,8 @@
#include <asm/uaccess.h>
int vfs_statfs(struct super_block *sb, struct statfs *buf)
{
-@@ -95,9 +97,10 @@ void fd_install(unsigned int fd, struct
+@@ -95,9 +97,10 @@
write_unlock(&files->file_lock);
}
int error;
struct iattr newattrs;
-@@ -108,7 +111,13 @@ int do_truncate(struct dentry *dentry, l
+@@ -108,7 +111,13 @@
down(&inode->i_sem);
newattrs.ia_size = length;
newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
up(&inode->i_sem);
return error;
}
-@@ -118,12 +127,13 @@ static inline long do_sys_truncate(const
+@@ -118,12 +127,13 @@
struct nameidata nd;
struct inode * inode;
int error;
if (error)
goto out;
inode = nd.dentry->d_inode;
-@@ -163,11 +173,13 @@ static inline long do_sys_truncate(const
+@@ -163,11 +173,13 @@
error = locks_verify_truncate(inode, NULL, length);
if (!error) {
DQUOT_INIT(inode);
path_release(&nd);
out:
return error;
-@@ -215,7 +227,7 @@ static inline long do_sys_ftruncate(unsi
+@@ -215,7 +227,7 @@
error = locks_verify_truncate(inode, file, length);
if (!error)
out_putf:
fput(file);
out:
-@@ -260,11 +272,13 @@ asmlinkage long sys_utime(char * filenam
+@@ -260,11 +272,13 @@
struct inode * inode;
struct iattr newattrs;
error = -EROFS;
if (IS_RDONLY(inode))
goto dput_and_out;
-@@ -279,11 +293,25 @@ asmlinkage long sys_utime(char * filenam
+@@ -279,11 +293,25 @@
goto dput_and_out;
newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
error = notify_change(nd.dentry, &newattrs);
dput_and_out:
path_release(&nd);
-@@ -304,12 +332,14 @@ asmlinkage long sys_utimes(char * filena
+@@ -304,12 +332,14 @@
struct inode * inode;
struct iattr newattrs;
error = -EROFS;
if (IS_RDONLY(inode))
goto dput_and_out;
-@@ -324,7 +354,20 @@ asmlinkage long sys_utimes(char * filena
+@@ -324,7 +354,20 @@
newattrs.ia_atime = times[0].tv_sec;
newattrs.ia_mtime = times[1].tv_sec;
newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
if (current->fsuid != inode->i_uid &&
(error = permission(inode,MAY_WRITE)) != 0)
goto dput_and_out;
-@@ -347,6 +390,7 @@ asmlinkage long sys_access(const char *
+@@ -347,6 +390,7 @@
int old_fsuid, old_fsgid;
kernel_cap_t old_cap;
int res;
if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */
return -EINVAL;
-@@ -364,13 +408,14 @@ asmlinkage long sys_access(const char *
+@@ -364,13 +408,14 @@
else
current->cap_effective = current->cap_permitted;
path_release(&nd);
}
-@@ -385,8 +430,9 @@ asmlinkage long sys_chdir(const char * f
+@@ -385,8 +430,9 @@
{
int error;
struct nameidata nd;
if (error)
goto out;
-@@ -397,6 +443,7 @@ asmlinkage long sys_chdir(const char * f
+@@ -397,6 +443,7 @@
set_fs_pwd(current->fs, nd.mnt, nd.dentry);
dput_and_out:
path_release(&nd);
out:
return error;
-@@ -436,9 +483,10 @@ asmlinkage long sys_chroot(const char *
+@@ -436,9 +483,10 @@
{
int error;
struct nameidata nd;
if (error)
goto out;
-@@ -454,39 +502,56 @@ asmlinkage long sys_chroot(const char *
+@@ -454,39 +502,56 @@
set_fs_altroot();
error = 0;
dput_and_out:
fput(file);
out:
return err;
-@@ -495,30 +560,14 @@ out:
+@@ -495,30 +560,14 @@
asmlinkage long sys_chmod(const char * filename, mode_t mode)
{
struct nameidata nd;
path_release(&nd);
out:
return error;
-@@ -538,6 +587,20 @@ static int chown_common(struct dentry *
+@@ -538,6 +587,20 @@
error = -EROFS;
if (IS_RDONLY(inode))
goto out;
error = -EPERM;
if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
goto out;
-@@ -642,6 +705,7 @@ struct file *filp_open(const char * file
+@@ -642,6 +705,7 @@
{
int namei_flags, error;
struct nameidata nd;
namei_flags = flags;
if ((namei_flags+1) & O_ACCMODE)
-@@ -649,14 +713,15 @@ struct file *filp_open(const char * file
+@@ -649,14 +713,15 @@
if (namei_flags & O_TRUNC)
namei_flags |= 2;
{
struct file * f;
struct inode *inode;
-@@ -693,12 +758,15 @@ struct file *dentry_open(struct dentry *
+@@ -693,12 +758,15 @@
}
if (f->f_op && f->f_op->open) {
return f;
cleanup_all:
-@@ -713,11 +781,17 @@ cleanup_all:
+@@ -713,11 +781,17 @@
cleanup_file:
put_filp(f);
cleanup_dentry:
/*
* Find an empty file descriptor entry, and mark it busy.
*/
---- linux-2.4.20-hp4-pnnl13/fs/stat.c~vfs_intent-2.4.20-hp 2001-09-14 03:04:43.000000000 +0400
-+++ linux-2.4.20-hp4-pnnl13-alexey/fs/stat.c 2003-09-14 17:34:07.000000000 +0400
-@@ -17,10 +17,14 @@
+Index: linux/fs/stat.c
+===================================================================
+--- linux.orig/fs/stat.c Thu Sep 13 19:04:43 2001
++++ linux/fs/stat.c Wed Mar 17 13:12:31 2004
+@@ -17,10 +17,12 @@
* Revalidate the inode. This is required for proper NFS attribute caching.
*/
static __inline__ int
{
struct inode * inode = dentry->d_inode;
- if (inode->i_op && inode->i_op->revalidate)
-+ if (!inode)
-+ return -ENOENT;
+ if (inode->i_op && inode->i_op->revalidate_it)
+ return inode->i_op->revalidate_it(dentry, it);
+ else if (inode->i_op && inode->i_op->revalidate)
return inode->i_op->revalidate(dentry);
return 0;
}
-@@ -135,13 +139,15 @@ static int cp_new_stat(struct inode * in
+@@ -135,13 +137,15 @@
asmlinkage long sys_stat(char * filename, struct __old_kernel_stat * statbuf)
{
struct nameidata nd;
path_release(&nd);
}
return error;
-@@ -151,13 +157,15 @@ asmlinkage long sys_stat(char * filename
+@@ -151,13 +155,15 @@
asmlinkage long sys_newstat(char * filename, struct stat * statbuf)
{
struct nameidata nd;
path_release(&nd);
}
return error;
-@@ -172,13 +180,15 @@ asmlinkage long sys_newstat(char * filen
+@@ -172,13 +178,15 @@
asmlinkage long sys_lstat(char * filename, struct __old_kernel_stat * statbuf)
{
struct nameidata nd;
path_release(&nd);
}
return error;
-@@ -189,13 +199,15 @@ asmlinkage long sys_lstat(char * filenam
+@@ -189,13 +197,15 @@
asmlinkage long sys_newlstat(char * filename, struct stat * statbuf)
{
struct nameidata nd;
path_release(&nd);
}
return error;
-@@ -216,7 +228,7 @@ asmlinkage long sys_fstat(unsigned int f
+@@ -216,7 +226,7 @@
if (f) {
struct dentry * dentry = f->f_dentry;
if (!err)
err = cp_old_stat(dentry->d_inode, statbuf);
fput(f);
-@@ -235,7 +247,7 @@ asmlinkage long sys_newfstat(unsigned in
+@@ -235,7 +245,7 @@
if (f) {
struct dentry * dentry = f->f_dentry;
if (!err)
err = cp_new_stat(dentry->d_inode, statbuf);
fput(f);
-@@ -257,7 +269,7 @@ asmlinkage long sys_readlink(const char
+@@ -257,7 +267,7 @@
error = -EINVAL;
if (inode->i_op && inode->i_op->readlink &&
UPDATE_ATIME(inode);
error = inode->i_op->readlink(nd.dentry, buf, bufsiz);
}
-@@ -333,12 +345,14 @@ asmlinkage long sys_stat64(char * filena
+@@ -333,12 +343,14 @@
{
struct nameidata nd;
int error;
path_release(&nd);
}
return error;
-@@ -348,12 +362,14 @@ asmlinkage long sys_lstat64(char * filen
+@@ -348,12 +360,14 @@
{
struct nameidata nd;
int error;
path_release(&nd);
}
return error;
-@@ -368,7 +384,7 @@ asmlinkage long sys_fstat64(unsigned lon
+@@ -368,7 +382,7 @@
if (f) {
struct dentry * dentry = f->f_dentry;
if (!err)
err = cp_new_stat64(dentry->d_inode, statbuf);
fput(f);
---- linux-2.4.20-hp4-pnnl13/fs/proc/base.c~vfs_intent-2.4.20-hp 2003-09-13 15:19:19.000000000 +0400
-+++ linux-2.4.20-hp4-pnnl13-alexey/fs/proc/base.c 2003-09-14 17:33:51.000000000 +0400
-@@ -481,6 +481,9 @@ static int proc_pid_follow_link(struct d
+Index: linux/fs/proc/base.c
+===================================================================
+--- linux.orig/fs/proc/base.c Wed Mar 17 13:00:35 2004
++++ linux/fs/proc/base.c Wed Mar 17 13:11:25 2004
+@@ -481,6 +481,9 @@
error = inode->u.proc_i.op.proc_get_link(inode, &nd->dentry, &nd->mnt);
nd->last_type = LAST_BIND;
out:
return error;
}
---- linux-2.4.20-hp4-pnnl13/include/linux/dcache.h~vfs_intent-2.4.20-hp 2002-11-29 02:53:15.000000000 +0300
-+++ linux-2.4.20-hp4-pnnl13-alexey/include/linux/dcache.h 2003-09-14 17:33:51.000000000 +0400
+Index: linux/include/linux/dcache.h
+===================================================================
+--- linux.orig/include/linux/dcache.h Thu Nov 28 18:53:15 2002
++++ linux/include/linux/dcache.h Wed Mar 17 13:11:25 2004
@@ -6,6 +6,51 @@
#include <asm/atomic.h>
#include <linux/mount.h>
/*
* linux/include/linux/dcache.h
-@@ -91,8 +136,22 @@ struct dentry_operations {
+@@ -91,8 +136,22 @@
int (*d_delete)(struct dentry *);
void (*d_release)(struct dentry *);
void (*d_iput)(struct dentry *, struct inode *);
/* the dentry parameter passed to d_hash and d_compare is the parent
* directory of the entries to be compared. It is used in case these
* functions need any directory specific information for determining
-@@ -124,6 +183,7 @@ d_iput: no no yes
+@@ -124,6 +183,7 @@
* s_nfsd_free_path semaphore will be down
*/
#define DCACHE_REFERENCED 0x0008 /* Recently used, don't discard. */
extern spinlock_t dcache_lock;
---- linux-2.4.20-hp4-pnnl13/include/linux/fs.h~vfs_intent-2.4.20-hp 2003-09-14 17:33:50.000000000 +0400
-+++ linux-2.4.20-hp4-pnnl13-alexey/include/linux/fs.h 2003-09-14 17:33:51.000000000 +0400
-@@ -73,6 +73,7 @@ extern int leases_enable, dir_notify_ena
+Index: linux/include/linux/fs.h
+===================================================================
+--- linux.orig/include/linux/fs.h Wed Mar 17 13:11:23 2004
++++ linux/include/linux/fs.h Wed Mar 17 13:11:31 2004
+@@ -73,6 +73,7 @@
#define FMODE_READ 1
#define FMODE_WRITE 2
#define READ 0
#define WRITE 1
-@@ -340,6 +341,9 @@ extern void set_bh_page(struct buffer_he
+@@ -340,6 +341,9 @@
#define ATTR_MTIME_SET 256
#define ATTR_FORCE 512 /* Not a change, but a change it */
#define ATTR_ATTR_FLAG 1024
/*
* This is the Inode Attributes structure, used for notify_change(). It
-@@ -474,6 +478,7 @@ struct inode {
+@@ -474,6 +478,7 @@
struct pipe_inode_info *i_pipe;
struct block_device *i_bdev;
struct char_device *i_cdev;
unsigned long i_dnotify_mask; /* Directory notify events */
struct dnotify_struct *i_dnotify; /* for directory notifications */
-@@ -576,6 +581,7 @@ struct file {
+@@ -576,6 +581,7 @@
/* needed for tty driver, and maybe others */
void *private_data;
/* preallocated helper kiobuf to speedup O_DIRECT */
struct kiobuf *f_iobuf;
-@@ -697,6 +703,7 @@ struct nameidata {
+@@ -697,6 +703,7 @@
struct qstr last;
unsigned int flags;
int last_type;
};
/*
-@@ -817,7 +824,8 @@ extern int vfs_symlink(struct inode *, s
+@@ -817,7 +824,8 @@
extern int vfs_link(struct dentry *, struct inode *, struct dentry *);
extern int vfs_rmdir(struct inode *, struct dentry *);
extern int vfs_unlink(struct inode *, struct dentry *);
/*
* File types
-@@ -877,21 +885,32 @@ struct file_operations {
+@@ -877,21 +885,32 @@
struct inode_operations {
int (*create) (struct inode *,struct dentry *,int);
int (*getattr) (struct dentry *, struct iattr *);
int (*setxattr) (struct dentry *, const char *, void *, size_t, int);
ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
-@@ -1088,10 +1107,14 @@ static inline int get_lease(struct inode
+@@ -1088,10 +1107,14 @@
asmlinkage long sys_open(const char *, int, int);
asmlinkage long sys_close(unsigned int); /* yes, it's really unsigned */
extern int filp_close(struct file *, fl_owner_t id);
extern char * getname(const char *);
-@@ -1353,6 +1376,7 @@ typedef int (*read_actor_t)(read_descrip
+@@ -1354,6 +1377,7 @@
extern loff_t default_llseek(struct file *file, loff_t offset, int origin);
extern int FASTCALL(__user_walk(const char *, unsigned, struct nameidata *));
extern int FASTCALL(path_init(const char *, unsigned, struct nameidata *));
extern int FASTCALL(path_walk(const char *, struct nameidata *));
extern int FASTCALL(path_lookup(const char *, unsigned, struct nameidata *));
-@@ -1364,6 +1388,8 @@ extern struct dentry * lookup_one_len(co
+@@ -1365,6 +1389,8 @@
extern struct dentry * lookup_hash(struct qstr *, struct dentry *);
#define user_path_walk(name,nd) __user_walk(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, nd)
#define user_path_walk_link(name,nd) __user_walk(name, LOOKUP_POSITIVE, nd)
+#define user_path_walk_link_it(name,nd,it) __user_walk_it(name, LOOKUP_POSITIVE, nd, it)
extern void inode_init_once(struct inode *);
- extern void iput(struct inode *);
-@@ -1499,6 +1525,8 @@ extern struct file_operations generic_ro
+ extern void _inode_init_once(struct inode *);
+@@ -1503,6 +1529,8 @@
extern int vfs_readlink(struct dentry *, char *, int, const char *);
extern int vfs_follow_link(struct nameidata *, const char *);
extern int page_readlink(struct dentry *, char *, int);
extern int page_follow_link(struct dentry *, struct nameidata *);
extern struct inode_operations page_symlink_inode_operations;
---- linux-2.4.20-hp4-pnnl13/include/linux/fs_struct.h~vfs_intent-2.4.20-hp 2001-07-14 02:10:44.000000000 +0400
-+++ linux-2.4.20-hp4-pnnl13-alexey/include/linux/fs_struct.h 2003-09-14 17:33:51.000000000 +0400
-@@ -34,10 +34,12 @@ static inline void set_fs_root(struct fs
+Index: linux/include/linux/fs_struct.h
+===================================================================
+--- linux.orig/include/linux/fs_struct.h Fri Jul 13 18:10:44 2001
++++ linux/include/linux/fs_struct.h Wed Mar 17 13:11:25 2004
+@@ -34,10 +34,12 @@
write_lock(&fs->lock);
old_root = fs->root;
old_rootmnt = fs->rootmnt;
dput(old_root);
mntput(old_rootmnt);
}
-@@ -57,10 +59,12 @@ static inline void set_fs_pwd(struct fs_
+@@ -57,10 +59,12 @@
write_lock(&fs->lock);
old_pwd = fs->pwd;
old_pwdmnt = fs->pwdmnt;
dput(old_pwd);
mntput(old_pwdmnt);
}
---- linux-2.4.20-hp4-pnnl13/kernel/ksyms.c~vfs_intent-2.4.20-hp 2003-09-14 17:33:50.000000000 +0400
-+++ linux-2.4.20-hp4-pnnl13-alexey/kernel/ksyms.c 2003-09-14 17:33:51.000000000 +0400
-@@ -296,6 +296,7 @@ EXPORT_SYMBOL(read_cache_page);
+Index: linux/kernel/ksyms.c
+===================================================================
+--- linux.orig/kernel/ksyms.c Wed Mar 17 13:11:23 2004
++++ linux/kernel/ksyms.c Wed Mar 17 13:11:25 2004
+@@ -315,6 +315,7 @@
EXPORT_SYMBOL(set_page_dirty);
EXPORT_SYMBOL(vfs_readlink);
EXPORT_SYMBOL(vfs_follow_link);
EXPORT_SYMBOL(page_readlink);
EXPORT_SYMBOL(page_follow_link);
EXPORT_SYMBOL(page_symlink_inode_operations);
---- linux-2.4.20-hp4-pnnl13/kernel/fork.c~vfs_intent-2.4.20-hp 2003-09-13 15:19:27.000000000 +0400
-+++ linux-2.4.20-hp4-pnnl13-alexey/kernel/fork.c 2003-09-14 17:33:51.000000000 +0400
-@@ -388,10 +388,13 @@ static inline struct fs_struct *__copy_f
+Index: linux/kernel/fork.c
+===================================================================
+--- linux.orig/kernel/fork.c Wed Mar 17 13:00:38 2004
++++ linux/kernel/fork.c Wed Mar 17 13:11:25 2004
+@@ -387,10 +387,13 @@
fs->umask = old->umask;
read_lock(&old->lock);
fs->rootmnt = mntget(old->rootmnt);
fs->altrootmnt = mntget(old->altrootmnt);
fs->altroot = dget(old->altroot);
} else {
---- linux-2.4.20-hp4-pnnl13/kernel/exit.c~vfs_intent-2.4.20-hp 2003-09-13 15:19:27.000000000 +0400
-+++ linux-2.4.20-hp4-pnnl13-alexey/kernel/exit.c 2003-09-14 17:33:51.000000000 +0400
-@@ -239,11 +239,14 @@ static inline void __put_fs_struct(struc
+Index: linux/kernel/exit.c
+===================================================================
+--- linux.orig/kernel/exit.c Wed Mar 17 13:00:38 2004
++++ linux/kernel/exit.c Wed Mar 17 13:11:25 2004
+@@ -239,11 +239,14 @@
{
/* No need to hold fs->lock if we are killing it */
if (atomic_dec_and_test(&fs->count)) {
dput(fs->altroot);
mntput(fs->altrootmnt);
}
-
-_
kernel/ksyms.c | 1
13 files changed, 578 insertions(+), 129 deletions(-)
---- linux-2.4.20-rh-20.9/fs/dcache.c~vfs_intent-2.4.20-rh 2003-09-13 19:34:35.000000000 +0400
-+++ linux-2.4.20-rh-20.9-alexey/fs/dcache.c 2003-09-14 17:34:53.000000000 +0400
-@@ -186,6 +186,13 @@ int d_invalidate(struct dentry * dentry)
+Index: linux-2.4.20/fs/dcache.c
+===================================================================
+--- linux-2.4.20.orig/fs/dcache.c Wed Mar 17 13:57:05 2004
++++ linux-2.4.20/fs/dcache.c Wed Mar 17 13:57:11 2004
+@@ -186,6 +186,13 @@
spin_unlock(&dcache_lock);
return 0;
}
/*
* Check whether to do a partial shrink_dcache
* to get rid of unused child entries.
-@@ -841,13 +848,19 @@ void d_delete(struct dentry * dentry)
+@@ -841,13 +848,19 @@
* Adds a dentry to the hash according to its name.
*/
}
#define do_switch(x,y) do { \
---- linux-2.4.20-rh-20.9/fs/exec.c~vfs_intent-2.4.20-rh 2003-09-13 19:34:35.000000000 +0400
-+++ linux-2.4.20-rh-20.9-alexey/fs/exec.c 2003-09-14 17:34:53.000000000 +0400
-@@ -114,8 +114,10 @@ asmlinkage long sys_uselib(const char *
+Index: linux-2.4.20/fs/exec.c
+===================================================================
+--- linux-2.4.20.orig/fs/exec.c Wed Mar 17 13:57:05 2004
++++ linux-2.4.20/fs/exec.c Wed Mar 17 13:57:11 2004
+@@ -114,8 +114,10 @@
struct file * file;
struct nameidata nd;
int error;
if (error)
goto out;
-@@ -127,7 +129,8 @@ asmlinkage long sys_uselib(const char *
+@@ -127,7 +129,8 @@
if (error)
goto exit;
error = PTR_ERR(file);
if (IS_ERR(file))
goto out;
-@@ -382,8 +385,10 @@ struct file *open_exec(const char *name)
+@@ -382,8 +385,10 @@
struct inode *inode;
struct file *file;
int err = 0;
file = ERR_PTR(err);
if (!err) {
inode = nd.dentry->d_inode;
-@@ -395,7 +400,8 @@ struct file *open_exec(const char *name)
+@@ -395,7 +400,8 @@
err = -EACCES;
file = ERR_PTR(err);
if (!err) {
if (!IS_ERR(file)) {
err = deny_write_access(file);
if (err) {
-@@ -407,6 +413,7 @@ out:
+@@ -407,6 +413,7 @@
return file;
}
}
path_release(&nd);
}
goto out;
-@@ -1296,7 +1303,7 @@ int do_coredump(long signr, int exit_cod
+@@ -1296,7 +1303,7 @@
goto close_fail;
if (!file->f_op->write)
goto close_fail;
goto close_fail;
retval = binfmt->core_dump(signr, regs, file);
---- linux-2.4.20-rh-20.9/fs/namei.c~vfs_intent-2.4.20-rh 2003-09-13 19:34:25.000000000 +0400
-+++ linux-2.4.20-rh-20.9-alexey/fs/namei.c 2003-09-14 17:34:53.000000000 +0400
+Index: linux-2.4.20/fs/namei.c
+===================================================================
+--- linux-2.4.20.orig/fs/namei.c Wed Mar 17 13:57:03 2004
++++ linux-2.4.20/fs/namei.c Wed Mar 17 13:58:01 2004
@@ -94,6 +94,13 @@
* XEmacs seems to be relying on it...
*/
/* In order to reduce some races, while at the same time doing additional
* checking and hopefully speeding things up, we copy filenames to the
* kernel data space before using them..
-@@ -260,10 +267,19 @@ void path_release(struct nameidata *nd)
+@@ -260,10 +267,19 @@
* Internal lookup() using the new generic dcache.
* SMP-safe
*/
if (dentry && dentry->d_op && dentry->d_op->d_revalidate) {
if (!dentry->d_op->d_revalidate(dentry, flags) && !d_invalidate(dentry)) {
dput(dentry);
-@@ -281,11 +297,15 @@ static struct dentry * cached_lookup(str
+@@ -281,11 +297,15 @@
* make sure that nobody added the entry to the dcache in the meantime..
* SMP-safe
*/
down(&dir->i_sem);
/*
* First re-do the cached lookup just in case it was created
-@@ -300,6 +320,9 @@ static struct dentry * real_lookup(struc
+@@ -300,6 +320,9 @@
result = ERR_PTR(-ENOMEM);
if (dentry) {
lock_kernel();
result = dir->i_op->lookup(dir, dentry);
unlock_kernel();
if (result)
-@@ -321,6 +344,15 @@ static struct dentry * real_lookup(struc
+@@ -321,6 +344,15 @@
dput(result);
result = ERR_PTR(-ENOENT);
}
}
return result;
}
-@@ -334,7 +366,8 @@ int max_recursive_link = 5;
+@@ -334,7 +366,8 @@
* Without that kind of total limit, nasty chains of consecutive
* symlinks can cause almost arbitrarily long lookups.
*/
{
int err;
if (current->link_count >= max_recursive_link)
-@@ -348,10 +381,18 @@ static inline int do_follow_link(struct
+@@ -348,10 +381,18 @@
current->link_count++;
current->total_link_count++;
UPDATE_ATIME(dentry->d_inode);
path_release(nd);
return -ELOOP;
}
-@@ -381,15 +422,26 @@ int follow_up(struct vfsmount **mnt, str
+@@ -381,15 +422,26 @@
return __follow_up(mnt, dentry);
}
dput(*dentry);
mntput(mounted->mnt_parent);
*dentry = dget(mounted->mnt_root);
-@@ -401,7 +453,7 @@ static inline int __follow_down(struct v
+@@ -401,7 +453,7 @@
int follow_down(struct vfsmount **mnt, struct dentry **dentry)
{
}
static inline void follow_dotdot(struct nameidata *nd)
-@@ -437,7 +489,7 @@ static inline void follow_dotdot(struct
+@@ -437,7 +489,7 @@
mntput(nd->mnt);
nd->mnt = parent;
}
;
}
-@@ -449,7 +501,8 @@ static inline void follow_dotdot(struct
+@@ -449,7 +501,8 @@
*
* We expect 'base' to be positive and a directory.
*/
{
struct dentry *dentry;
struct inode *inode;
-@@ -526,19 +579,18 @@ int link_path_walk(const char * name, st
+@@ -526,19 +579,18 @@
break;
}
/* This does the actual lookups.. */
err = -ENOENT;
inode = dentry->d_inode;
-@@ -549,7 +601,7 @@ int link_path_walk(const char * name, st
+@@ -549,7 +601,7 @@
goto out_dput;
if (inode->i_op->follow_link) {
dput(dentry);
if (err)
goto return_err;
-@@ -565,7 +617,7 @@ int link_path_walk(const char * name, st
+@@ -565,7 +617,7 @@
nd->dentry = dentry;
}
err = -ENOTDIR;
break;
continue;
/* here ends the main loop */
-@@ -592,22 +644,22 @@ last_component:
+@@ -592,22 +644,22 @@
if (err < 0)
break;
}
dput(dentry);
if (err)
goto return_err;
-@@ -621,7 +673,8 @@ last_component:
+@@ -621,7 +673,8 @@
goto no_inode;
if (lookup_flags & LOOKUP_DIRECTORY) {
err = -ENOTDIR;
break;
}
goto return_base;
-@@ -645,6 +698,25 @@ return_reval:
+@@ -645,6 +698,27 @@
* Check the cached dentry for staleness.
*/
dentry = nd->dentry;
+ }
+ nd->dentry = new;
+ }
++ if (!nd->dentry->d_inode)
++ goto no_inode;
+ } else
if (dentry && dentry->d_op && dentry->d_op->d_revalidate) {
err = -ESTALE;
if (!dentry->d_op->d_revalidate(dentry, 0)) {
-@@ -658,15 +730,28 @@ out_dput:
+@@ -658,15 +732,28 @@
dput(dentry);
break;
}
}
/* SMP-safe */
-@@ -751,6 +836,17 @@ walk_init_root(const char *name, struct
+@@ -751,6 +838,17 @@
}
/* SMP-safe */
int path_lookup(const char *path, unsigned flags, struct nameidata *nd)
{
int error = 0;
-@@ -765,6 +861,7 @@ int path_init(const char *name, unsigned
+@@ -765,6 +863,7 @@
{
nd->last_type = LAST_ROOT; /* if there are only slashes... */
nd->flags = flags;
if (*name=='/')
return walk_init_root(name,nd);
read_lock(¤t->fs->lock);
-@@ -779,7 +876,8 @@ int path_init(const char *name, unsigned
+@@ -779,7 +878,8 @@
* needs parent already locked. Doesn't follow mounts.
* SMP-safe.
*/
{
struct dentry * dentry;
struct inode *inode;
-@@ -802,13 +900,16 @@ struct dentry * lookup_hash(struct qstr
+@@ -802,13 +902,16 @@
goto out;
}
dentry = inode->i_op->lookup(inode, new);
unlock_kernel();
if (!dentry)
-@@ -820,6 +921,12 @@ out:
+@@ -820,6 +923,12 @@
return dentry;
}
/* SMP-safe */
struct dentry * lookup_one_len(const char * name, struct dentry * base, int len)
{
-@@ -841,7 +948,7 @@ struct dentry * lookup_one_len(const cha
+@@ -841,7 +950,7 @@
}
this.hash = end_name_hash(hash);
access:
return ERR_PTR(-EACCES);
}
-@@ -872,6 +979,23 @@ int __user_walk(const char *name, unsign
+@@ -872,6 +981,23 @@
return err;
}
/*
* It's inline, so penalty for filesystems that don't use sticky bit is
* minimal.
-@@ -969,7 +1093,8 @@ static inline int lookup_flags(unsigned
+@@ -969,7 +1095,8 @@
return retval;
}
{
int error;
-@@ -982,12 +1107,15 @@ int vfs_create(struct inode *dir, struct
+@@ -982,12 +1109,15 @@
goto exit_lock;
error = -EACCES; /* shouldn't it be ENOSYS? */
unlock_kernel();
exit_lock:
up(&dir->i_zombie);
-@@ -996,6 +1124,11 @@ exit_lock:
+@@ -996,6 +1126,11 @@
return error;
}
/*
* open_namei()
*
-@@ -1010,7 +1143,8 @@ exit_lock:
+@@ -1010,7 +1145,8 @@
* for symlinks (where the permissions are checked later).
* SMP-safe
*/
{
int acc_mode, error = 0;
struct inode *inode;
-@@ -1020,11 +1154,14 @@ int open_namei(const char * pathname, in
+@@ -1020,11 +1156,14 @@
acc_mode = ACC_MODE(flag);
if (error)
return error;
dentry = nd->dentry;
-@@ -1034,6 +1171,10 @@ int open_namei(const char * pathname, in
+@@ -1034,6 +1173,10 @@
/*
* Create - we need to know the parent.
*/
error = path_lookup(pathname, LOOKUP_PARENT, nd);
if (error)
return error;
-@@ -1049,7 +1190,7 @@ int open_namei(const char * pathname, in
+@@ -1049,7 +1192,7 @@
dir = nd->dentry;
down(&dir->d_inode->i_sem);
do_last:
error = PTR_ERR(dentry);
-@@ -1058,10 +1199,11 @@ do_last:
+@@ -1058,10 +1201,11 @@
goto exit;
}
up(&dir->d_inode->i_sem);
dput(nd->dentry);
nd->dentry = dentry;
-@@ -1086,7 +1228,7 @@ do_last:
+@@ -1086,7 +1230,7 @@
error = -ELOOP;
if (flag & O_NOFOLLOW)
goto exit_dput;
}
error = -ENOENT;
if (!dentry->d_inode)
-@@ -1165,7 +1307,7 @@ ok:
+@@ -1165,7 +1309,7 @@
if (!error) {
DQUOT_INIT(inode);
}
put_write_access(inode);
if (error)
-@@ -1177,8 +1319,10 @@ ok:
+@@ -1177,8 +1321,10 @@
return 0;
exit_dput:
path_release(nd);
return error;
-@@ -1197,7 +1341,16 @@ do_link:
+@@ -1197,7 +1343,16 @@
* are done. Procfs-like symlinks just set LAST_BIND.
*/
UPDATE_ATIME(dentry->d_inode);
dput(dentry);
if (error)
return error;
-@@ -1219,13 +1372,20 @@ do_link:
+@@ -1219,13 +1374,20 @@
}
dir = nd->dentry;
down(&dir->d_inode->i_sem);
{
struct dentry *dentry;
-@@ -1233,7 +1393,7 @@ static struct dentry *lookup_create(stru
+@@ -1233,7 +1395,7 @@
dentry = ERR_PTR(-EEXIST);
if (nd->last_type != LAST_NORM)
goto fail;
if (IS_ERR(dentry))
goto fail;
if (!is_dir && nd->last.name[nd->last.len] && !dentry->d_inode)
-@@ -1289,7 +1449,16 @@ asmlinkage long sys_mknod(const char * f
+@@ -1289,7 +1451,20 @@
error = path_lookup(tmp, LOOKUP_PARENT, &nd);
if (error)
goto out;
- dentry = lookup_create(&nd, 0);
+
++ if (nd.last_type != LAST_NORM) {
++ error = -EEXIST;
++ goto out2;
++ }
+ if (nd.dentry->d_inode->i_op->mknod_raw) {
+ struct inode_operations *op = nd.dentry->d_inode->i_op;
+ error = op->mknod_raw(&nd, mode, dev);
error = PTR_ERR(dentry);
mode &= ~current->fs->umask;
-@@ -1310,6 +1479,7 @@ asmlinkage long sys_mknod(const char * f
+@@ -1310,6 +1485,7 @@
dput(dentry);
}
up(&nd.dentry->d_inode->i_sem);
path_release(&nd);
out:
putname(tmp);
-@@ -1357,7 +1527,14 @@ asmlinkage long sys_mkdir(const char * p
+@@ -1357,7 +1533,18 @@
error = path_lookup(tmp, LOOKUP_PARENT, &nd);
if (error)
goto out;
- dentry = lookup_create(&nd, 1);
++ if (nd.last_type != LAST_NORM) {
++ error = -EEXIST;
++ goto out2;
++ }
+ if (nd.dentry->d_inode->i_op->mkdir_raw) {
+ struct inode_operations *op = nd.dentry->d_inode->i_op;
+ error = op->mkdir_raw(&nd, mode);
error = PTR_ERR(dentry);
if (!IS_ERR(dentry)) {
error = vfs_mkdir(nd.dentry->d_inode, dentry,
-@@ -1365,6 +1542,7 @@ asmlinkage long sys_mkdir(const char * p
+@@ -1365,6 +1552,7 @@
dput(dentry);
}
up(&nd.dentry->d_inode->i_sem);
path_release(&nd);
out:
putname(tmp);
-@@ -1465,8 +1643,16 @@ asmlinkage long sys_rmdir(const char * p
+@@ -1465,8 +1653,16 @@
error = -EBUSY;
goto exit1;
}
error = PTR_ERR(dentry);
if (!IS_ERR(dentry)) {
error = vfs_rmdir(nd.dentry->d_inode, dentry);
-@@ -1524,8 +1710,15 @@ asmlinkage long sys_unlink(const char *
+@@ -1524,8 +1720,15 @@
error = -EISDIR;
if (nd.last_type != LAST_NORM)
goto exit1;
error = PTR_ERR(dentry);
if (!IS_ERR(dentry)) {
/* Why not before? Because we want correct error value */
-@@ -1592,15 +1785,23 @@ asmlinkage long sys_symlink(const char *
+@@ -1592,15 +1795,27 @@
error = path_lookup(to, LOOKUP_PARENT, &nd);
if (error)
goto out;
- dentry = lookup_create(&nd, 0);
++ if (nd.last_type != LAST_NORM) {
++ error = -EEXIST;
++ goto out2;
++ }
+ if (nd.dentry->d_inode->i_op->symlink_raw) {
+ struct inode_operations *op = nd.dentry->d_inode->i_op;
+ error = op->symlink_raw(&nd, from);
putname(to);
}
putname(from);
-@@ -1676,7 +1877,14 @@ asmlinkage long sys_link(const char * ol
+@@ -1676,7 +1891,18 @@
error = -EXDEV;
if (old_nd.mnt != nd.mnt)
goto out_release;
- new_dentry = lookup_create(&nd, 0);
++ if (nd.last_type != LAST_NORM) {
++ error = -EEXIST;
++ goto out_release;
++ }
+ if (nd.dentry->d_inode->i_op->link_raw) {
+ struct inode_operations *op = nd.dentry->d_inode->i_op;
+ error = op->link_raw(&old_nd, &nd);
error = PTR_ERR(new_dentry);
if (!IS_ERR(new_dentry)) {
error = vfs_link(old_nd.dentry, nd.dentry->d_inode, new_dentry);
-@@ -1720,7 +1928,7 @@ exit:
+@@ -1720,7 +1946,7 @@
* locking].
*/
int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
{
int error;
struct inode *target;
-@@ -1799,7 +2007,7 @@ out_unlock:
+@@ -1799,7 +2025,7 @@
}
int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry,
{
int error;
-@@ -1887,9 +2095,18 @@ static inline int do_rename(const char *
+@@ -1887,9 +2113,18 @@
if (newnd.last_type != LAST_NORM)
goto exit2;
error = PTR_ERR(old_dentry);
if (IS_ERR(old_dentry))
goto exit3;
-@@ -1905,16 +2122,16 @@ static inline int do_rename(const char *
+@@ -1905,16 +2140,16 @@
if (newnd.last.name[newnd.last.len])
goto exit4;
}
dput(new_dentry);
exit4:
dput(old_dentry);
-@@ -1965,20 +2182,28 @@ out:
+@@ -1965,20 +2200,28 @@
}
static inline int
out:
if (current->link_count || res || nd->last_type!=LAST_NORM)
return res;
-@@ -2002,7 +2227,13 @@ fail:
+@@ -2002,7 +2245,13 @@
int vfs_follow_link(struct nameidata *nd, const char *link)
{
}
/* get the link contents into pagecache */
-@@ -2044,7 +2275,7 @@ int page_follow_link(struct dentry *dent
+@@ -2044,7 +2293,7 @@
{
struct page *page = NULL;
char *s = page_getlink(dentry, &page);
if (page) {
kunmap(page);
page_cache_release(page);
---- linux-2.4.20-rh-20.9/fs/namespace.c~vfs_intent-2.4.20-rh 2003-09-13 19:34:35.000000000 +0400
-+++ linux-2.4.20-rh-20.9-alexey/fs/namespace.c 2003-09-14 17:34:53.000000000 +0400
-@@ -99,6 +99,7 @@ static void detach_mnt(struct vfsmount *
+Index: linux-2.4.20/fs/namespace.c
+===================================================================
+--- linux-2.4.20.orig/fs/namespace.c Wed Mar 17 13:57:05 2004
++++ linux-2.4.20/fs/namespace.c Wed Mar 17 13:57:11 2004
+@@ -99,6 +99,7 @@
{
old_nd->dentry = mnt->mnt_mountpoint;
old_nd->mnt = mnt->mnt_parent;
mnt->mnt_parent = mnt;
mnt->mnt_mountpoint = mnt->mnt_root;
list_del_init(&mnt->mnt_child);
-@@ -110,6 +111,7 @@ static void attach_mnt(struct vfsmount *
+@@ -110,6 +111,7 @@
{
mnt->mnt_parent = mntget(nd->mnt);
mnt->mnt_mountpoint = dget(nd->dentry);
list_add(&mnt->mnt_hash, mount_hashtable+hash(nd->mnt, nd->dentry));
list_add(&mnt->mnt_child, &nd->mnt->mnt_mounts);
nd->dentry->d_mounted++;
-@@ -485,14 +487,17 @@ static int do_loopback(struct nameidata
+@@ -485,14 +487,17 @@
{
struct nameidata old_nd;
struct vfsmount *mnt = NULL;
down_write(¤t->namespace->sem);
err = -EINVAL;
-@@ -515,6 +520,7 @@ static int do_loopback(struct nameidata
+@@ -515,6 +520,7 @@
}
up_write(¤t->namespace->sem);
path_release(&old_nd);
return err;
}
-@@ -698,6 +704,7 @@ long do_mount(char * dev_name, char * di
+@@ -698,6 +704,7 @@
unsigned long flags, void *data_page)
{
struct nameidata nd;
int retval = 0;
int mnt_flags = 0;
-@@ -722,10 +729,11 @@ long do_mount(char * dev_name, char * di
+@@ -722,10 +729,11 @@
flags &= ~(MS_NOSUID|MS_NOEXEC|MS_NODEV);
/* ... and get the mountpoint */
if (flags & MS_REMOUNT)
retval = do_remount(&nd, flags & ~MS_REMOUNT, mnt_flags,
data_page);
-@@ -736,6 +744,8 @@ long do_mount(char * dev_name, char * di
+@@ -736,6 +744,8 @@
else
retval = do_add_mount(&nd, type_page, flags, mnt_flags,
dev_name, data_page);
path_release(&nd);
return retval;
}
-@@ -901,6 +911,8 @@ asmlinkage long sys_pivot_root(const cha
+@@ -901,6 +911,8 @@
{
struct vfsmount *tmp;
struct nameidata new_nd, old_nd, parent_nd, root_parent, user_nd;
int error;
if (!capable(CAP_SYS_ADMIN))
-@@ -908,14 +920,14 @@ asmlinkage long sys_pivot_root(const cha
+@@ -908,14 +920,14 @@
lock_kernel();
if (error)
goto out1;
-@@ -970,8 +982,10 @@ out2:
+@@ -970,8 +982,10 @@
up(&old_nd.dentry->d_inode->i_zombie);
up_write(¤t->namespace->sem);
path_release(&user_nd);
path_release(&new_nd);
out0:
unlock_kernel();
---- linux-2.4.20-rh-20.9/fs/open.c~vfs_intent-2.4.20-rh 2003-09-13 19:34:25.000000000 +0400
-+++ linux-2.4.20-rh-20.9-alexey/fs/open.c 2003-09-14 17:34:53.000000000 +0400
+Index: linux-2.4.20/fs/open.c
+===================================================================
+--- linux-2.4.20.orig/fs/open.c Wed Mar 17 13:57:03 2004
++++ linux-2.4.20/fs/open.c Wed Mar 17 13:57:11 2004
@@ -19,6 +19,8 @@
#include <asm/uaccess.h>
int vfs_statfs(struct super_block *sb, struct statfs *buf)
{
-@@ -95,9 +97,10 @@ void fd_install(unsigned int fd, struct
+@@ -95,9 +97,10 @@
write_unlock(&files->file_lock);
}
int error;
struct iattr newattrs;
-@@ -108,7 +111,13 @@ int do_truncate(struct dentry *dentry, l
+@@ -108,7 +111,13 @@
down(&inode->i_sem);
newattrs.ia_size = length;
newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
up(&inode->i_sem);
return error;
}
-@@ -118,12 +127,13 @@ static inline long do_sys_truncate(const
+@@ -118,12 +127,13 @@
struct nameidata nd;
struct inode * inode;
int error;
if (error)
goto out;
inode = nd.dentry->d_inode;
-@@ -163,11 +173,13 @@ static inline long do_sys_truncate(const
+@@ -163,11 +173,13 @@
error = locks_verify_truncate(inode, NULL, length);
if (!error) {
DQUOT_INIT(inode);
path_release(&nd);
out:
return error;
-@@ -215,7 +227,7 @@ static inline long do_sys_ftruncate(unsi
+@@ -215,7 +227,7 @@
error = locks_verify_truncate(inode, file, length);
if (!error)
out_putf:
fput(file);
out:
-@@ -260,11 +272,13 @@ asmlinkage long sys_utime(char * filenam
+@@ -260,11 +272,13 @@
struct inode * inode;
struct iattr newattrs;
error = -EROFS;
if (IS_RDONLY(inode))
goto dput_and_out;
-@@ -279,11 +293,25 @@ asmlinkage long sys_utime(char * filenam
+@@ -279,11 +293,25 @@
goto dput_and_out;
newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
error = notify_change(nd.dentry, &newattrs);
dput_and_out:
path_release(&nd);
-@@ -304,12 +332,14 @@ asmlinkage long sys_utimes(char * filena
+@@ -304,12 +332,14 @@
struct inode * inode;
struct iattr newattrs;
error = -EROFS;
if (IS_RDONLY(inode))
goto dput_and_out;
-@@ -324,7 +354,20 @@ asmlinkage long sys_utimes(char * filena
+@@ -324,7 +354,20 @@
newattrs.ia_atime = times[0].tv_sec;
newattrs.ia_mtime = times[1].tv_sec;
newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
if (current->fsuid != inode->i_uid &&
(error = permission(inode,MAY_WRITE)) != 0)
goto dput_and_out;
-@@ -347,6 +390,7 @@ asmlinkage long sys_access(const char *
+@@ -347,6 +390,7 @@
int old_fsuid, old_fsgid;
kernel_cap_t old_cap;
int res;
if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */
return -EINVAL;
-@@ -364,13 +408,14 @@ asmlinkage long sys_access(const char *
+@@ -364,13 +408,14 @@
else
current->cap_effective = current->cap_permitted;
path_release(&nd);
}
-@@ -385,8 +430,9 @@ asmlinkage long sys_chdir(const char * f
+@@ -385,8 +430,9 @@
{
int error;
struct nameidata nd;
if (error)
goto out;
-@@ -397,6 +443,7 @@ asmlinkage long sys_chdir(const char * f
+@@ -397,6 +443,7 @@
set_fs_pwd(current->fs, nd.mnt, nd.dentry);
dput_and_out:
path_release(&nd);
out:
return error;
-@@ -436,9 +483,10 @@ asmlinkage long sys_chroot(const char *
+@@ -436,9 +483,10 @@
{
int error;
struct nameidata nd;
if (error)
goto out;
-@@ -454,39 +502,56 @@ asmlinkage long sys_chroot(const char *
+@@ -454,39 +502,56 @@
set_fs_altroot();
error = 0;
dput_and_out:
fput(file);
out:
return err;
-@@ -495,30 +560,14 @@ out:
+@@ -495,30 +560,14 @@
asmlinkage long sys_chmod(const char * filename, mode_t mode)
{
struct nameidata nd;
path_release(&nd);
out:
return error;
-@@ -538,6 +587,20 @@ static int chown_common(struct dentry *
+@@ -538,6 +587,20 @@
error = -EROFS;
if (IS_RDONLY(inode))
goto out;
error = -EPERM;
if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
goto out;
-@@ -642,8 +705,9 @@ struct file *filp_open(const char * file
+@@ -642,8 +705,9 @@
{
int namei_flags, error;
struct nameidata nd;
namei_flags = flags;
if ((namei_flags+1) & O_ACCMODE)
-@@ -651,14 +715,15 @@ struct file *filp_open(const char * file
+@@ -651,14 +715,15 @@
if (namei_flags & O_TRUNC)
namei_flags |= 2;
{
struct file * f;
struct inode *inode;
-@@ -695,12 +760,15 @@ struct file *dentry_open(struct dentry *
+@@ -695,12 +760,15 @@
}
if (f->f_op && f->f_op->open) {
return f;
cleanup_all:
-@@ -715,11 +783,17 @@ cleanup_all:
+@@ -715,11 +783,17 @@
cleanup_file:
put_filp(f);
cleanup_dentry:
/*
* Find an empty file descriptor entry, and mark it busy.
*/
---- linux-2.4.20-rh-20.9/fs/proc/base.c~vfs_intent-2.4.20-rh 2003-09-13 19:34:35.000000000 +0400
-+++ linux-2.4.20-rh-20.9-alexey/fs/proc/base.c 2003-09-14 17:34:53.000000000 +0400
-@@ -494,6 +494,9 @@ static int proc_pid_follow_link(struct d
+Index: linux-2.4.20/fs/proc/base.c
+===================================================================
+--- linux-2.4.20.orig/fs/proc/base.c Wed Mar 17 13:57:05 2004
++++ linux-2.4.20/fs/proc/base.c Wed Mar 17 13:57:11 2004
+@@ -494,6 +494,9 @@
error = inode->u.proc_i.op.proc_get_link(inode, &nd->dentry, &nd->mnt);
nd->last_type = LAST_BIND;
out:
return error;
}
---- linux-2.4.20-rh-20.9/fs/stat.c~vfs_intent-2.4.20-rh 2003-09-13 19:34:35.000000000 +0400
-+++ linux-2.4.20-rh-20.9-alexey/fs/stat.c 2003-09-14 17:35:10.000000000 +0400
-@@ -17,10 +17,14 @@
+Index: linux-2.4.20/fs/stat.c
+===================================================================
+--- linux-2.4.20.orig/fs/stat.c Wed Mar 17 13:57:05 2004
++++ linux-2.4.20/fs/stat.c Wed Mar 17 13:58:01 2004
+@@ -17,10 +17,12 @@
* Revalidate the inode. This is required for proper NFS attribute caching.
*/
static __inline__ int
{
struct inode * inode = dentry->d_inode;
- if (inode->i_op && inode->i_op->revalidate)
-+ if (!inode)
-+ return -ENOENT;
+ if (inode->i_op && inode->i_op->revalidate_it)
+ return inode->i_op->revalidate_it(dentry, it);
+ else if (inode->i_op && inode->i_op->revalidate)
return inode->i_op->revalidate(dentry);
return 0;
}
-@@ -32,13 +36,13 @@ static inline nlink_t user_nlink(struct
+@@ -32,13 +34,13 @@
return inode->i_nlink;
}
if (res)
return res;
-@@ -111,10 +115,12 @@ int vfs_stat(char *name, struct kstat *s
+@@ -111,10 +113,12 @@
{
struct nameidata nd;
int error;
path_release(&nd);
}
return error;
-@@ -124,10 +130,12 @@ int vfs_lstat(char *name, struct kstat *
+@@ -124,10 +128,12 @@
{
struct nameidata nd;
int error;
path_release(&nd);
}
return error;
-@@ -139,7 +147,7 @@ int vfs_fstat(unsigned int fd, struct ks
+@@ -139,7 +145,7 @@
int error = -EBADF;
if (f) {
fput(f);
}
return error;
-@@ -286,7 +294,7 @@ asmlinkage long sys_readlink(const char
+@@ -286,7 +292,7 @@
error = -EINVAL;
if (inode->i_op && inode->i_op->readlink &&
UPDATE_ATIME(inode);
error = inode->i_op->readlink(nd.dentry, buf, bufsiz);
}
---- linux-2.4.20-rh-20.9/include/linux/dcache.h~vfs_intent-2.4.20-rh 2003-09-13 19:34:28.000000000 +0400
-+++ linux-2.4.20-rh-20.9-alexey/include/linux/dcache.h 2003-09-14 17:34:53.000000000 +0400
+Index: linux-2.4.20/include/linux/dcache.h
+===================================================================
+--- linux-2.4.20.orig/include/linux/dcache.h Wed Mar 17 13:57:04 2004
++++ linux-2.4.20/include/linux/dcache.h Wed Mar 17 13:57:11 2004
@@ -6,6 +6,51 @@
#include <asm/atomic.h>
#include <linux/mount.h>
/*
* linux/include/linux/dcache.h
-@@ -96,8 +141,22 @@ struct dentry_operations {
+@@ -96,8 +141,22 @@
int (*d_delete)(struct dentry *);
void (*d_release)(struct dentry *);
void (*d_iput)(struct dentry *, struct inode *);
/* the dentry parameter passed to d_hash and d_compare is the parent
* directory of the entries to be compared. It is used in case these
* functions need any directory specific information for determining
-@@ -129,6 +188,7 @@ d_iput: no no yes
+@@ -129,6 +188,7 @@
* s_nfsd_free_path semaphore will be down
*/
#define DCACHE_REFERENCED 0x0008 /* Recently used, don't discard. */
extern spinlock_t dcache_lock;
---- linux-2.4.20-rh-20.9/include/linux/fs.h~vfs_intent-2.4.20-rh 2003-09-14 17:34:50.000000000 +0400
-+++ linux-2.4.20-rh-20.9-alexey/include/linux/fs.h 2003-09-14 17:34:53.000000000 +0400
-@@ -73,6 +73,7 @@ extern int leases_enable, dir_notify_ena
+Index: linux-2.4.20/include/linux/fs.h
+===================================================================
+--- linux-2.4.20.orig/include/linux/fs.h Wed Mar 17 13:57:11 2004
++++ linux-2.4.20/include/linux/fs.h Wed Mar 17 13:57:11 2004
+@@ -73,6 +73,7 @@
#define FMODE_READ 1
#define FMODE_WRITE 2
#define READ 0
#define WRITE 1
-@@ -338,6 +339,9 @@ extern void set_bh_page(struct buffer_he
+@@ -338,6 +339,9 @@
#define ATTR_MTIME_SET 256
#define ATTR_FORCE 512 /* Not a change, but a change it */
#define ATTR_ATTR_FLAG 1024
/*
* This is the Inode Attributes structure, used for notify_change(). It
-@@ -473,6 +477,7 @@ struct inode {
+@@ -473,6 +477,7 @@
struct pipe_inode_info *i_pipe;
struct block_device *i_bdev;
struct char_device *i_cdev;
unsigned long i_dnotify_mask; /* Directory notify events */
struct dnotify_struct *i_dnotify; /* for directory notifications */
-@@ -575,6 +580,7 @@ struct file {
+@@ -575,6 +580,7 @@
/* needed for tty driver, and maybe others */
void *private_data;
/* preallocated helper kiobuf to speedup O_DIRECT */
struct kiobuf *f_iobuf;
-@@ -702,6 +708,7 @@ struct nameidata {
+@@ -702,6 +708,7 @@
struct qstr last;
unsigned int flags;
int last_type;
};
/*
-@@ -822,7 +829,8 @@ extern int vfs_symlink(struct inode *, s
+@@ -822,7 +829,8 @@
extern int vfs_link(struct dentry *, struct inode *, struct dentry *);
extern int vfs_rmdir(struct inode *, struct dentry *);
extern int vfs_unlink(struct inode *, struct dentry *);
/*
* File types
-@@ -882,21 +890,32 @@ struct file_operations {
+@@ -882,21 +890,32 @@
struct inode_operations {
int (*create) (struct inode *,struct dentry *,int);
int (*getattr) (struct dentry *, struct iattr *);
int (*setxattr) (struct dentry *, const char *, void *, size_t, int);
ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
-@@ -1092,10 +1111,14 @@ static inline int get_lease(struct inode
+@@ -1092,10 +1111,14 @@
asmlinkage long sys_open(const char *, int, int);
asmlinkage long sys_close(unsigned int); /* yes, it's really unsigned */
extern int filp_close(struct file *, fl_owner_t id);
extern char * getname(const char *);
-@@ -1386,6 +1409,7 @@ typedef int (*read_actor_t)(read_descrip
+@@ -1386,6 +1409,7 @@
extern loff_t default_llseek(struct file *file, loff_t offset, int origin);
extern int FASTCALL(__user_walk(const char *, unsigned, struct nameidata *));
extern int FASTCALL(path_init(const char *, unsigned, struct nameidata *));
extern int FASTCALL(path_walk(const char *, struct nameidata *));
extern int FASTCALL(path_lookup(const char *, unsigned, struct nameidata *));
-@@ -1397,6 +1421,8 @@ extern struct dentry * lookup_one_len(co
+@@ -1397,6 +1421,8 @@
extern struct dentry * lookup_hash(struct qstr *, struct dentry *);
#define user_path_walk(name,nd) __user_walk(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, nd)
#define user_path_walk_link(name,nd) __user_walk(name, LOOKUP_POSITIVE, nd)
extern void inode_init_once(struct inode *);
extern void iput(struct inode *);
-@@ -1504,6 +1530,8 @@ extern struct file_operations generic_ro
+@@ -1504,6 +1530,8 @@
extern int vfs_readlink(struct dentry *, char *, int, const char *);
extern int vfs_follow_link(struct nameidata *, const char *);
extern int page_readlink(struct dentry *, char *, int);
extern int page_follow_link(struct dentry *, struct nameidata *);
extern struct inode_operations page_symlink_inode_operations;
---- linux-2.4.20-rh-20.9/include/linux/fs_struct.h~vfs_intent-2.4.20-rh 2003-09-13 19:34:19.000000000 +0400
-+++ linux-2.4.20-rh-20.9-alexey/include/linux/fs_struct.h 2003-09-14 17:34:53.000000000 +0400
-@@ -37,10 +37,12 @@ static inline void set_fs_root(struct fs
+Index: linux-2.4.20/include/linux/fs_struct.h
+===================================================================
+--- linux-2.4.20.orig/include/linux/fs_struct.h Wed Mar 17 13:57:02 2004
++++ linux-2.4.20/include/linux/fs_struct.h Wed Mar 17 13:57:11 2004
+@@ -37,10 +37,12 @@
write_lock(&fs->lock);
old_root = fs->root;
old_rootmnt = fs->rootmnt;
dput(old_root);
mntput(old_rootmnt);
}
-@@ -60,10 +62,12 @@ static inline void set_fs_pwd(struct fs_
+@@ -60,10 +62,12 @@
write_lock(&fs->lock);
old_pwd = fs->pwd;
old_pwdmnt = fs->pwdmnt;
dput(old_pwd);
mntput(old_pwdmnt);
}
---- linux-2.4.20-rh-20.9/kernel/ksyms.c~vfs_intent-2.4.20-rh 2003-09-14 17:34:51.000000000 +0400
-+++ linux-2.4.20-rh-20.9-alexey/kernel/ksyms.c 2003-09-14 17:34:53.000000000 +0400
-@@ -298,6 +298,7 @@ EXPORT_SYMBOL(read_cache_page);
+Index: linux-2.4.20/kernel/ksyms.c
+===================================================================
+--- linux-2.4.20.orig/kernel/ksyms.c Wed Mar 17 13:57:11 2004
++++ linux-2.4.20/kernel/ksyms.c Wed Mar 17 13:57:11 2004
+@@ -297,6 +297,7 @@
EXPORT_SYMBOL(set_page_dirty);
EXPORT_SYMBOL(vfs_readlink);
EXPORT_SYMBOL(vfs_follow_link);
EXPORT_SYMBOL(page_readlink);
EXPORT_SYMBOL(page_follow_link);
EXPORT_SYMBOL(page_symlink_inode_operations);
---- linux-2.4.20-rh-20.9/kernel/fork.c~vfs_intent-2.4.20-rh 2003-09-13 19:34:35.000000000 +0400
-+++ linux-2.4.20-rh-20.9-alexey/kernel/fork.c 2003-09-14 17:34:53.000000000 +0400
-@@ -440,10 +440,13 @@ static inline struct fs_struct *__copy_f
+Index: linux-2.4.20/kernel/fork.c
+===================================================================
+--- linux-2.4.20.orig/kernel/fork.c Wed Mar 17 13:57:05 2004
++++ linux-2.4.20/kernel/fork.c Wed Mar 17 13:57:11 2004
+@@ -440,10 +440,13 @@
fs->umask = old->umask;
read_lock(&old->lock);
fs->rootmnt = mntget(old->rootmnt);
fs->altrootmnt = mntget(old->altrootmnt);
fs->altroot = dget(old->altroot);
} else {
---- linux-2.4.20-rh-20.9/kernel/exit.c~vfs_intent-2.4.20-rh 2003-09-13 19:34:35.000000000 +0400
-+++ linux-2.4.20-rh-20.9-alexey/kernel/exit.c 2003-09-14 17:34:53.000000000 +0400
-@@ -345,11 +345,14 @@ static inline void __put_fs_struct(struc
+Index: linux-2.4.20/kernel/exit.c
+===================================================================
+--- linux-2.4.20.orig/kernel/exit.c Wed Mar 17 13:57:05 2004
++++ linux-2.4.20/kernel/exit.c Wed Mar 17 13:57:11 2004
+@@ -345,11 +345,14 @@
{
/* No need to hold fs->lock if we are killing it */
if (atomic_dec_and_test(&fs->count)) {
dput(fs->altroot);
mntput(fs->altrootmnt);
}
-
-_
kernel/ksyms.c | 1
12 files changed, 558 insertions(+), 128 deletions(-)
---- linux-2.4.20-vanilla/fs/exec.c~vfs_intent-2.4.20-vanilla 2003-05-16 05:29:12.000000000 +0400
-+++ linux-2.4.20-vanilla-alexey/fs/exec.c 2003-09-17 21:05:04.000000000 +0400
-@@ -107,8 +107,10 @@ asmlinkage long sys_uselib(const char *
+Index: linux-2.4.24/fs/exec.c
+===================================================================
+--- linux-2.4.24.orig/fs/exec.c Fri Nov 28 10:26:21 2003
++++ linux-2.4.24/fs/exec.c Wed Mar 17 17:36:14 2004
+@@ -112,8 +112,10 @@ asmlinkage long sys_uselib(const char *
struct file * file;
struct nameidata nd;
int error;
if (error)
goto out;
-@@ -120,7 +122,8 @@ asmlinkage long sys_uselib(const char *
+@@ -125,7 +127,8 @@ asmlinkage long sys_uselib(const char *
if (error)
goto exit;
error = PTR_ERR(file);
if (IS_ERR(file))
goto out;
-@@ -363,8 +366,10 @@ struct file *open_exec(const char *name)
+@@ -374,8 +377,10 @@ struct file *open_exec(const char *name)
struct inode *inode;
struct file *file;
int err = 0;
file = ERR_PTR(err);
if (!err) {
inode = nd.dentry->d_inode;
-@@ -376,7 +381,8 @@ struct file *open_exec(const char *name)
+@@ -387,7 +392,8 @@ struct file *open_exec(const char *name)
err = -EACCES;
file = ERR_PTR(err);
if (!err) {
if (!IS_ERR(file)) {
err = deny_write_access(file);
if (err) {
-@@ -388,6 +394,7 @@ out:
+@@ -399,6 +405,7 @@ out:
return file;
}
}
path_release(&nd);
}
goto out;
-@@ -989,7 +996,7 @@ int do_coredump(long signr, struct pt_re
+@@ -1132,7 +1139,7 @@ int do_coredump(long signr, struct pt_re
goto close_fail;
if (!file->f_op->write)
goto close_fail;
goto close_fail;
retval = binfmt->core_dump(signr, regs, file);
---- linux-2.4.20-vanilla/fs/dcache.c~vfs_intent-2.4.20-vanilla 2003-05-16 05:29:12.000000000 +0400
-+++ linux-2.4.20-vanilla-alexey/fs/dcache.c 2003-09-17 21:05:04.000000000 +0400
+Index: linux-2.4.24/fs/dcache.c
+===================================================================
+--- linux-2.4.24.orig/fs/dcache.c Fri Jun 13 07:51:37 2003
++++ linux-2.4.24/fs/dcache.c Wed Mar 17 17:36:14 2004
@@ -181,6 +181,13 @@ int d_invalidate(struct dentry * dentry)
spin_unlock(&dcache_lock);
return 0;
}
#define do_switch(x,y) do { \
---- linux-2.4.20-vanilla/fs/namespace.c~vfs_intent-2.4.20-vanilla 2003-05-16 05:29:12.000000000 +0400
-+++ linux-2.4.20-vanilla-alexey/fs/namespace.c 2003-09-17 21:05:04.000000000 +0400
-@@ -99,6 +99,7 @@ static void detach_mnt(struct vfsmount *
+Index: linux-2.4.24/fs/namespace.c
+===================================================================
+--- linux-2.4.24.orig/fs/namespace.c Fri Nov 28 10:26:21 2003
++++ linux-2.4.24/fs/namespace.c Wed Mar 17 17:36:14 2004
+@@ -98,6 +98,7 @@ static void detach_mnt(struct vfsmount *
{
old_nd->dentry = mnt->mnt_mountpoint;
old_nd->mnt = mnt->mnt_parent;
mnt->mnt_parent = mnt;
mnt->mnt_mountpoint = mnt->mnt_root;
list_del_init(&mnt->mnt_child);
-@@ -110,6 +111,7 @@ static void attach_mnt(struct vfsmount *
+@@ -109,6 +110,7 @@ static void attach_mnt(struct vfsmount *
{
mnt->mnt_parent = mntget(nd->mnt);
mnt->mnt_mountpoint = dget(nd->dentry);
+ PIN(nd->dentry, nd->mnt, 1);
list_add(&mnt->mnt_hash, mount_hashtable+hash(nd->mnt, nd->dentry));
- list_add(&mnt->mnt_child, &nd->mnt->mnt_mounts);
+ list_add_tail(&mnt->mnt_child, &nd->mnt->mnt_mounts);
nd->dentry->d_mounted++;
-@@ -485,14 +487,17 @@ static int do_loopback(struct nameidata
+@@ -488,14 +490,17 @@ static int do_loopback(struct nameidata
{
struct nameidata old_nd;
struct vfsmount *mnt = NULL;
down_write(¤t->namespace->sem);
err = -EINVAL;
-@@ -515,6 +520,7 @@ static int do_loopback(struct nameidata
+@@ -518,6 +523,7 @@ static int do_loopback(struct nameidata
}
up_write(¤t->namespace->sem);
path_release(&old_nd);
return err;
}
-@@ -698,6 +704,7 @@ long do_mount(char * dev_name, char * di
+@@ -701,6 +707,7 @@ long do_mount(char * dev_name, char * di
unsigned long flags, void *data_page)
{
struct nameidata nd;
int retval = 0;
int mnt_flags = 0;
-@@ -722,10 +729,11 @@ long do_mount(char * dev_name, char * di
+@@ -725,10 +732,11 @@ long do_mount(char * dev_name, char * di
flags &= ~(MS_NOSUID|MS_NOEXEC|MS_NODEV);
/* ... and get the mountpoint */
if (flags & MS_REMOUNT)
retval = do_remount(&nd, flags & ~MS_REMOUNT, mnt_flags,
data_page);
-@@ -736,6 +744,8 @@ long do_mount(char * dev_name, char * di
+@@ -739,6 +747,8 @@ long do_mount(char * dev_name, char * di
else
retval = do_add_mount(&nd, type_page, flags, mnt_flags,
dev_name, data_page);
path_release(&nd);
return retval;
}
-@@ -901,6 +911,8 @@ asmlinkage long sys_pivot_root(const cha
+@@ -904,6 +914,8 @@ asmlinkage long sys_pivot_root(const cha
{
struct vfsmount *tmp;
struct nameidata new_nd, old_nd, parent_nd, root_parent, user_nd;
int error;
if (!capable(CAP_SYS_ADMIN))
-@@ -908,14 +920,14 @@ asmlinkage long sys_pivot_root(const cha
+@@ -911,14 +923,14 @@ asmlinkage long sys_pivot_root(const cha
lock_kernel();
if (error)
goto out1;
-@@ -970,8 +982,10 @@ out2:
+@@ -973,8 +985,10 @@ out2:
up(&old_nd.dentry->d_inode->i_zombie);
up_write(¤t->namespace->sem);
path_release(&user_nd);
path_release(&new_nd);
out0:
unlock_kernel();
---- linux-2.4.20-vanilla/fs/namei.c~vfs_intent-2.4.20-vanilla 2003-05-16 05:29:12.000000000 +0400
-+++ linux-2.4.20-vanilla-alexey/fs/namei.c 2003-09-17 21:05:04.000000000 +0400
+Index: linux-2.4.24/fs/namei.c
+===================================================================
+--- linux-2.4.24.orig/fs/namei.c Mon Aug 25 04:44:43 2003
++++ linux-2.4.24/fs/namei.c Wed Mar 17 17:36:52 2004
@@ -94,6 +94,13 @@
* XEmacs seems to be relying on it...
*/
break;
}
goto return_base;
-@@ -633,6 +670,25 @@ return_reval:
+@@ -635,6 +672,27 @@ return_reval:
* Check the cached dentry for staleness.
*/
dentry = nd->dentry;
+ &dentry->d_name, 0, NULL);
+ d_invalidate(dentry);
+ dput(dentry);
-+ if (IS_ERR(new)) {
++ if (IS_ERR(new)) {
+ err = PTR_ERR(new);
+ break;
+ }
+ nd->dentry = new;
+ }
++ if (!nd->dentry->d_inode)
++ goto no_inode;
+ } else
if (dentry && dentry->d_op && dentry->d_op->d_revalidate) {
err = -ESTALE;
if (!dentry->d_op->d_revalidate(dentry, 0)) {
-@@ -646,15 +702,28 @@ out_dput:
+@@ -648,15 +706,28 @@ out_dput:
dput(dentry);
break;
}
}
/* SMP-safe */
-@@ -739,6 +808,17 @@ walk_init_root(const char *name, struct
+@@ -741,6 +812,17 @@ walk_init_root(const char *name, struct
}
/* SMP-safe */
int path_lookup(const char *path, unsigned flags, struct nameidata *nd)
{
int error = 0;
-@@ -753,6 +833,7 @@ int path_init(const char *name, unsigned
+@@ -755,6 +837,7 @@ int path_init(const char *name, unsigned
{
nd->last_type = LAST_ROOT; /* if there are only slashes... */
nd->flags = flags;
if (*name=='/')
return walk_init_root(name,nd);
read_lock(¤t->fs->lock);
-@@ -767,7 +848,8 @@ int path_init(const char *name, unsigned
+@@ -769,7 +852,8 @@ int path_init(const char *name, unsigned
* needs parent already locked. Doesn't follow mounts.
* SMP-safe.
*/
{
struct dentry * dentry;
struct inode *inode;
-@@ -790,13 +872,16 @@ struct dentry * lookup_hash(struct qstr
+@@ -792,13 +876,16 @@ struct dentry * lookup_hash(struct qstr
goto out;
}
dentry = inode->i_op->lookup(inode, new);
unlock_kernel();
if (!dentry)
-@@ -808,6 +893,12 @@ out:
+@@ -810,6 +897,12 @@ out:
return dentry;
}
/* SMP-safe */
struct dentry * lookup_one_len(const char * name, struct dentry * base, int len)
{
-@@ -829,7 +920,7 @@ struct dentry * lookup_one_len(const cha
+@@ -831,7 +924,7 @@ struct dentry * lookup_one_len(const cha
}
this.hash = end_name_hash(hash);
access:
return ERR_PTR(-EACCES);
}
-@@ -860,6 +951,23 @@ int __user_walk(const char *name, unsign
+@@ -862,6 +955,23 @@ int __user_walk(const char *name, unsign
return err;
}
/*
* It's inline, so penalty for filesystems that don't use sticky bit is
* minimal.
-@@ -955,7 +1063,8 @@ static inline int lookup_flags(unsigned
+@@ -957,7 +1067,8 @@ static inline int lookup_flags(unsigned
return retval;
}
{
int error;
-@@ -968,12 +1077,15 @@ int vfs_create(struct inode *dir, struct
+@@ -970,12 +1081,15 @@ int vfs_create(struct inode *dir, struct
goto exit_lock;
error = -EACCES; /* shouldn't it be ENOSYS? */
unlock_kernel();
exit_lock:
up(&dir->i_zombie);
-@@ -982,6 +1094,11 @@ exit_lock:
+@@ -984,6 +1098,11 @@ exit_lock:
return error;
}
/*
* open_namei()
*
-@@ -996,7 +1113,8 @@ exit_lock:
+@@ -998,7 +1117,8 @@ exit_lock:
* for symlinks (where the permissions are checked later).
* SMP-safe
*/
{
int acc_mode, error = 0;
struct inode *inode;
-@@ -1006,11 +1124,14 @@ int open_namei(const char * pathname, in
+@@ -1008,11 +1128,14 @@ int open_namei(const char * pathname, in
acc_mode = ACC_MODE(flag);
if (error)
return error;
dentry = nd->dentry;
-@@ -1020,6 +1141,10 @@ int open_namei(const char * pathname, in
+@@ -1022,6 +1145,10 @@ int open_namei(const char * pathname, in
/*
* Create - we need to know the parent.
*/
error = path_lookup(pathname, LOOKUP_PARENT, nd);
if (error)
return error;
-@@ -1035,7 +1160,7 @@ int open_namei(const char * pathname, in
+@@ -1037,7 +1164,7 @@ int open_namei(const char * pathname, in
dir = nd->dentry;
down(&dir->d_inode->i_sem);
do_last:
error = PTR_ERR(dentry);
-@@ -1044,10 +1169,11 @@ do_last:
+@@ -1046,10 +1173,11 @@ do_last:
goto exit;
}
up(&dir->d_inode->i_sem);
dput(nd->dentry);
nd->dentry = dentry;
-@@ -1151,7 +1277,7 @@ ok:
+@@ -1153,7 +1281,7 @@ ok:
if (!error) {
DQUOT_INIT(inode);
}
put_write_access(inode);
if (error)
-@@ -1163,8 +1289,10 @@ ok:
+@@ -1165,8 +1293,10 @@ ok:
return 0;
exit_dput:
path_release(nd);
return error;
-@@ -1183,7 +1311,10 @@ do_link:
+@@ -1185,7 +1315,10 @@ do_link:
* are done. Procfs-like symlinks just set LAST_BIND.
*/
UPDATE_ATIME(dentry->d_inode);
dput(dentry);
if (error)
return error;
-@@ -1205,13 +1336,20 @@ do_link:
+@@ -1207,13 +1340,20 @@ do_link:
}
dir = nd->dentry;
down(&dir->d_inode->i_sem);
{
struct dentry *dentry;
-@@ -1219,7 +1357,7 @@ static struct dentry *lookup_create(stru
+@@ -1221,7 +1361,7 @@ static struct dentry *lookup_create(stru
dentry = ERR_PTR(-EEXIST);
if (nd->last_type != LAST_NORM)
goto fail;
if (IS_ERR(dentry))
goto fail;
if (!is_dir && nd->last.name[nd->last.len] && !dentry->d_inode)
-@@ -1275,7 +1413,16 @@ asmlinkage long sys_mknod(const char * f
+@@ -1277,7 +1417,20 @@ asmlinkage long sys_mknod(const char * f
error = path_lookup(tmp, LOOKUP_PARENT, &nd);
if (error)
goto out;
- dentry = lookup_create(&nd, 0);
+
++ if (nd.last_type != LAST_NORM) {
++ error = -EEXIST;
++ goto out2;
++ }
+ if (nd.dentry->d_inode->i_op->mknod_raw) {
+ struct inode_operations *op = nd.dentry->d_inode->i_op;
+ error = op->mknod_raw(&nd, mode, dev);
error = PTR_ERR(dentry);
mode &= ~current->fs->umask;
-@@ -1296,6 +1443,7 @@ asmlinkage long sys_mknod(const char * f
+@@ -1298,6 +1451,7 @@ asmlinkage long sys_mknod(const char * f
dput(dentry);
}
up(&nd.dentry->d_inode->i_sem);
path_release(&nd);
out:
putname(tmp);
-@@ -1343,7 +1491,14 @@ asmlinkage long sys_mkdir(const char * p
+@@ -1345,7 +1499,18 @@ asmlinkage long sys_mkdir(const char * p
error = path_lookup(tmp, LOOKUP_PARENT, &nd);
if (error)
goto out;
- dentry = lookup_create(&nd, 1);
++ if (nd.last_type != LAST_NORM) {
++ error = -EEXIST;
++ goto out2;
++ }
+ if (nd.dentry->d_inode->i_op->mkdir_raw) {
+ struct inode_operations *op = nd.dentry->d_inode->i_op;
+ error = op->mkdir_raw(&nd, mode);
error = PTR_ERR(dentry);
if (!IS_ERR(dentry)) {
error = vfs_mkdir(nd.dentry->d_inode, dentry,
-@@ -1351,6 +1506,7 @@ asmlinkage long sys_mkdir(const char * p
+@@ -1353,6 +1518,7 @@ asmlinkage long sys_mkdir(const char * p
dput(dentry);
}
up(&nd.dentry->d_inode->i_sem);
path_release(&nd);
out:
putname(tmp);
-@@ -1451,8 +1607,16 @@ asmlinkage long sys_rmdir(const char * p
+@@ -1453,8 +1619,16 @@ asmlinkage long sys_rmdir(const char * p
error = -EBUSY;
goto exit1;
}
error = PTR_ERR(dentry);
if (!IS_ERR(dentry)) {
error = vfs_rmdir(nd.dentry->d_inode, dentry);
-@@ -1510,8 +1674,15 @@ asmlinkage long sys_unlink(const char *
+@@ -1512,8 +1686,15 @@ asmlinkage long sys_unlink(const char *
error = -EISDIR;
if (nd.last_type != LAST_NORM)
goto exit1;
error = PTR_ERR(dentry);
if (!IS_ERR(dentry)) {
/* Why not before? Because we want correct error value */
-@@ -1578,15 +1749,23 @@ asmlinkage long sys_symlink(const char *
+@@ -1580,15 +1761,27 @@ asmlinkage long sys_symlink(const char *
error = path_lookup(to, LOOKUP_PARENT, &nd);
if (error)
goto out;
- dentry = lookup_create(&nd, 0);
++ if (nd.last_type != LAST_NORM) {
++ error = -EEXIST;
++ goto out2;
++ }
+ if (nd.dentry->d_inode->i_op->symlink_raw) {
+ struct inode_operations *op = nd.dentry->d_inode->i_op;
+ error = op->symlink_raw(&nd, from);
putname(to);
}
putname(from);
-@@ -1662,7 +1841,14 @@ asmlinkage long sys_link(const char * ol
+@@ -1664,7 +1857,18 @@ asmlinkage long sys_link(const char * ol
error = -EXDEV;
if (old_nd.mnt != nd.mnt)
goto out_release;
- new_dentry = lookup_create(&nd, 0);
++ if (nd.last_type != LAST_NORM) {
++ error = -EEXIST;
++ goto out_release;
++ }
+ if (nd.dentry->d_inode->i_op->link_raw) {
+ struct inode_operations *op = nd.dentry->d_inode->i_op;
+ error = op->link_raw(&old_nd, &nd);
error = PTR_ERR(new_dentry);
if (!IS_ERR(new_dentry)) {
error = vfs_link(old_nd.dentry, nd.dentry->d_inode, new_dentry);
-@@ -1706,7 +1892,7 @@ exit:
+@@ -1708,7 +1912,7 @@ exit:
* locking].
*/
int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
{
int error;
struct inode *target;
-@@ -1785,7 +1971,7 @@ out_unlock:
+@@ -1787,7 +1991,7 @@ out_unlock:
}
int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry,
{
int error;
-@@ -1873,9 +2059,18 @@ static inline int do_rename(const char *
+@@ -1875,9 +2079,18 @@ static inline int do_rename(const char *
if (newnd.last_type != LAST_NORM)
goto exit2;
error = PTR_ERR(old_dentry);
if (IS_ERR(old_dentry))
goto exit3;
-@@ -1891,16 +2086,16 @@ static inline int do_rename(const char *
+@@ -1893,16 +2106,16 @@ static inline int do_rename(const char *
if (newnd.last.name[newnd.last.len])
goto exit4;
}
dput(new_dentry);
exit4:
dput(old_dentry);
-@@ -1951,20 +2146,26 @@ out:
+@@ -1953,20 +2166,26 @@ out:
}
static inline int
out:
if (current->link_count || res || nd->last_type!=LAST_NORM)
return res;
-@@ -1986,7 +2187,13 @@ fail:
+@@ -1990,7 +2209,13 @@ fail:
int vfs_follow_link(struct nameidata *nd, const char *link)
{
}
/* get the link contents into pagecache */
-@@ -2028,7 +2235,7 @@ int page_follow_link(struct dentry *dent
+@@ -2032,7 +2257,7 @@ int page_follow_link(struct dentry *dent
{
struct page *page = NULL;
char *s = page_getlink(dentry, &page);
if (page) {
kunmap(page);
page_cache_release(page);
---- linux-2.4.20-vanilla/fs/open.c~vfs_intent-2.4.20-vanilla 2003-05-16 05:29:13.000000000 +0400
-+++ linux-2.4.20-vanilla-alexey/fs/open.c 2003-09-17 21:05:04.000000000 +0400
+Index: linux-2.4.24/fs/open.c
+===================================================================
+--- linux-2.4.24.orig/fs/open.c Mon Aug 25 04:44:43 2003
++++ linux-2.4.24/fs/open.c Wed Mar 17 17:36:14 2004
@@ -19,6 +19,8 @@
#include <asm/uaccess.h>
int error;
struct iattr newattrs;
-@@ -108,7 +111,13 @@ int do_truncate(struct dentry *dentry, l
+@@ -109,7 +112,13 @@ int do_truncate(struct dentry *dentry, l
down(&inode->i_sem);
newattrs.ia_size = length;
newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
+ } else
+ error = notify_change(dentry, &newattrs);
up(&inode->i_sem);
+ up_write(&inode->i_alloc_sem);
return error;
- }
-@@ -118,12 +127,13 @@ static inline long do_sys_truncate(const
+@@ -120,12 +129,13 @@ static inline long do_sys_truncate(const
struct nameidata nd;
struct inode * inode;
int error;
if (error)
goto out;
inode = nd.dentry->d_inode;
-@@ -163,11 +173,13 @@ static inline long do_sys_truncate(const
+@@ -165,11 +175,13 @@ static inline long do_sys_truncate(const
error = locks_verify_truncate(inode, NULL, length);
if (!error) {
DQUOT_INIT(inode);
path_release(&nd);
out:
return error;
-@@ -215,7 +227,7 @@ static inline long do_sys_ftruncate(unsi
+@@ -217,7 +229,7 @@ static inline long do_sys_ftruncate(unsi
error = locks_verify_truncate(inode, file, length);
if (!error)
out_putf:
fput(file);
out:
-@@ -260,11 +272,13 @@ asmlinkage long sys_utime(char * filenam
+@@ -262,11 +274,13 @@ asmlinkage long sys_utime(char * filenam
struct inode * inode;
struct iattr newattrs;
error = -EROFS;
if (IS_RDONLY(inode))
goto dput_and_out;
-@@ -279,11 +293,25 @@ asmlinkage long sys_utime(char * filenam
+@@ -281,11 +295,25 @@ asmlinkage long sys_utime(char * filenam
goto dput_and_out;
newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
error = notify_change(nd.dentry, &newattrs);
dput_and_out:
path_release(&nd);
-@@ -304,12 +332,14 @@ asmlinkage long sys_utimes(char * filena
+@@ -306,12 +334,14 @@ asmlinkage long sys_utimes(char * filena
struct inode * inode;
struct iattr newattrs;
error = -EROFS;
if (IS_RDONLY(inode))
goto dput_and_out;
-@@ -324,7 +354,20 @@ asmlinkage long sys_utimes(char * filena
+@@ -326,7 +356,20 @@ asmlinkage long sys_utimes(char * filena
newattrs.ia_atime = times[0].tv_sec;
newattrs.ia_mtime = times[1].tv_sec;
newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
if (current->fsuid != inode->i_uid &&
(error = permission(inode,MAY_WRITE)) != 0)
goto dput_and_out;
-@@ -347,6 +390,7 @@ asmlinkage long sys_access(const char *
+@@ -349,6 +392,7 @@ asmlinkage long sys_access(const char *
int old_fsuid, old_fsgid;
kernel_cap_t old_cap;
int res;
if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */
return -EINVAL;
-@@ -364,13 +408,14 @@ asmlinkage long sys_access(const char *
+@@ -366,13 +410,14 @@ asmlinkage long sys_access(const char *
else
current->cap_effective = current->cap_permitted;
path_release(&nd);
}
-@@ -385,8 +430,9 @@ asmlinkage long sys_chdir(const char * f
+@@ -387,8 +432,9 @@ asmlinkage long sys_chdir(const char * f
{
int error;
struct nameidata nd;
if (error)
goto out;
-@@ -397,6 +443,7 @@ asmlinkage long sys_chdir(const char * f
+@@ -399,6 +445,7 @@ asmlinkage long sys_chdir(const char * f
set_fs_pwd(current->fs, nd.mnt, nd.dentry);
dput_and_out:
path_release(&nd);
out:
return error;
-@@ -436,9 +483,10 @@ asmlinkage long sys_chroot(const char *
+@@ -438,9 +485,10 @@ asmlinkage long sys_chroot(const char *
{
int error;
struct nameidata nd;
if (error)
goto out;
-@@ -454,39 +502,56 @@ asmlinkage long sys_chroot(const char *
+@@ -456,39 +504,56 @@ asmlinkage long sys_chroot(const char *
set_fs_altroot();
error = 0;
dput_and_out:
fput(file);
out:
return err;
-@@ -495,30 +560,14 @@ out:
+@@ -497,30 +562,14 @@ out:
asmlinkage long sys_chmod(const char * filename, mode_t mode)
{
struct nameidata nd;
path_release(&nd);
out:
return error;
-@@ -538,6 +587,20 @@ static int chown_common(struct dentry *
+@@ -540,6 +589,20 @@ static int chown_common(struct dentry *
error = -EROFS;
if (IS_RDONLY(inode))
goto out;
error = -EPERM;
if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
goto out;
-@@ -642,6 +705,7 @@ struct file *filp_open(const char * file
+@@ -644,6 +707,7 @@ struct file *filp_open(const char * file
{
int namei_flags, error;
struct nameidata nd;
namei_flags = flags;
if ((namei_flags+1) & O_ACCMODE)
-@@ -649,14 +713,15 @@ struct file *filp_open(const char * file
+@@ -651,14 +715,15 @@ struct file *filp_open(const char * file
if (namei_flags & O_TRUNC)
namei_flags |= 2;
{
struct file * f;
struct inode *inode;
-@@ -693,12 +758,15 @@ struct file *dentry_open(struct dentry *
+@@ -695,12 +760,15 @@ struct file *dentry_open(struct dentry *
}
if (f->f_op && f->f_op->open) {
return f;
cleanup_all:
-@@ -713,11 +781,17 @@ cleanup_all:
+@@ -715,11 +783,17 @@ cleanup_all:
cleanup_file:
put_filp(f);
cleanup_dentry:
/*
* Find an empty file descriptor entry, and mark it busy.
*/
---- linux-2.4.20-vanilla/fs/stat.c~vfs_intent-2.4.20-vanilla 2001-09-14 03:04:43.000000000 +0400
-+++ linux-2.4.20-vanilla-alexey/fs/stat.c 2003-09-17 21:05:04.000000000 +0400
-@@ -17,10 +17,14 @@
+Index: linux-2.4.24/fs/stat.c
+===================================================================
+--- linux-2.4.24.orig/fs/stat.c Mon Aug 25 04:44:43 2003
++++ linux-2.4.24/fs/stat.c Wed Mar 17 17:36:52 2004
+@@ -17,10 +17,12 @@
* Revalidate the inode. This is required for proper NFS attribute caching.
*/
static __inline__ int
{
struct inode * inode = dentry->d_inode;
- if (inode->i_op && inode->i_op->revalidate)
-+ if (!inode)
-+ return -ENOENT;
+ if (inode->i_op && inode->i_op->revalidate_it)
+ return inode->i_op->revalidate_it(dentry, it);
+ else if (inode->i_op && inode->i_op->revalidate)
return inode->i_op->revalidate(dentry);
return 0;
}
-@@ -135,13 +139,15 @@ static int cp_new_stat(struct inode * in
+@@ -137,13 +139,15 @@ static int cp_new_stat(struct inode * in
asmlinkage long sys_stat(char * filename, struct __old_kernel_stat * statbuf)
{
struct nameidata nd;
path_release(&nd);
}
return error;
-@@ -151,13 +157,15 @@ asmlinkage long sys_stat(char * filename
+@@ -153,13 +157,15 @@ asmlinkage long sys_stat(char * filename
asmlinkage long sys_newstat(char * filename, struct stat * statbuf)
{
struct nameidata nd;
path_release(&nd);
}
return error;
-@@ -172,13 +180,15 @@ asmlinkage long sys_newstat(char * filen
+@@ -174,13 +180,15 @@ asmlinkage long sys_newstat(char * filen
asmlinkage long sys_lstat(char * filename, struct __old_kernel_stat * statbuf)
{
struct nameidata nd;
path_release(&nd);
}
return error;
-@@ -189,13 +199,15 @@ asmlinkage long sys_lstat(char * filenam
+@@ -191,13 +199,15 @@ asmlinkage long sys_lstat(char * filenam
asmlinkage long sys_newlstat(char * filename, struct stat * statbuf)
{
struct nameidata nd;
path_release(&nd);
}
return error;
-@@ -216,7 +228,7 @@ asmlinkage long sys_fstat(unsigned int f
+@@ -218,7 +228,7 @@ asmlinkage long sys_fstat(unsigned int f
if (f) {
struct dentry * dentry = f->f_dentry;
if (!err)
err = cp_old_stat(dentry->d_inode, statbuf);
fput(f);
-@@ -235,7 +247,7 @@ asmlinkage long sys_newfstat(unsigned in
+@@ -237,7 +247,7 @@ asmlinkage long sys_newfstat(unsigned in
if (f) {
struct dentry * dentry = f->f_dentry;
if (!err)
err = cp_new_stat(dentry->d_inode, statbuf);
fput(f);
-@@ -257,7 +269,7 @@ asmlinkage long sys_readlink(const char
+@@ -259,7 +269,7 @@ asmlinkage long sys_readlink(const char
error = -EINVAL;
if (inode->i_op && inode->i_op->readlink &&
UPDATE_ATIME(inode);
error = inode->i_op->readlink(nd.dentry, buf, bufsiz);
}
-@@ -333,12 +345,14 @@ asmlinkage long sys_stat64(char * filena
+@@ -335,12 +345,14 @@ asmlinkage long sys_stat64(char * filena
{
struct nameidata nd;
int error;
path_release(&nd);
}
return error;
-@@ -348,12 +362,14 @@ asmlinkage long sys_lstat64(char * filen
+@@ -350,12 +362,14 @@ asmlinkage long sys_lstat64(char * filen
{
struct nameidata nd;
int error;
path_release(&nd);
}
return error;
-@@ -368,7 +384,7 @@ asmlinkage long sys_fstat64(unsigned lon
+@@ -370,7 +384,7 @@ asmlinkage long sys_fstat64(unsigned lon
if (f) {
struct dentry * dentry = f->f_dentry;
if (!err)
err = cp_new_stat64(dentry->d_inode, statbuf);
fput(f);
---- linux-2.4.20-vanilla/include/linux/dcache.h~vfs_intent-2.4.20-vanilla 2003-05-16 05:29:15.000000000 +0400
-+++ linux-2.4.20-vanilla-alexey/include/linux/dcache.h 2003-09-17 21:05:42.000000000 +0400
+Index: linux-2.4.24/include/linux/dcache.h
+===================================================================
+--- linux-2.4.24.orig/include/linux/dcache.h Thu Nov 28 15:53:15 2002
++++ linux-2.4.24/include/linux/dcache.h Wed Mar 17 17:36:14 2004
@@ -6,6 +6,51 @@
#include <asm/atomic.h>
#include <linux/mount.h>
extern spinlock_t dcache_lock;
---- linux-2.4.20-vanilla/include/linux/fs.h~vfs_intent-2.4.20-vanilla 2003-09-17 21:05:03.000000000 +0400
-+++ linux-2.4.20-vanilla-alexey/include/linux/fs.h 2003-09-17 21:05:04.000000000 +0400
+Index: linux-2.4.24/include/linux/fs.h
+===================================================================
+--- linux-2.4.24.orig/include/linux/fs.h Wed Mar 17 17:36:14 2004
++++ linux-2.4.24/include/linux/fs.h Wed Mar 17 17:36:14 2004
@@ -73,6 +73,7 @@ extern int leases_enable, dir_notify_ena
#define FMODE_READ 1
#define READ 0
#define WRITE 1
-@@ -338,6 +339,9 @@ extern void set_bh_page(struct buffer_he
+@@ -340,6 +341,9 @@ extern void set_bh_page(struct buffer_he
#define ATTR_MTIME_SET 256
#define ATTR_FORCE 512 /* Not a change, but a change it */
#define ATTR_ATTR_FLAG 1024
/*
* This is the Inode Attributes structure, used for notify_change(). It
-@@ -471,6 +475,7 @@ struct inode {
+@@ -478,6 +482,7 @@ struct inode {
struct pipe_inode_info *i_pipe;
struct block_device *i_bdev;
struct char_device *i_cdev;
unsigned long i_dnotify_mask; /* Directory notify events */
struct dnotify_struct *i_dnotify; /* for directory notifications */
-@@ -542,6 +547,7 @@ struct file {
+@@ -582,6 +587,7 @@ struct file {
/* needed for tty driver, and maybe others */
void *private_data;
/* preallocated helper kiobuf to speedup O_DIRECT */
struct kiobuf *f_iobuf;
-@@ -661,6 +667,7 @@ struct nameidata {
+@@ -702,6 +708,7 @@ struct nameidata {
struct qstr last;
unsigned int flags;
int last_type;
+ struct lookup_intent *intent;
};
- #define DQUOT_USR_ENABLED 0x01 /* User diskquotas enabled */
-@@ -794,7 +801,8 @@ extern int vfs_symlink(struct inode *, s
+ /*
+@@ -822,7 +829,8 @@ extern int vfs_symlink(struct inode *, s
extern int vfs_link(struct dentry *, struct inode *, struct dentry *);
extern int vfs_rmdir(struct inode *, struct dentry *);
extern int vfs_unlink(struct inode *, struct dentry *);
/*
* File types
-@@ -854,21 +862,32 @@ struct file_operations {
+@@ -884,21 +892,32 @@ struct file_operations {
struct inode_operations {
int (*create) (struct inode *,struct dentry *,int);
int (*getattr) (struct dentry *, struct iattr *);
int (*setxattr) (struct dentry *, const char *, void *, size_t, int);
ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
-@@ -1070,10 +1089,14 @@ static inline int get_lease(struct inode
+@@ -1094,10 +1113,14 @@ static inline int get_lease(struct inode
asmlinkage long sys_open(const char *, int, int);
asmlinkage long sys_close(unsigned int); /* yes, it's really unsigned */
extern int filp_close(struct file *, fl_owner_t id);
extern char * getname(const char *);
-@@ -1335,6 +1358,7 @@ typedef int (*read_actor_t)(read_descrip
+@@ -1386,6 +1409,7 @@ typedef int (*read_actor_t)(read_descrip
extern loff_t default_llseek(struct file *file, loff_t offset, int origin);
extern int FASTCALL(__user_walk(const char *, unsigned, struct nameidata *));
extern int FASTCALL(path_init(const char *, unsigned, struct nameidata *));
extern int FASTCALL(path_walk(const char *, struct nameidata *));
extern int FASTCALL(path_lookup(const char *, unsigned, struct nameidata *));
-@@ -1346,6 +1370,8 @@ extern struct dentry * lookup_one_len(co
+@@ -1397,6 +1421,8 @@ extern struct dentry * lookup_one_len(co
extern struct dentry * lookup_hash(struct qstr *, struct dentry *);
#define user_path_walk(name,nd) __user_walk(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, nd)
#define user_path_walk_link(name,nd) __user_walk(name, LOOKUP_POSITIVE, nd)
+#define user_path_walk_it(name,nd,it) __user_walk_it(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, nd, it)
+#define user_path_walk_link_it(name,nd,it) __user_walk_it(name, LOOKUP_POSITIVE, nd, it)
+ extern void inode_init_once(struct inode *);
extern void iput(struct inode *);
- extern void force_delete(struct inode *);
-@@ -1455,6 +1481,8 @@ extern struct file_operations generic_ro
+@@ -1500,6 +1526,8 @@ extern struct file_operations generic_ro
extern int vfs_readlink(struct dentry *, char *, int, const char *);
extern int vfs_follow_link(struct nameidata *, const char *);
extern int page_readlink(struct dentry *, char *, int);
extern int page_follow_link(struct dentry *, struct nameidata *);
extern struct inode_operations page_symlink_inode_operations;
---- linux-2.4.20-vanilla/include/linux/fs_struct.h~vfs_intent-2.4.20-vanilla 2001-07-14 02:10:44.000000000 +0400
-+++ linux-2.4.20-vanilla-alexey/include/linux/fs_struct.h 2003-09-17 21:05:04.000000000 +0400
+Index: linux-2.4.24/include/linux/fs_struct.h
+===================================================================
+--- linux-2.4.24.orig/include/linux/fs_struct.h Fri Jul 13 15:10:44 2001
++++ linux-2.4.24/include/linux/fs_struct.h Wed Mar 17 17:36:14 2004
@@ -34,10 +34,12 @@ static inline void set_fs_root(struct fs
write_lock(&fs->lock);
old_root = fs->root;
dput(old_pwd);
mntput(old_pwdmnt);
}
---- linux-2.4.20-vanilla/kernel/ksyms.c~vfs_intent-2.4.20-vanilla 2003-09-17 21:05:03.000000000 +0400
-+++ linux-2.4.20-vanilla-alexey/kernel/ksyms.c 2003-09-17 21:05:04.000000000 +0400
-@@ -269,6 +269,7 @@ EXPORT_SYMBOL(read_cache_page);
- EXPORT_SYMBOL(set_page_dirty);
+Index: linux-2.4.24/kernel/ksyms.c
+===================================================================
+--- linux-2.4.24.orig/kernel/ksyms.c Wed Mar 17 17:36:14 2004
++++ linux-2.4.24/kernel/ksyms.c Wed Mar 17 17:36:14 2004
+@@ -275,6 +275,7 @@ EXPORT_SYMBOL(set_page_dirty);
+ EXPORT_SYMBOL(mark_page_accessed);
EXPORT_SYMBOL(vfs_readlink);
EXPORT_SYMBOL(vfs_follow_link);
+EXPORT_SYMBOL(vfs_follow_link_it);
EXPORT_SYMBOL(page_readlink);
EXPORT_SYMBOL(page_follow_link);
EXPORT_SYMBOL(page_symlink_inode_operations);
---- linux-2.4.20-vanilla/kernel/fork.c~vfs_intent-2.4.20-vanilla 2003-05-16 05:29:15.000000000 +0400
-+++ linux-2.4.20-vanilla-alexey/kernel/fork.c 2003-09-17 21:05:04.000000000 +0400
-@@ -384,10 +384,13 @@ static inline struct fs_struct *__copy_f
+Index: linux-2.4.24/kernel/fork.c
+===================================================================
+--- linux-2.4.24.orig/kernel/fork.c Fri Nov 28 10:26:21 2003
++++ linux-2.4.24/kernel/fork.c Wed Mar 17 17:36:14 2004
+@@ -386,10 +386,13 @@ static inline struct fs_struct *__copy_f
fs->umask = old->umask;
read_lock(&old->lock);
fs->rootmnt = mntget(old->rootmnt);
fs->altrootmnt = mntget(old->altrootmnt);
fs->altroot = dget(old->altroot);
} else {
---- linux-2.4.20-vanilla/kernel/exit.c~vfs_intent-2.4.20-vanilla 2003-05-16 05:29:15.000000000 +0400
-+++ linux-2.4.20-vanilla-alexey/kernel/exit.c 2003-09-17 21:05:04.000000000 +0400
+Index: linux-2.4.24/kernel/exit.c
+===================================================================
+--- linux-2.4.24.orig/kernel/exit.c Thu Nov 28 15:53:15 2002
++++ linux-2.4.24/kernel/exit.c Wed Mar 17 17:36:14 2004
@@ -238,11 +238,14 @@ static inline void __put_fs_struct(struc
{
/* No need to hold fs->lock if we are killing it */
dput(fs->altroot);
mntput(fs->altrootmnt);
}
-
-_
kernel/ksyms.c | 1
12 files changed, 558 insertions(+), 128 deletions(-)
-Index: linux-2.4.21-chaos/fs/dcache.c
+Index: linux-ia64/fs/dcache.c
===================================================================
---- linux-2.4.21-chaos.orig/fs/dcache.c 2003-09-19 03:49:54.000000000 +0400
-+++ linux-2.4.21-chaos/fs/dcache.c 2003-12-12 17:02:47.000000000 +0300
-@@ -186,6 +186,13 @@
+--- linux-ia64.orig/fs/dcache.c 2004-03-17 15:47:15.000000000 -0800
++++ linux-ia64/fs/dcache.c 2004-03-17 16:05:28.000000000 -0800
+@@ -186,6 +186,13 @@ int d_invalidate(struct dentry * dentry)
spin_unlock(&dcache_lock);
return 0;
}
/*
* Check whether to do a partial shrink_dcache
* to get rid of unused child entries.
-@@ -847,13 +854,19 @@
+@@ -850,13 +857,19 @@ void d_delete(struct dentry * dentry)
* Adds a dentry to the hash according to its name.
*/
}
#define do_switch(x,y) do { \
-Index: linux-2.4.21-chaos/fs/exec.c
+Index: linux-ia64/fs/exec.c
===================================================================
---- linux-2.4.21-chaos.orig/fs/exec.c 2003-12-05 07:55:47.000000000 +0300
-+++ linux-2.4.21-chaos/fs/exec.c 2003-12-12 17:02:47.000000000 +0300
-@@ -119,8 +119,10 @@
+--- linux-ia64.orig/fs/exec.c 2004-03-17 15:47:15.000000000 -0800
++++ linux-ia64/fs/exec.c 2004-03-17 16:05:28.000000000 -0800
+@@ -119,8 +119,10 @@ asmlinkage long sys_uselib(const char *
struct file * file;
struct nameidata nd;
int error;
if (error)
goto out;
-@@ -132,7 +134,8 @@
+@@ -132,7 +134,8 @@ asmlinkage long sys_uselib(const char *
if (error)
goto exit;
error = PTR_ERR(file);
if (IS_ERR(file))
goto out;
-@@ -400,8 +403,10 @@
+@@ -400,8 +403,10 @@ struct file *open_exec(const char *name)
struct inode *inode;
struct file *file;
int err = 0;
file = ERR_PTR(err);
if (!err) {
inode = nd.dentry->d_inode;
-@@ -413,7 +418,8 @@
+@@ -413,7 +418,8 @@ struct file *open_exec(const char *name)
err = -EACCES;
file = ERR_PTR(err);
if (!err) {
if (!IS_ERR(file)) {
err = deny_write_access(file);
if (err) {
-@@ -425,6 +431,7 @@
+@@ -425,6 +431,7 @@ out:
return file;
}
}
path_release(&nd);
}
goto out;
-@@ -1348,7 +1355,7 @@
+@@ -1348,7 +1355,7 @@ int do_coredump(long signr, int exit_cod
goto close_fail;
if (!file->f_op->write)
goto close_fail;
goto close_fail;
retval = binfmt->core_dump(signr, regs, file);
-Index: linux-2.4.21-chaos/fs/namei.c
+Index: linux-ia64/fs/namei.c
===================================================================
---- linux-2.4.21-chaos.orig/fs/namei.c 2003-07-15 04:41:01.000000000 +0400
-+++ linux-2.4.21-chaos/fs/namei.c 2003-12-12 17:03:37.000000000 +0300
+--- linux-ia64.orig/fs/namei.c 2004-03-17 15:47:15.000000000 -0800
++++ linux-ia64/fs/namei.c 2004-03-17 16:06:13.000000000 -0800
@@ -94,6 +94,13 @@
* XEmacs seems to be relying on it...
*/
/* In order to reduce some races, while at the same time doing additional
* checking and hopefully speeding things up, we copy filenames to the
* kernel data space before using them..
-@@ -260,10 +267,19 @@
+@@ -260,10 +267,19 @@ void path_release(struct nameidata *nd)
* Internal lookup() using the new generic dcache.
* SMP-safe
*/
if (dentry && dentry->d_op && dentry->d_op->d_revalidate) {
if (!dentry->d_op->d_revalidate(dentry, flags) && !d_invalidate(dentry)) {
dput(dentry);
-@@ -281,11 +297,15 @@
+@@ -281,11 +297,15 @@ static struct dentry * cached_lookup(str
* make sure that nobody added the entry to the dcache in the meantime..
* SMP-safe
*/
down(&dir->i_sem);
/*
* First re-do the cached lookup just in case it was created
-@@ -300,6 +320,9 @@
+@@ -300,6 +320,9 @@ static struct dentry * real_lookup(struc
result = ERR_PTR(-ENOMEM);
if (dentry) {
lock_kernel();
result = dir->i_op->lookup(dir, dentry);
unlock_kernel();
if (result)
-@@ -321,6 +344,15 @@
+@@ -321,6 +344,15 @@ static struct dentry * real_lookup(struc
dput(result);
result = ERR_PTR(-ENOENT);
}
}
return result;
}
-@@ -332,7 +364,8 @@
+@@ -332,7 +364,8 @@ static struct dentry * real_lookup(struc
* Without that kind of total limit, nasty chains of consecutive
* symlinks can cause almost arbitrarily long lookups.
*/
{
int err;
if (current->link_count >= 8)
-@@ -346,10 +379,12 @@
+@@ -346,10 +379,12 @@ static inline int do_follow_link(struct
current->link_count++;
current->total_link_count++;
UPDATE_ATIME(dentry->d_inode);
path_release(nd);
return -ELOOP;
}
-@@ -447,7 +482,8 @@
+@@ -447,7 +482,8 @@ static inline void follow_dotdot(struct
*
* We expect 'base' to be positive and a directory.
*/
{
struct dentry *dentry;
struct inode *inode;
-@@ -524,12 +560,12 @@
+@@ -524,12 +560,12 @@ int link_path_walk(const char * name, st
break;
}
/* This does the actual lookups.. */
err = PTR_ERR(dentry);
if (IS_ERR(dentry))
break;
-@@ -547,7 +583,7 @@
+@@ -547,7 +583,7 @@ int link_path_walk(const char * name, st
goto out_dput;
if (inode->i_op->follow_link) {
dput(dentry);
if (err)
goto return_err;
-@@ -563,7 +599,7 @@
+@@ -563,7 +599,7 @@ int link_path_walk(const char * name, st
nd->dentry = dentry;
}
err = -ENOTDIR;
break;
continue;
/* here ends the main loop */
-@@ -590,12 +626,12 @@
+@@ -590,12 +626,12 @@ last_component:
if (err < 0)
break;
}
err = PTR_ERR(dentry);
if (IS_ERR(dentry))
break;
-@@ -605,7 +641,7 @@
+@@ -605,7 +641,7 @@ last_component:
inode = dentry->d_inode;
if ((lookup_flags & LOOKUP_FOLLOW)
&& inode && inode->i_op && inode->i_op->follow_link) {
dput(dentry);
if (err)
goto return_err;
-@@ -619,7 +655,8 @@
+@@ -619,7 +655,8 @@ last_component:
goto no_inode;
if (lookup_flags & LOOKUP_DIRECTORY) {
err = -ENOTDIR;
break;
}
goto return_base;
-@@ -643,6 +680,25 @@
+@@ -643,6 +680,27 @@ return_reval:
* Check the cached dentry for staleness.
*/
dentry = nd->dentry;
+ &dentry->d_name, 0, NULL);
+ d_invalidate(dentry);
+ dput(dentry);
-+ if (IS_ERR(new)) {
++ if (IS_ERR(new)) {
+ err = PTR_ERR(new);
+ break;
+ }
+ nd->dentry = new;
+ }
++ if (!nd->dentry->d_inode)
++ goto no_inode;
+ } else
if (dentry && dentry->d_op && dentry->d_op->d_revalidate) {
err = -ESTALE;
if (!dentry->d_op->d_revalidate(dentry, 0)) {
-@@ -656,15 +712,28 @@
+@@ -656,15 +714,28 @@ out_dput:
dput(dentry);
break;
}
}
/* SMP-safe */
-@@ -749,6 +818,17 @@
+@@ -749,6 +820,17 @@ walk_init_root(const char *name, struct
}
/* SMP-safe */
int path_lookup(const char *path, unsigned flags, struct nameidata *nd)
{
int error = 0;
-@@ -763,6 +843,7 @@
+@@ -763,6 +845,7 @@ int path_init(const char *name, unsigned
{
nd->last_type = LAST_ROOT; /* if there are only slashes... */
nd->flags = flags;
if (*name=='/')
return walk_init_root(name,nd);
read_lock(¤t->fs->lock);
-@@ -777,7 +858,8 @@
+@@ -777,7 +860,8 @@ int path_init(const char *name, unsigned
* needs parent already locked. Doesn't follow mounts.
* SMP-safe.
*/
{
struct dentry * dentry;
struct inode *inode;
-@@ -800,13 +882,16 @@
+@@ -800,13 +884,16 @@ struct dentry * lookup_hash(struct qstr
goto out;
}
dentry = inode->i_op->lookup(inode, new);
unlock_kernel();
if (!dentry)
-@@ -818,6 +903,12 @@
+@@ -818,6 +905,12 @@ out:
return dentry;
}
/* SMP-safe */
struct dentry * lookup_one_len(const char * name, struct dentry * base, int len)
{
-@@ -839,7 +930,7 @@
+@@ -839,7 +932,7 @@ struct dentry * lookup_one_len(const cha
}
this.hash = end_name_hash(hash);
access:
return ERR_PTR(-EACCES);
}
-@@ -870,6 +961,23 @@
+@@ -870,6 +963,23 @@ int __user_walk(const char *name, unsign
return err;
}
/*
* It's inline, so penalty for filesystems that don't use sticky bit is
* minimal.
-@@ -967,7 +1075,8 @@
+@@ -967,7 +1077,8 @@ static inline int lookup_flags(unsigned
return retval;
}
{
int error;
-@@ -980,12 +1089,15 @@
+@@ -980,12 +1091,15 @@ int vfs_create(struct inode *dir, struct
goto exit_lock;
error = -EACCES; /* shouldn't it be ENOSYS? */
unlock_kernel();
exit_lock:
up(&dir->i_zombie);
-@@ -994,6 +1106,11 @@
+@@ -994,6 +1108,11 @@ exit_lock:
return error;
}
/*
* open_namei()
*
-@@ -1008,7 +1125,8 @@
+@@ -1008,7 +1127,8 @@ exit_lock:
* for symlinks (where the permissions are checked later).
* SMP-safe
*/
{
int acc_mode, error = 0;
struct inode *inode;
-@@ -1018,11 +1136,14 @@
+@@ -1018,11 +1138,14 @@ int open_namei(const char * pathname, in
acc_mode = ACC_MODE(flag);
if (error)
return error;
dentry = nd->dentry;
-@@ -1032,6 +1153,10 @@
+@@ -1032,6 +1155,10 @@ int open_namei(const char * pathname, in
/*
* Create - we need to know the parent.
*/
error = path_lookup(pathname, LOOKUP_PARENT, nd);
if (error)
return error;
-@@ -1047,7 +1172,7 @@
+@@ -1047,7 +1174,7 @@ int open_namei(const char * pathname, in
dir = nd->dentry;
down(&dir->d_inode->i_sem);
do_last:
error = PTR_ERR(dentry);
-@@ -1056,11 +1181,12 @@
+@@ -1056,11 +1183,12 @@ do_last:
goto exit;
}
up(&dir->d_inode->i_sem);
dput(nd->dentry);
nd->dentry = dentry;
-@@ -1164,7 +1290,7 @@
+@@ -1164,7 +1292,7 @@ ok:
if (!error) {
DQUOT_INIT(inode);
}
put_write_access(inode);
if (error)
-@@ -1176,8 +1302,10 @@
+@@ -1176,8 +1304,10 @@ ok:
return 0;
exit_dput:
path_release(nd);
return error;
-@@ -1196,7 +1324,10 @@
+@@ -1196,7 +1326,10 @@ do_link:
* are done. Procfs-like symlinks just set LAST_BIND.
*/
UPDATE_ATIME(dentry->d_inode);
dput(dentry);
if (error)
return error;
-@@ -1218,13 +1349,20 @@
+@@ -1218,13 +1351,20 @@ do_link:
}
dir = nd->dentry;
down(&dir->d_inode->i_sem);
{
struct dentry *dentry;
-@@ -1232,7 +1370,7 @@
+@@ -1232,7 +1372,7 @@ static struct dentry *lookup_create(stru
dentry = ERR_PTR(-EEXIST);
if (nd->last_type != LAST_NORM)
goto fail;
if (IS_ERR(dentry))
goto fail;
if (!is_dir && nd->last.name[nd->last.len] && !dentry->d_inode)
-@@ -1288,7 +1426,16 @@
+@@ -1288,7 +1428,20 @@ asmlinkage long sys_mknod(const char * f
error = path_lookup(tmp, LOOKUP_PARENT, &nd);
if (error)
goto out;
- dentry = lookup_create(&nd, 0);
+
++ if (nd.last_type != LAST_NORM) {
++ error = -EEXIST;
++ goto out2;
++ }
+ if (nd.dentry->d_inode->i_op->mknod_raw) {
+ struct inode_operations *op = nd.dentry->d_inode->i_op;
+ error = op->mknod_raw(&nd, mode, dev);
error = PTR_ERR(dentry);
if (!IS_POSIXACL(nd.dentry->d_inode))
-@@ -1310,6 +1457,7 @@
+@@ -1310,6 +1463,7 @@ asmlinkage long sys_mknod(const char * f
dput(dentry);
}
up(&nd.dentry->d_inode->i_sem);
path_release(&nd);
out:
putname(tmp);
-@@ -1357,7 +1505,14 @@
+@@ -1357,7 +1511,18 @@ asmlinkage long sys_mkdir(const char * p
error = path_lookup(tmp, LOOKUP_PARENT, &nd);
if (error)
goto out;
- dentry = lookup_create(&nd, 1);
++ if (nd.last_type != LAST_NORM) {
++ error = -EEXIST;
++ goto out2;
++ }
+ if (nd.dentry->d_inode->i_op->mkdir_raw) {
+ struct inode_operations *op = nd.dentry->d_inode->i_op;
+ error = op->mkdir_raw(&nd, mode);
error = PTR_ERR(dentry);
if (!IS_ERR(dentry)) {
if (!IS_POSIXACL(nd.dentry->d_inode))
-@@ -1366,6 +1521,7 @@
+@@ -1366,6 +1531,7 @@ asmlinkage long sys_mkdir(const char * p
dput(dentry);
}
up(&nd.dentry->d_inode->i_sem);
path_release(&nd);
out:
putname(tmp);
-@@ -1466,8 +1622,16 @@
+@@ -1466,8 +1632,16 @@ asmlinkage long sys_rmdir(const char * p
error = -EBUSY;
goto exit1;
}
error = PTR_ERR(dentry);
if (!IS_ERR(dentry)) {
error = vfs_rmdir(nd.dentry->d_inode, dentry);
-@@ -1525,8 +1689,15 @@
+@@ -1525,8 +1699,15 @@ asmlinkage long sys_unlink(const char *
error = -EISDIR;
if (nd.last_type != LAST_NORM)
goto exit1;
error = PTR_ERR(dentry);
if (!IS_ERR(dentry)) {
/* Why not before? Because we want correct error value */
-@@ -1593,15 +1764,23 @@
+@@ -1593,15 +1774,27 @@ asmlinkage long sys_symlink(const char *
error = path_lookup(to, LOOKUP_PARENT, &nd);
if (error)
goto out;
- dentry = lookup_create(&nd, 0);
++ if (nd.last_type != LAST_NORM) {
++ error = -EEXIST;
++ goto out2;
++ }
+ if (nd.dentry->d_inode->i_op->symlink_raw) {
+ struct inode_operations *op = nd.dentry->d_inode->i_op;
+ error = op->symlink_raw(&nd, from);
putname(to);
}
putname(from);
-@@ -1677,7 +1856,14 @@
+@@ -1677,7 +1870,18 @@ asmlinkage long sys_link(const char * ol
error = -EXDEV;
if (old_nd.mnt != nd.mnt)
goto out_release;
- new_dentry = lookup_create(&nd, 0);
++ if (nd.last_type != LAST_NORM) {
++ error = -EEXIST;
++ goto out_release;
++ }
+ if (nd.dentry->d_inode->i_op->link_raw) {
+ struct inode_operations *op = nd.dentry->d_inode->i_op;
+ error = op->link_raw(&old_nd, &nd);
error = PTR_ERR(new_dentry);
if (!IS_ERR(new_dentry)) {
error = vfs_link(old_nd.dentry, nd.dentry->d_inode, new_dentry);
-@@ -1721,7 +1907,7 @@
+@@ -1721,7 +1925,7 @@ exit:
* locking].
*/
int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
{
int error;
struct inode *target;
-@@ -1800,7 +1986,7 @@
+@@ -1800,7 +2004,7 @@ out_unlock:
}
int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry,
{
int error;
-@@ -1888,9 +2074,18 @@
+@@ -1888,9 +2092,18 @@ static inline int do_rename(const char *
if (newnd.last_type != LAST_NORM)
goto exit2;
error = PTR_ERR(old_dentry);
if (IS_ERR(old_dentry))
goto exit3;
-@@ -1906,16 +2101,16 @@
+@@ -1906,16 +2119,16 @@ static inline int do_rename(const char *
if (newnd.last.name[newnd.last.len])
goto exit4;
}
dput(new_dentry);
exit4:
dput(old_dentry);
-@@ -1966,20 +2161,26 @@
+@@ -1966,20 +2179,26 @@ out:
}
static inline int
out:
if (current->link_count || res || nd->last_type!=LAST_NORM)
return res;
-@@ -2003,7 +2204,13 @@
+@@ -2003,7 +2222,13 @@ fail:
int vfs_follow_link(struct nameidata *nd, const char *link)
{
}
/* get the link contents into pagecache */
-@@ -2045,7 +2252,7 @@
+@@ -2045,7 +2270,7 @@ int page_follow_link(struct dentry *dent
{
struct page *page = NULL;
char *s = page_getlink(dentry, &page);
if (page) {
kunmap(page);
page_cache_release(page);
-Index: linux-2.4.21-chaos/fs/namespace.c
+Index: linux-ia64/fs/namespace.c
===================================================================
---- linux-2.4.21-chaos.orig/fs/namespace.c 2003-07-15 04:41:01.000000000 +0400
-+++ linux-2.4.21-chaos/fs/namespace.c 2003-12-12 17:02:47.000000000 +0300
-@@ -98,6 +98,7 @@
+--- linux-ia64.orig/fs/namespace.c 2004-03-17 15:47:15.000000000 -0800
++++ linux-ia64/fs/namespace.c 2004-03-17 16:05:28.000000000 -0800
+@@ -98,6 +98,7 @@ static void detach_mnt(struct vfsmount *
{
old_nd->dentry = mnt->mnt_mountpoint;
old_nd->mnt = mnt->mnt_parent;
mnt->mnt_parent = mnt;
mnt->mnt_mountpoint = mnt->mnt_root;
list_del_init(&mnt->mnt_child);
-@@ -109,6 +110,7 @@
+@@ -109,6 +110,7 @@ static void attach_mnt(struct vfsmount *
{
mnt->mnt_parent = mntget(nd->mnt);
mnt->mnt_mountpoint = dget(nd->dentry);
list_add(&mnt->mnt_hash, mount_hashtable+hash(nd->mnt, nd->dentry));
list_add(&mnt->mnt_child, &nd->mnt->mnt_mounts);
nd->dentry->d_mounted++;
-@@ -488,14 +490,17 @@
+@@ -488,14 +490,17 @@ static int do_loopback(struct nameidata
{
struct nameidata old_nd;
struct vfsmount *mnt = NULL;
down_write(¤t->namespace->sem);
err = -EINVAL;
-@@ -518,6 +523,7 @@
+@@ -518,6 +523,7 @@ static int do_loopback(struct nameidata
}
up_write(¤t->namespace->sem);
path_release(&old_nd);
return err;
}
-@@ -701,6 +707,7 @@
+@@ -701,6 +707,7 @@ long do_mount(char * dev_name, char * di
unsigned long flags, void *data_page)
{
struct nameidata nd;
int retval = 0;
int mnt_flags = 0;
-@@ -725,10 +732,11 @@
+@@ -725,10 +732,11 @@ long do_mount(char * dev_name, char * di
flags &= ~(MS_NOSUID|MS_NOEXEC|MS_NODEV);
/* ... and get the mountpoint */
if (flags & MS_REMOUNT)
retval = do_remount(&nd, flags & ~MS_REMOUNT, mnt_flags,
data_page);
-@@ -739,6 +747,8 @@
+@@ -739,6 +747,8 @@ long do_mount(char * dev_name, char * di
else
retval = do_add_mount(&nd, type_page, flags, mnt_flags,
dev_name, data_page);
path_release(&nd);
return retval;
}
-@@ -904,6 +914,8 @@
+@@ -904,6 +914,8 @@ asmlinkage long sys_pivot_root(const cha
{
struct vfsmount *tmp;
struct nameidata new_nd, old_nd, parent_nd, root_parent, user_nd;
int error;
if (!capable(CAP_SYS_ADMIN))
-@@ -911,14 +923,14 @@
+@@ -911,14 +923,14 @@ asmlinkage long sys_pivot_root(const cha
lock_kernel();
if (error)
goto out1;
-@@ -973,8 +985,10 @@
+@@ -973,8 +985,10 @@ out2:
up(&old_nd.dentry->d_inode->i_zombie);
up_write(¤t->namespace->sem);
path_release(&user_nd);
path_release(&new_nd);
out0:
unlock_kernel();
-Index: linux-2.4.21-chaos/fs/open.c
+Index: linux-ia64/fs/open.c
===================================================================
---- linux-2.4.21-chaos.orig/fs/open.c 2003-07-15 04:41:01.000000000 +0400
-+++ linux-2.4.21-chaos/fs/open.c 2003-12-12 17:02:47.000000000 +0300
+--- linux-ia64.orig/fs/open.c 2004-03-17 15:47:15.000000000 -0800
++++ linux-ia64/fs/open.c 2004-03-17 16:05:28.000000000 -0800
@@ -19,6 +19,8 @@
#include <asm/uaccess.h>
int vfs_statfs(struct super_block *sb, struct statfs *buf)
{
-@@ -95,9 +97,10 @@
+@@ -95,9 +97,10 @@ void fd_install(unsigned int fd, struct
write_unlock(&files->file_lock);
}
int error;
struct iattr newattrs;
-@@ -109,7 +112,13 @@
+@@ -109,7 +112,13 @@ int do_truncate(struct dentry *dentry, l
down(&inode->i_sem);
newattrs.ia_size = length;
newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
up(&inode->i_sem);
up_write(&inode->i_alloc_sem);
return error;
-@@ -120,12 +129,13 @@
+@@ -120,12 +129,13 @@ static inline long do_sys_truncate(const
struct nameidata nd;
struct inode * inode;
int error;
if (error)
goto out;
inode = nd.dentry->d_inode;
-@@ -165,11 +175,13 @@
+@@ -165,11 +175,13 @@ static inline long do_sys_truncate(const
error = locks_verify_truncate(inode, NULL, length);
if (!error) {
DQUOT_INIT(inode);
path_release(&nd);
out:
return error;
-@@ -217,7 +229,7 @@
+@@ -217,7 +229,7 @@ static inline long do_sys_ftruncate(unsi
error = locks_verify_truncate(inode, file, length);
if (!error)
out_putf:
fput(file);
out:
-@@ -262,11 +274,13 @@
+@@ -262,11 +274,13 @@ asmlinkage long sys_utime(char * filenam
struct inode * inode;
struct iattr newattrs;
error = -EROFS;
if (IS_RDONLY(inode))
goto dput_and_out;
-@@ -281,11 +295,25 @@
+@@ -281,11 +295,25 @@ asmlinkage long sys_utime(char * filenam
goto dput_and_out;
newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
error = notify_change(nd.dentry, &newattrs);
dput_and_out:
path_release(&nd);
-@@ -306,12 +334,14 @@
+@@ -306,12 +334,14 @@ asmlinkage long sys_utimes(char * filena
struct inode * inode;
struct iattr newattrs;
error = -EROFS;
if (IS_RDONLY(inode))
goto dput_and_out;
-@@ -326,7 +356,20 @@
+@@ -326,7 +356,20 @@ asmlinkage long sys_utimes(char * filena
newattrs.ia_atime = times[0].tv_sec;
newattrs.ia_mtime = times[1].tv_sec;
newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
if (current->fsuid != inode->i_uid &&
(error = permission(inode,MAY_WRITE)) != 0)
goto dput_and_out;
-@@ -349,6 +392,7 @@
+@@ -349,6 +392,7 @@ asmlinkage long sys_access(const char *
int old_fsuid, old_fsgid;
kernel_cap_t old_cap;
int res;
if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */
return -EINVAL;
-@@ -366,13 +410,14 @@
+@@ -366,13 +410,14 @@ asmlinkage long sys_access(const char *
else
current->cap_effective = current->cap_permitted;
path_release(&nd);
}
-@@ -387,8 +432,9 @@
+@@ -387,8 +432,9 @@ asmlinkage long sys_chdir(const char * f
{
int error;
struct nameidata nd;
if (error)
goto out;
-@@ -399,6 +445,7 @@
+@@ -399,6 +445,7 @@ asmlinkage long sys_chdir(const char * f
set_fs_pwd(current->fs, nd.mnt, nd.dentry);
dput_and_out:
path_release(&nd);
out:
return error;
-@@ -438,9 +485,10 @@
+@@ -438,9 +485,10 @@ asmlinkage long sys_chroot(const char *
{
int error;
struct nameidata nd;
if (error)
goto out;
-@@ -456,39 +504,56 @@
+@@ -456,39 +504,56 @@ asmlinkage long sys_chroot(const char *
set_fs_altroot();
error = 0;
dput_and_out:
fput(file);
out:
return err;
-@@ -497,30 +562,14 @@
+@@ -497,30 +562,14 @@ out:
asmlinkage long sys_chmod(const char * filename, mode_t mode)
{
struct nameidata nd;
path_release(&nd);
out:
return error;
-@@ -540,6 +589,20 @@
+@@ -540,6 +589,20 @@ static int chown_common(struct dentry *
error = -EROFS;
if (IS_RDONLY(inode))
goto out;
error = -EPERM;
if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
goto out;
-@@ -644,6 +707,7 @@
+@@ -644,6 +707,7 @@ struct file *filp_open(const char * file
{
int namei_flags, error;
struct nameidata nd;
namei_flags = flags;
if ((namei_flags+1) & O_ACCMODE)
-@@ -651,14 +715,15 @@
+@@ -651,14 +715,15 @@ struct file *filp_open(const char * file
if (namei_flags & O_TRUNC)
namei_flags |= 2;
{
struct file * f;
struct inode *inode;
-@@ -695,7 +760,9 @@
+@@ -695,7 +760,9 @@ struct file *dentry_open(struct dentry *
}
if (f->f_op && f->f_op->open) {
if (error)
goto cleanup_all;
}
-@@ -708,6 +775,7 @@
+@@ -708,6 +775,7 @@ struct file *dentry_open(struct dentry *
inode->i_mapping->a_ops->direct_sector_IO)))
goto cleanup_all;
return f;
cleanup_all:
-@@ -722,11 +790,17 @@
+@@ -722,11 +790,17 @@ cleanup_all:
cleanup_file:
put_filp(f);
cleanup_dentry:
/*
* Find an empty file descriptor entry, and mark it busy.
*/
-Index: linux-2.4.21-chaos/fs/stat.c
+Index: linux-ia64/fs/stat.c
===================================================================
---- linux-2.4.21-chaos.orig/fs/stat.c 2003-09-19 03:49:54.000000000 +0400
-+++ linux-2.4.21-chaos/fs/stat.c 2003-12-12 17:02:47.000000000 +0300
-@@ -17,10 +17,14 @@
+--- linux-ia64.orig/fs/stat.c 2004-03-17 15:47:15.000000000 -0800
++++ linux-ia64/fs/stat.c 2004-03-17 16:06:13.000000000 -0800
+@@ -17,10 +17,12 @@
* Revalidate the inode. This is required for proper NFS attribute caching.
*/
static __inline__ int
{
struct inode * inode = dentry->d_inode;
- if (inode->i_op && inode->i_op->revalidate)
-+ if (!inode)
-+ return -ENOENT;
+ if (inode->i_op && inode->i_op->revalidate_it)
+ return inode->i_op->revalidate_it(dentry, it);
+ else if (inode->i_op && inode->i_op->revalidate)
return inode->i_op->revalidate(dentry);
return 0;
}
-@@ -143,13 +147,15 @@
+@@ -143,13 +145,15 @@ static int cp_new_stat(struct inode * in
asmlinkage long sys_stat(char * filename, struct __old_kernel_stat * statbuf)
{
struct nameidata nd;
path_release(&nd);
}
return error;
-@@ -159,13 +165,15 @@
+@@ -159,13 +163,15 @@ asmlinkage long sys_stat(char * filename
asmlinkage long sys_newstat(char * filename, struct stat * statbuf)
{
struct nameidata nd;
path_release(&nd);
}
return error;
-@@ -180,13 +188,15 @@
+@@ -180,13 +186,15 @@ asmlinkage long sys_newstat(char * filen
asmlinkage long sys_lstat(char * filename, struct __old_kernel_stat * statbuf)
{
struct nameidata nd;
path_release(&nd);
}
return error;
-@@ -197,13 +207,15 @@
+@@ -197,13 +205,15 @@ asmlinkage long sys_lstat(char * filenam
asmlinkage long sys_newlstat(char * filename, struct stat * statbuf)
{
struct nameidata nd;
path_release(&nd);
}
return error;
-@@ -224,7 +236,7 @@
+@@ -224,7 +234,7 @@ asmlinkage long sys_fstat(unsigned int f
if (f) {
struct dentry * dentry = f->f_dentry;
if (!err)
err = cp_old_stat(dentry->d_inode, statbuf);
fput(f);
-@@ -243,7 +255,7 @@
+@@ -243,7 +253,7 @@ asmlinkage long sys_newfstat(unsigned in
if (f) {
struct dentry * dentry = f->f_dentry;
if (!err)
err = cp_new_stat(dentry->d_inode, statbuf);
fput(f);
-@@ -265,7 +277,7 @@
+@@ -265,7 +275,7 @@ asmlinkage long sys_readlink(const char
error = -EINVAL;
if (inode->i_op && inode->i_op->readlink &&
UPDATE_ATIME(inode);
error = inode->i_op->readlink(nd.dentry, buf, bufsiz);
}
-@@ -341,12 +353,14 @@
+@@ -341,12 +351,14 @@ asmlinkage long sys_stat64(char * filena
{
struct nameidata nd;
int error;
path_release(&nd);
}
return error;
-@@ -356,12 +370,14 @@
+@@ -356,12 +368,14 @@ asmlinkage long sys_lstat64(char * filen
{
struct nameidata nd;
int error;
path_release(&nd);
}
return error;
-@@ -376,7 +392,7 @@
+@@ -376,7 +390,7 @@ asmlinkage long sys_fstat64(unsigned lon
if (f) {
struct dentry * dentry = f->f_dentry;
if (!err)
err = cp_new_stat64(dentry->d_inode, statbuf);
fput(f);
-Index: linux-2.4.21-chaos/include/linux/dcache.h
+Index: linux-ia64/include/linux/dcache.h
===================================================================
---- linux-2.4.21-chaos.orig/include/linux/dcache.h 2003-12-05 16:54:33.000000000 +0300
-+++ linux-2.4.21-chaos/include/linux/dcache.h 2003-12-12 17:02:47.000000000 +0300
+--- linux-ia64.orig/include/linux/dcache.h 2004-03-17 15:47:15.000000000 -0800
++++ linux-ia64/include/linux/dcache.h 2004-03-17 16:05:28.000000000 -0800
@@ -6,6 +6,51 @@
#include <asm/atomic.h>
#include <linux/mount.h>
/*
* linux/include/linux/dcache.h
-@@ -96,8 +141,22 @@
+@@ -96,8 +141,22 @@ struct dentry_operations {
int (*d_delete)(struct dentry *);
void (*d_release)(struct dentry *);
void (*d_iput)(struct dentry *, struct inode *);
/* the dentry parameter passed to d_hash and d_compare is the parent
* directory of the entries to be compared. It is used in case these
* functions need any directory specific information for determining
-@@ -129,6 +188,7 @@
+@@ -129,6 +188,7 @@ d_iput: no no yes
* s_nfsd_free_path semaphore will be down
*/
#define DCACHE_REFERENCED 0x0008 /* Recently used, don't discard. */
extern spinlock_t dcache_lock;
-Index: linux-2.4.21-chaos/include/linux/fs.h
+Index: linux-ia64/include/linux/fs.h
===================================================================
---- linux-2.4.21-chaos.orig/include/linux/fs.h 2003-12-12 17:02:46.000000000 +0300
-+++ linux-2.4.21-chaos/include/linux/fs.h 2003-12-12 17:02:47.000000000 +0300
-@@ -73,6 +73,7 @@
+--- linux-ia64.orig/include/linux/fs.h 2004-03-17 16:05:28.000000000 -0800
++++ linux-ia64/include/linux/fs.h 2004-03-17 16:05:52.000000000 -0800
+@@ -73,6 +73,7 @@ extern int leases_enable, dir_notify_ena
#define FMODE_READ 1
#define FMODE_WRITE 2
#define READ 0
#define WRITE 1
-@@ -359,6 +360,9 @@
+@@ -359,6 +360,9 @@ extern void set_bh_page(struct buffer_he
#define ATTR_MTIME_SET 256
#define ATTR_FORCE 512 /* Not a change, but a change it */
#define ATTR_ATTR_FLAG 1024
/*
* This is the Inode Attributes structure, used for notify_change(). It
-@@ -496,6 +500,7 @@
+@@ -496,6 +500,7 @@ struct inode {
struct pipe_inode_info *i_pipe;
struct block_device *i_bdev;
struct char_device *i_cdev;
unsigned long i_dnotify_mask; /* Directory notify events */
struct dnotify_struct *i_dnotify; /* for directory notifications */
-@@ -598,6 +603,7 @@
+@@ -598,6 +603,7 @@ struct file {
/* needed for tty driver, and maybe others */
void *private_data;
/* preallocated helper kiobuf to speedup O_DIRECT */
struct kiobuf *f_iobuf;
-@@ -726,6 +732,7 @@
+@@ -726,6 +732,7 @@ struct nameidata {
struct qstr last;
unsigned int flags;
int last_type;
};
/*
-@@ -846,7 +853,8 @@
+@@ -846,7 +853,8 @@ extern int vfs_symlink(struct inode *, s
extern int vfs_link(struct dentry *, struct inode *, struct dentry *);
extern int vfs_rmdir(struct inode *, struct dentry *);
extern int vfs_unlink(struct inode *, struct dentry *);
/*
* File types
-@@ -920,21 +928,32 @@
+@@ -920,21 +928,32 @@ struct file_operations {
struct inode_operations {
int (*create) (struct inode *,struct dentry *,int);
int (*getattr) (struct dentry *, struct iattr *);
int (*setxattr) (struct dentry *, const char *, const void *, size_t, int);
ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
-@@ -1131,10 +1150,14 @@
+@@ -1131,10 +1150,14 @@ static inline int get_lease(struct inode
asmlinkage long sys_open(const char *, int, int);
asmlinkage long sys_close(unsigned int); /* yes, it's really unsigned */
extern int filp_close(struct file *, fl_owner_t id);
extern char * getname(const char *);
-@@ -1425,6 +1448,7 @@
+@@ -1425,6 +1448,7 @@ typedef int (*read_actor_t)(read_descrip
extern loff_t default_llseek(struct file *file, loff_t offset, int origin);
extern int FASTCALL(__user_walk(const char *, unsigned, struct nameidata *));
extern int FASTCALL(path_init(const char *, unsigned, struct nameidata *));
extern int FASTCALL(path_walk(const char *, struct nameidata *));
extern int FASTCALL(path_lookup(const char *, unsigned, struct nameidata *));
-@@ -1436,6 +1460,8 @@
+@@ -1436,6 +1460,8 @@ extern struct dentry * lookup_one_len(co
extern struct dentry * lookup_hash(struct qstr *, struct dentry *);
#define user_path_walk(name,nd) __user_walk(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, nd)
#define user_path_walk_link(name,nd) __user_walk(name, LOOKUP_POSITIVE, nd)
extern void inode_init_once(struct inode *);
extern void iput(struct inode *);
-@@ -1599,6 +1625,8 @@
+@@ -1599,6 +1625,8 @@ extern struct file_operations generic_ro
extern int vfs_readlink(struct dentry *, char *, int, const char *);
extern int vfs_follow_link(struct nameidata *, const char *);
extern int page_readlink(struct dentry *, char *, int);
extern int page_follow_link(struct dentry *, struct nameidata *);
extern struct inode_operations page_symlink_inode_operations;
-Index: linux-2.4.21-chaos/include/linux/fs_struct.h
+Index: linux-ia64/include/linux/fs_struct.h
===================================================================
---- linux-2.4.21-chaos.orig/include/linux/fs_struct.h 2003-12-05 16:54:33.000000000 +0300
-+++ linux-2.4.21-chaos/include/linux/fs_struct.h 2003-12-12 17:02:47.000000000 +0300
-@@ -37,10 +37,12 @@
+--- linux-ia64.orig/include/linux/fs_struct.h 2004-03-17 15:47:15.000000000 -0800
++++ linux-ia64/include/linux/fs_struct.h 2004-03-17 16:05:28.000000000 -0800
+@@ -37,10 +37,12 @@ static inline void set_fs_root(struct fs
write_lock(&fs->lock);
old_root = fs->root;
old_rootmnt = fs->rootmnt;
dput(old_root);
mntput(old_rootmnt);
}
-@@ -60,10 +62,12 @@
+@@ -60,10 +62,12 @@ static inline void set_fs_pwd(struct fs_
write_lock(&fs->lock);
old_pwd = fs->pwd;
old_pwdmnt = fs->pwdmnt;
dput(old_pwd);
mntput(old_pwdmnt);
}
-Index: linux-2.4.21-chaos/kernel/exit.c
+Index: linux-ia64/kernel/exit.c
===================================================================
---- linux-2.4.21-chaos.orig/kernel/exit.c 2003-09-19 03:50:00.000000000 +0400
-+++ linux-2.4.21-chaos/kernel/exit.c 2003-12-12 17:02:47.000000000 +0300
-@@ -347,11 +347,14 @@
+--- linux-ia64.orig/kernel/exit.c 2004-03-17 15:47:15.000000000 -0800
++++ linux-ia64/kernel/exit.c 2004-03-17 16:05:28.000000000 -0800
+@@ -347,11 +347,14 @@ static inline void __put_fs_struct(struc
{
/* No need to hold fs->lock if we are killing it */
if (atomic_dec_and_test(&fs->count)) {
dput(fs->altroot);
mntput(fs->altrootmnt);
}
-Index: linux-2.4.21-chaos/kernel/fork.c
+Index: linux-ia64/kernel/fork.c
===================================================================
---- linux-2.4.21-chaos.orig/kernel/fork.c 2003-12-05 07:55:51.000000000 +0300
-+++ linux-2.4.21-chaos/kernel/fork.c 2003-12-12 17:02:47.000000000 +0300
-@@ -463,10 +463,13 @@
+--- linux-ia64.orig/kernel/fork.c 2004-03-17 15:47:15.000000000 -0800
++++ linux-ia64/kernel/fork.c 2004-03-17 16:05:28.000000000 -0800
+@@ -463,10 +463,13 @@ static inline struct fs_struct *__copy_f
fs->umask = old->umask;
read_lock(&old->lock);
fs->rootmnt = mntget(old->rootmnt);
fs->altrootmnt = mntget(old->altrootmnt);
fs->altroot = dget(old->altroot);
} else {
-Index: linux-2.4.21-chaos/kernel/ksyms.c
+Index: linux-ia64/kernel/ksyms.c
===================================================================
---- linux-2.4.21-chaos.orig/kernel/ksyms.c 2003-12-12 17:02:46.000000000 +0300
-+++ linux-2.4.21-chaos/kernel/ksyms.c 2003-12-12 17:02:47.000000000 +0300
-@@ -318,6 +318,7 @@
+--- linux-ia64.orig/kernel/ksyms.c 2004-03-17 16:05:28.000000000 -0800
++++ linux-ia64/kernel/ksyms.c 2004-03-17 16:05:51.000000000 -0800
+@@ -318,6 +318,7 @@ EXPORT_SYMBOL(read_cache_page);
EXPORT_SYMBOL(set_page_dirty);
EXPORT_SYMBOL(vfs_readlink);
EXPORT_SYMBOL(vfs_follow_link);
+ &dentry->d_name, 0, NULL);
+ d_invalidate(dentry);
+ dput(dentry);
-+ if (IS_ERR(new)) {
++ if (IS_ERR(new)) {
+ err = PTR_ERR(new);
+ break;
+ }
+ &dentry->d_name, 0, NULL);
+ d_invalidate(dentry);
+ dput(dentry);
-+ if (IS_ERR(new)) {
++ if (IS_ERR(new)) {
+ err = PTR_ERR(new);
+ break;
+ }
kernel_text_address-2.4.18-chaos.patch
pagecache-lock-2.4.21-chaos.patch
ext3-truncate-buffer-head.patch
+inode-max-readahead-2.4.24.patch
dev_read_only_hp_2.4.20.patch
exports_2.4.20-rh-hp.patch
lustre_version.patch
-vfs_intent-2.4.20-hp.patch
+vfs_intent-2.4.20-hp.patch
invalidate_show-2.4.20-hp.patch
export-truncate.patch
iod-stock-24-exports_hp.patch
ext3-xattr-ptr-arith-fix.patch
procfs-ndynamic-2.4.patch
ext3-truncate-buffer-head.patch
+inode-max-readahead-2.4.24.patch
+dcache_refcount_debug.patch
dev_read_only_2.4.20-rh.patch
exports_2.4.20-rh-hp.patch
lustre_version.patch
-vfs_intent-2.4.20-rh.patch
+vfs_intent-2.4.20-rh.patch
invalidate_show-2.4.20-rh.patch
iod-rmap-exports-2.4.20.patch
export-truncate.patch
ext3-no-write-super-chaos.patch
dynamic-locks-2.4.20-rh.patch
vfs-pdirops-2.4.20-rh.patch
-ext3-pdirops-2.4.18-chaos.patch
+ext3-pdirops-2.4.20-chaos.patch
tcp_zero_copy_2.4.20_chaos.patch
gpl_header-chaos-2.4.20.patch
add_page_private.patch
ext3-xattr-ptr-arith-fix.patch
procfs-ndynamic-2.4.patch
ext3-truncate-buffer-head.patch
+inode-max-readahead-2.4.24.patch
dev_read_only_2.4.20-rh.patch
exports_2.4.20-rh-hp.patch
lustre_version.patch
-vfs_intent-2.4.20-vanilla.patch
+vfs_intent-2.4.20-vanilla.patch
invalidate_show.patch
export-truncate.patch
iod-stock-exports-2.4.22.patch
3.5G-address-space-2.4.22-vanilla.patch
procfs-ndynamic-2.4.patch
ext3-truncate-buffer-head.patch
+inode-max-readahead-2.4.24.patch
int rc;
/* NB 1 request reference will be taken away by ll_intent_lock()
- * when I return
+ * when I return
* Note: libsysio require the inode must be generated here
*/
if ((it->it_op & IT_CREAT) || !it_disposition(it, DISP_LOOKUP_NEG)) {
rc = llu_glimpse_size(inode, &lvb);
if (rc) {
I_RELE(inode);
- RETURN(-EIO);
+ RETURN(rc);
}
lli->lli_st_size = lvb.lvb_size;
}
EXTRA_PROGRAMS = llite
COMMON_SRC = dcache.c dir.c file.c llite_close.c llite_lib.c llite_nfs.c rw.c \
- lproc_llite.c namei.c symlink.c sysctl.c llite_internal.h
+ lproc_llite.c namei.c symlink.c llite_internal.h
if LINUX25
llite_SOURCES = $(COMMON_SRC) rw26.c super25.c
obj-y += llite.o
llite-objs := llite_lib.o dcache.o super.o rw.o \
- super25.o file.o dir.o sysctl.o symlink.o namei.o lproc_llite.o \
+ super25.o file.o dir.o symlink.o namei.o lproc_llite.o \
rw26.o llite_nfs.o llite_close.o
* lockers handled correctly. fixes from bug 20 will make it
* more efficient by associating locks with pages and with
* batching writeback under the lock explicitly. */
- for (i = start, j = start % count ; i <= end;
+ for (i = start, j = start % count; i <= end;
j++, i++, tmpex.l_extent.start += PAGE_CACHE_SIZE) {
+ if (j == count) {
+ CDEBUG(D_PAGE, "skip index %lu to %lu\n", i, i + skip);
+ i += skip;
+ j = 0;
+ if (i > end)
+ break;
+ }
LASSERTF(tmpex.l_extent.start< lock->l_policy_data.l_extent.end,
LPU64" >= "LPU64" start %lu i %lu end %lu\n",
tmpex.l_extent.start, lock->l_policy_data.l_extent.end,
page = find_get_page(inode->i_mapping, i);
if (page == NULL)
- goto next_index;
- LL_CDEBUG_PAGE(D_PAGE, page, "locking page\n");
+ continue;
+ LL_CDEBUG_PAGE(D_PAGE, page, "lock page idx %lu ext "LPU64"\n",
+ i, tmpex.l_extent.start);
lock_page(page);
/* page->mapping to check with racing against teardown */
}
unlock_page(page);
page_cache_release(page);
-
- next_index:
- if (j == count) {
- i += skip;
- j = 0;
- }
}
+ LASSERTF(tmpex.l_extent.start <=
+ (lock->l_policy_data.l_extent.end == ~0ULL ? ~0ULL :
+ lock->l_policy_data.l_extent.end + 1),
+ "loop too long "LPU64" > "LPU64" start %lu i %lu end %lu\n",
+ tmpex.l_extent.start, lock->l_policy_data.l_extent.end,
+ start, i, end);
EXIT;
}
LCK_PR, &flags, ll_extent_lock_callback,
ldlm_completion_ast, ll_glimpse_callback, inode,
sizeof(*lvb), lustre_swab_ost_lvb, &lockh);
- if (rc > 0) {
+ if (rc != 0) {
CERROR("obd_enqueue returned rc %d, returning -EIO\n", rc);
- RETURN(-EIO);
+ RETURN(rc > 0 ? -EIO : rc);
}
lvb->lvb_size = lov_merge_size(lli->lli_smd, 0);
retval = generic_file_write(file, buf, count, ppos);
out:
- /* XXX errors? */
- lprocfs_counter_add(ll_i2sbi(inode)->ll_stats, LPROC_LL_WRITE_BYTES,
- retval);
ll_extent_unlock(fd, inode, lsm, LCK_PW, &lockh);
+ lprocfs_counter_add(ll_i2sbi(inode)->ll_stats, LPROC_LL_WRITE_BYTES,
+ retval > 0 ? retval : 0);
RETURN(retval);
}
}
static int ll_lov_setstripe_ea_info(struct inode *inode, struct file *file,
- int flags, struct lov_user_md *lum, int lum_size)
+ int flags, struct lov_user_md *lum,
+ int lum_size)
{
struct ll_inode_info *lli = ll_i2info(inode);
struct file *f;
struct inode *inode = dentry->d_inode;
struct ll_inode_info *lli;
struct lov_stripe_md *lsm;
+ int rc;
ENTRY;
if (!inode) {
struct ll_sb_info *sbi = ll_i2sbi(dentry->d_inode);
struct ll_fid fid;
unsigned long valid = 0;
- int rc, ealen = 0;
+ int ealen = 0;
if (S_ISREG(inode->i_mode)) {
ealen = obd_size_diskmd(sbi->ll_osc_exp, NULL);
* the file */
{
struct ost_lvb lvb;
- ldlm_error_t err;
- err = ll_glimpse_size(inode, &lvb);
+ rc = ll_glimpse_size(inode, &lvb);
inode->i_size = lvb.lvb_size;
}
- RETURN(0);
+ RETURN(rc);
}
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+++ /dev/null
-/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
- * vim:expandtab:shiftwidth=8:tabstop=8:
- *
- * Copyright (C) 2001 Cluster File Systems, Inc.
- *
- * This code is issued under the GNU General Public License.
- * See the file COPYING in this distribution
- */
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/sysctl.h>
-#include <linux/version.h>
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
-#include <linux/swapctl.h>
-#endif
-#include <linux/proc_fs.h>
-#include <linux/slab.h>
-#include <linux/stat.h>
-#include <linux/ctype.h>
-#include <asm/bitops.h>
-#include <asm/segment.h>
-#include <asm/uaccess.h>
-#include <linux/utsname.h>
-
-struct ctl_table_header *ll_table_header = NULL;
-
-int ll_debug_level = 0;
-int ll_print_entry = 1;
-
-
-#define LL_SYSCTL 1
-
-#define LL_DEBUG 1 /* control debugging */
-#define LL_ENTRY 2 /* control enter/leave pattern */
-#define LL_TIMEOUT 3 /* timeout on upcalls to become intrble */
-#define LL_HARD 4 /* mount type "hard" or "soft" */
-#define LL_VARS 5
-#define LL_INDEX 6
-#define LL_RESET 7
-
-#define LL_VARS_SLOT 2
-
-static ctl_table ll_table[] = {
- {LL_DEBUG, "debug", &ll_debug_level, sizeof(int), 0644, NULL, &proc_dointvec},
- {LL_ENTRY, "trace", &ll_print_entry, sizeof(int), 0644, NULL, &proc_dointvec},
- { 0 }
-};
-
-static ctl_table top_table[] = {
- {LL_SYSCTL, "lustre_light", NULL, 0, 0555, ll_table},
- {0}
-};
-
-void ll_sysctl_init (void)
-{
-
-#ifdef CONFIG_SYSCTL
- if ( !ll_table_header )
- ll_table_header = register_sysctl_table(top_table, 0);
-#endif
-}
-
-void ll_sysctl_clean (void)
-{
-#ifdef CONFIG_SYSCTL
- if ( ll_table_header )
- unregister_sysctl_table(ll_table_header);
- ll_table_header = NULL;
-#endif
-}
.deps
TAGS
.*.cmd
+fsfilt_extN.c
endif
endif
+fsfilt_extN.c: fsfilt_ext3.c
+ sed -e "s/EXT3/EXTN/g" -e "s/ext3/extN/g" $< > $@
+
include $(top_srcdir)/Rules
if LINUX25
* the inode (which we will be changing anyways as part of this
* transaction).
*/
-static void *fsfilt_ext3_start(struct inode *inode, int op, void *desc_private)
+static void *fsfilt_ext3_start(struct inode *inode, int op, void *desc_private,
+ int logs)
{
/* For updates to the last recieved file */
- int nblocks = EXT3_DATA_TRANS_BLOCKS;
+ int nblocks = EXT3_SINGLEDATA_TRANS_BLOCKS;
+ journal_t *journal;
void *handle;
if (current->journal_info) {
}
switch(op) {
- case FSFILT_OP_CREATE_LOG:
- nblocks += EXT3_INDEX_EXTRA_TRANS_BLOCKS+EXT3_DATA_TRANS_BLOCKS;
- op = FSFILT_OP_CREATE;
- break;
- case FSFILT_OP_UNLINK_LOG:
- nblocks += EXT3_INDEX_EXTRA_TRANS_BLOCKS+EXT3_DATA_TRANS_BLOCKS;
- op = FSFILT_OP_UNLINK;
- break;
- }
-
- switch(op) {
case FSFILT_OP_RMDIR:
case FSFILT_OP_UNLINK:
+ /* delete one file + create/update logs for each stripe */
nblocks += EXT3_DELETE_TRANS_BLOCKS;
+ nblocks += (EXT3_INDEX_EXTRA_TRANS_BLOCKS +
+ EXT3_SINGLEDATA_TRANS_BLOCKS) * logs;
break;
case FSFILT_OP_RENAME:
/* modify additional directory */
- nblocks += EXT3_DATA_TRANS_BLOCKS;
+ nblocks += EXT3_SINGLEDATA_TRANS_BLOCKS;
/* no break */
case FSFILT_OP_SYMLINK:
/* additional block + block bitmap + GDT for long symlink */
nblocks += 3;
/* no break */
case FSFILT_OP_CREATE:
+ /* create/update logs for each stripe */
+ nblocks += (EXT3_INDEX_EXTRA_TRANS_BLOCKS +
+ EXT3_SINGLEDATA_TRANS_BLOCKS) * logs;
+ /* no break */
case FSFILT_OP_MKDIR:
case FSFILT_OP_MKNOD:
/* modify one inode + block bitmap + GDT */
/* no break */
case FSFILT_OP_LINK:
/* modify parent directory */
- nblocks += EXT3_INDEX_EXTRA_TRANS_BLOCKS+EXT3_DATA_TRANS_BLOCKS;
+ nblocks += EXT3_INDEX_EXTRA_TRANS_BLOCKS +
+ EXT3_DATA_TRANS_BLOCKS;
break;
case FSFILT_OP_SETATTR:
/* Setattr on inode */
nblocks += 1;
break;
- case FSFILT_OP_CANCEL_UNLINK_LOG:
+ case FSFILT_OP_CANCEL_UNLINK:
+ /* blocks for log header bitmap update OR
+ * blocks for catalog header bitmap update + unlink of logs */
nblocks = (LLOG_CHUNK_SIZE >> inode->i_blkbits) +
- EXT3_DELETE_TRANS_BLOCKS;
+ EXT3_DELETE_TRANS_BLOCKS * logs;
break;
default: CERROR("unknown transaction start op %d\n", op);
LBUG();
}
LASSERT(current->journal_info == desc_private);
+ journal = EXT3_SB(inode->i_sb)->s_journal;
+ if (nblocks > journal->j_max_transaction_buffers) {
+ CERROR("too many credits %d for op %ux%u using %d instead\n",
+ nblocks, op, logs, journal->j_max_transaction_buffers);
+ nblocks = journal->j_max_transaction_buffers;
+ }
journal_start:
lock_kernel();
if (!IS_ERR(handle))
LASSERT(current->journal_info == handle);
+ else
+ CERROR("error starting handle for op %u (%u credits): rc %ld\n",
+ op, nblocks, PTR_ERR(handle));
return handle;
}
*/
static void *fsfilt_ext3_brw_start(int objcount, struct fsfilt_objinfo *fso,
int niocount, struct niobuf_local *nb,
- void *desc_private)
+ void *desc_private, int logs)
{
journal_t *journal;
handle_t *handle;
return 0;
}
+/* If fso is NULL, op is FSFILT operation, otherwise op is number of fso
+ objects. Logs is number of logfiles to update */
+static int fsfilt_ext3_get_op_len(int op, struct fsfilt_objinfo *fso, int logs)
+{
+ if ( !fso ) {
+ switch(op) {
+ case FSFILT_OP_CREATE:
+ /* directory leaf, index & indirect & EA*/
+ return 4 + 3 * logs;
+ case FSFILT_OP_UNLINK:
+ return 3 * logs;
+ }
+ } else {
+ int i;
+ int needed = 0;
+ struct super_block *sb = fso->fso_dentry->d_inode->i_sb;
+ int blockpp = 1 << (PAGE_CACHE_SHIFT - sb->s_blocksize_bits);
+ int addrpp = EXT3_ADDR_PER_BLOCK(sb) * blockpp;
+ for (i = 0; i < op; i++, fso++) {
+ int nblocks = fso->fso_bufcnt * blockpp;
+ int ndindirect = min(nblocks, addrpp + 1);
+ int nindir = nblocks + ndindirect + 1;
+
+ needed += nindir;
+ }
+ return needed + 3 * logs;
+ }
+
+ return 0;
+}
+
static struct fsfilt_operations fsfilt_ext3_ops = {
fs_type: "ext3",
fs_owner: THIS_MODULE,
fs_write_record: fsfilt_ext3_write_record,
fs_read_record: fsfilt_ext3_read_record,
fs_setup: fsfilt_ext3_setup,
+ fs_get_op_len: fsfilt_ext3_get_op_len,
};
static int __init fsfilt_ext3_init(void)
+++ /dev/null
-/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
- * vim:expandtab:shiftwidth=8:tabstop=8:
- *
- * lustre/lib/fsfilt_extN.c
- * Lustre filesystem abstraction routines
- *
- * Copyright (C) 2002, 2003 Cluster File Systems, Inc.
- * Author: Andreas Dilger <adilger@clusterfs.com>
- *
- * This file is part of Lustre, http://www.lustre.org.
- *
- * Lustre is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * Lustre is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Lustre; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#define DEBUG_SUBSYSTEM S_FILTER
-
-#include <linux/fs.h>
-#include <linux/jbd.h>
-#include <linux/slab.h>
-#include <linux/pagemap.h>
-#include <linux/quotaops.h>
-#include <linux/extN_fs.h>
-#include <linux/extN_jbd.h>
-#include <linux/version.h>
-/* XXX ugh */
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
- #include <linux/extN_xattr.h>
-#else
- #include <linux/../../fs/extN/xattr.h>
-#endif
-#include <linux/kp30.h>
-#include <linux/lustre_fsfilt.h>
-#include <linux/obd.h>
-#include <linux/obd_class.h>
-#include <linux/module.h>
-
-static kmem_cache_t *fcb_cache;
-static atomic_t fcb_cache_count = ATOMIC_INIT(0);
-
-struct fsfilt_cb_data {
- struct journal_callback cb_jcb; /* jbd private data - MUST BE FIRST */
- fsfilt_cb_t cb_func; /* MDS/OBD completion function */
- struct obd_device *cb_obd; /* MDS/OBD completion device */
- __u64 cb_last_rcvd; /* MDS/OST last committed operation */
- void *cb_data; /* MDS/OST completion function data */
-};
-
-#ifndef EXTN_XATTR_INDEX_TRUSTED /* temporary until we hit l28 kernel */
-#define EXTN_XATTR_INDEX_TRUSTED 4
-#endif
-#define XATTR_LUSTRE_MDS_LOV_EA "lov"
-
-#define EXTN_XATTR_INDEX_LUSTRE 5 /* old */
-#define XATTR_LUSTRE_MDS_OBJID "system.lustre_mds_objid" /* old */
-
-/*
- * We don't currently need any additional blocks for rmdir and
- * unlink transactions because we are storing the OST oa_id inside
- * the inode (which we will be changing anyways as part of this
- * transaction).
- */
-static void *fsfilt_extN_start(struct inode *inode, int op, void *desc_private)
-{
- /* For updates to the last recieved file */
- int nblocks = EXTN_DATA_TRANS_BLOCKS;
- void *handle;
-
- if (current->journal_info) {
- CDEBUG(D_INODE, "increasing refcount on %p\n", current->journal_info);
- goto journal_start;
- }
-
- switch(op) {
- case FSFILT_OP_CREATE_LOG:
- nblocks += EXTN_INDEX_EXTRA_TRANS_BLOCKS+EXTN_DATA_TRANS_BLOCKS;
- op = FSFILT_OP_CREATE;
- break;
- case FSFILT_OP_UNLINK_LOG:
- nblocks += EXTN_INDEX_EXTRA_TRANS_BLOCKS+EXTN_DATA_TRANS_BLOCKS;
- op = FSFILT_OP_UNLINK;
- break;
- }
-
- switch(op) {
- case FSFILT_OP_RMDIR:
- case FSFILT_OP_UNLINK:
- nblocks += EXTN_DELETE_TRANS_BLOCKS;
- break;
- case FSFILT_OP_RENAME:
- /* modify additional directory */
- nblocks += EXTN_DATA_TRANS_BLOCKS;
- /* no break */
- case FSFILT_OP_SYMLINK:
- /* additional block + block bitmap + GDT for long symlink */
- nblocks += 3;
- /* no break */
- case FSFILT_OP_CREATE:
- case FSFILT_OP_MKDIR:
- case FSFILT_OP_MKNOD:
- /* modify one inode + block bitmap + GDT */
- nblocks += 3;
- /* no break */
- case FSFILT_OP_LINK:
- /* modify parent directory */
- nblocks += EXTN_INDEX_EXTRA_TRANS_BLOCKS+EXTN_DATA_TRANS_BLOCKS;
- break;
- case FSFILT_OP_SETATTR:
- /* Setattr on inode */
- nblocks += 1;
- break;
- default: CERROR("unknown transaction start op %d\n", op);
- LBUG();
- }
-
- LASSERT(current->journal_info == desc_private);
-
- journal_start:
- lock_kernel();
- handle = journal_start(EXTN_JOURNAL(inode), nblocks);
- unlock_kernel();
-
- if (!IS_ERR(handle))
- LASSERT(current->journal_info == handle);
- return handle;
-}
-
-/*
- * Calculate the number of buffer credits needed to write multiple pages in
- * a single extN transaction. No, this shouldn't be here, but as yet extN
- * doesn't have a nice API for calculating this sort of thing in advance.
- *
- * See comment above extN_writepage_trans_blocks for details. We assume
- * no data journaling is being done, but it does allow for all of the pages
- * being non-contiguous. If we are guaranteed contiguous pages we could
- * reduce the number of (d)indirect blocks a lot.
- *
- * With N blocks per page and P pages, for each inode we have at most:
- * N*P indirect
- * min(N*P, blocksize/4 + 1) dindirect blocks
- * niocount tindirect
- *
- * For the entire filesystem, we have at most:
- * min(sum(nindir + P), ngroups) bitmap blocks (from the above)
- * min(sum(nindir + P), gdblocks) group descriptor blocks (from the above)
- * objcount inode blocks
- * 1 superblock
- * 2 * EXTN_SINGLEDATA_TRANS_BLOCKS for the quota files
- *
- * 1 EXTN_DATA_TRANS_BLOCKS for the last_rcvd update.
- */
-static int fsfilt_extN_credits_needed(int objcount, struct fsfilt_objinfo *fso)
-{
- struct super_block *sb = fso->fso_dentry->d_inode->i_sb;
- int blockpp = 1 << (PAGE_CACHE_SHIFT - sb->s_blocksize_bits);
- int addrpp = EXTN_ADDR_PER_BLOCK(sb) * blockpp;
- int nbitmaps = 0;
- int ngdblocks = 0;
- int needed = objcount + 1;
- int i;
-
- for (i = 0; i < objcount; i++, fso++) {
- int nblocks = fso->fso_bufcnt * blockpp;
- int ndindirect = min(nblocks, addrpp + 1);
- int nindir = nblocks + ndindirect + 1;
-
- nbitmaps += nindir + nblocks;
- ngdblocks += nindir + nblocks;
-
- needed += nindir;
- }
-
- /* Assumes extN and extN have same sb_info layout at the start. */
- if (nbitmaps > EXTN_SB(sb)->s_groups_count)
- nbitmaps = EXTN_SB(sb)->s_groups_count;
- if (ngdblocks > EXTN_SB(sb)->s_gdb_count)
- ngdblocks = EXTN_SB(sb)->s_gdb_count;
-
- needed += nbitmaps + ngdblocks;
-
- /* last_rcvd update */
- needed += EXTN_DATA_TRANS_BLOCKS;
-
-#ifdef CONFIG_QUOTA
- /* We assume that there will be 1 bit set in s_dquot.flags for each
- * quota file that is active. This is at least true for now.
- */
- needed += hweight32(sb_any_quota_enabled(sb)) *
- EXTN_SINGLEDATA_TRANS_BLOCKS;
-#endif
-
- return needed;
-}
-
-/* We have to start a huge journal transaction here to hold all of the
- * metadata for the pages being written here. This is necessitated by
- * the fact that we do lots of prepare_write operations before we do
- * any of the matching commit_write operations, so even if we split
- * up to use "smaller" transactions none of them could complete until
- * all of them were opened. By having a single journal transaction,
- * we eliminate duplicate reservations for common blocks like the
- * superblock and group descriptors or bitmaps.
- *
- * We will start the transaction here, but each prepare_write will
- * add a refcount to the transaction, and each commit_write will
- * remove a refcount. The transaction will be closed when all of
- * the pages have been written.
- */
-static void *fsfilt_extN_brw_start(int objcount, struct fsfilt_objinfo *fso,
- int niocount, void *desc_private)
-{
- journal_t *journal;
- handle_t *handle;
- int needed;
- ENTRY;
-
- LASSERT(current->journal_info == desc_private);
- journal = EXTN_SB(fso->fso_dentry->d_inode->i_sb)->s_journal;
- needed = fsfilt_extN_credits_needed(objcount, fso);
-
- /* The number of blocks we could _possibly_ dirty can very large.
- * We reduce our request if it is absurd (and we couldn't get that
- * many credits for a single handle anyways).
- *
- * At some point we have to limit the size of I/Os sent at one time,
- * increase the size of the journal, or we have to calculate the
- * actual journal requirements more carefully by checking all of
- * the blocks instead of being maximally pessimistic. It remains to
- * be seen if this is a real problem or not.
- */
- if (needed > journal->j_max_transaction_buffers) {
- CERROR("want too many journal credits (%d) using %d instead\n",
- needed, journal->j_max_transaction_buffers);
- needed = journal->j_max_transaction_buffers;
- }
-
- lock_kernel();
- handle = journal_start(journal, needed);
- unlock_kernel();
- if (IS_ERR(handle)) {
- CERROR("can't get handle for %d credits: rc = %ld\n", needed,
- PTR_ERR(handle));
- } else {
- LASSERT(handle->h_buffer_credits >= needed);
- LASSERT(current->journal_info == handle);
- }
-
- RETURN(handle);
-}
-
-static int fsfilt_extN_commit(struct inode *inode, void *h, int force_sync)
-{
- int rc;
- handle_t *handle = h;
-
- LASSERT(current->journal_info == handle);
- if (force_sync)
- handle->h_sync = 1; /* recovery likes this */
-
- lock_kernel();
- rc = journal_stop(handle);
- unlock_kernel();
-
- // LASSERT(current->journal_info == NULL);
- return rc;
-}
-
-static int fsfilt_extN_commit_async(struct inode *inode, void *h,
- void **wait_handle)
-{
- transaction_t *transaction;
- unsigned long tid, rtid;
- handle_t *handle = h;
- journal_t *journal;
- int rc;
-
- LASSERT(current->journal_info == handle);
-
- lock_kernel();
- transaction = handle->h_transaction;
- journal = transaction->t_journal;
- tid = transaction->t_tid;
- /* we don't want to be blocked */
- handle->h_sync = 0;
- rc = journal_stop(handle);
- if (rc) {
- CERROR("error while stopping transaction: %d\n", rc);
- unlock_kernel();
- return rc;
- }
-
- rtid = log_start_commit(journal, transaction);
- if (rtid != tid)
- CERROR("strange race: %lu != %lu\n",
- (unsigned long) tid, (unsigned long) rtid);
- unlock_kernel();
-
- *wait_handle = (void *) tid;
- CDEBUG(D_INODE, "commit async: %lu\n", (unsigned long) tid);
- return 0;
-}
-
-static int fsfilt_extN_commit_wait(struct inode *inode, void *h)
-{
- tid_t tid = (tid_t)(long)h;
-
- CDEBUG(D_INODE, "commit wait: %lu\n", (unsigned long) tid);
- if (is_journal_aborted(EXTN_JOURNAL(inode)))
- return -EIO;
-
- log_wait_commit(EXTN_JOURNAL(inode), tid);
-
- return 0;
-}
-
-static int fsfilt_extN_setattr(struct dentry *dentry, void *handle,
- struct iattr *iattr, int do_trunc)
-{
- struct inode *inode = dentry->d_inode;
- int rc;
-
- lock_kernel();
-
- /* A _really_ horrible hack to avoid removing the data stored
- * in the block pointers; this is really the "small" stripe MD data.
- * We can avoid further hackery by virtue of the MDS file size being
- * zero all the time (which doesn't invoke block truncate at unlink
- * time), so we assert we never change the MDS file size from zero. */
- if (iattr->ia_valid & ATTR_SIZE && !do_trunc) {
- /* ATTR_SIZE would invoke truncate: clear it */
- iattr->ia_valid &= ~ATTR_SIZE;
- EXTN_I(inode)->i_disksize = inode->i_size = iattr->ia_size;
-
- /* make sure _something_ gets set - so new inode
- * goes to disk (probably won't work over XFS */
- if (!(iattr->ia_valid & (ATTR_MODE | ATTR_MTIME | ATTR_CTIME))){
- iattr->ia_valid |= ATTR_MODE;
- iattr->ia_mode = inode->i_mode;
- }
- }
-
- /* Don't allow setattr to change file type */
- iattr->ia_mode = (inode->i_mode & S_IFMT)|(iattr->ia_mode & ~S_IFMT);
-
- /* We set these flags on the client, but have already checked perms
- * so don't confuse inode_change_ok. */
- iattr->ia_valid &= ~(ATTR_MTIME_SET | ATTR_ATIME_SET);
-
- if (inode->i_op->setattr) {
- rc = inode->i_op->setattr(dentry, iattr);
- } else {
- rc = inode_change_ok(inode, iattr);
- if (!rc)
- rc = inode_setattr(inode, iattr);
- }
-
- unlock_kernel();
-
- return rc;
-}
-
-static int fsfilt_extN_iocontrol(struct inode * inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- int rc = 0;
- ENTRY;
-
- if (inode->i_fop->ioctl)
- rc = inode->i_fop->ioctl(inode, file, cmd, arg);
- else
- RETURN(-ENOTTY);
-
- RETURN(rc);
-}
-
-#undef INLINE_EA
-#undef OLD_EA
-static int fsfilt_extN_set_md(struct inode *inode, void *handle,
- void *lmm, int lmm_size)
-{
- int rc, old_ea = 0;
-
-#ifdef INLINE_EA /* can go away before 1.0 - just for testing bug 2097 now */
- /* Nasty hack city - store stripe MD data in the block pointers if
- * it will fit, because putting it in an EA currently kills the MDS
- * performance. We'll fix this with "fast EAs" in the future.
- */
- if (inode->i_blocks == 0 && lmm_size <= sizeof(EXTN_I(inode)->i_data) -
- sizeof(EXTN_I(inode)->i_data[0])) {
- unsigned old_size = EXTN_I(inode)->i_data[0];
- if (old_size != 0) {
- LASSERT(old_size < sizeof(EXTN_I(inode)->i_data));
- CERROR("setting EA on %lu/%u again... interesting\n",
- inode->i_ino, inode->i_generation);
- }
-
- EXTN_I(inode)->i_data[0] = cpu_to_le32(lmm_size);
- memcpy(&EXTN_I(inode)->i_data[1], lmm, lmm_size);
- mark_inode_dirty(inode);
- return 0;
- }
-#endif
-#ifdef OLD_EA
- /* keep this when we get rid of OLD_EA (too noisy during conversion) */
- if (EXTN_I(inode)->i_file_acl /* || large inode EA flag */) {
- CWARN("setting EA on %lu/%u again... interesting\n",
- inode->i_ino, inode->i_generation);
- old_ea = 1;
- }
-
- lock_kernel();
- /* this can go away before 1.0. For bug 2097 testing only. */
- rc = extN_xattr_set_handle(handle, inode, EXTN_XATTR_INDEX_LUSTRE,
- XATTR_LUSTRE_MDS_OBJID, lmm, lmm_size, 0);
-#else
- lock_kernel();
- rc = extN_xattr_set_handle(handle, inode, EXTN_XATTR_INDEX_TRUSTED,
- XATTR_LUSTRE_MDS_LOV_EA, lmm, lmm_size, 0);
-
- /* This tries to delete the old-format LOV EA, but only as long as we
- * have successfully saved the new-format LOV EA (we can always try
- * the conversion again the next time the file is accessed). It is
- * possible (although unlikely) that the new-format LOV EA couldn't be
- * saved because it ran out of space but we would need a file striped
- * over least 123 OSTs before the two EAs filled a 4kB block.
- *
- * This can be removed when all filesystems have converted to the
- * new EA format, but otherwise adds little if any overhead. If we
- * wanted backward compatibility for existing files, we could keep
- * the old EA around for a while but we'd have to clean it up later. */
- if (rc >= 0 && old_ea) {
- int err = extN_xattr_set_handle(handle, inode,
- EXTN_XATTR_INDEX_LUSTRE,
- XATTR_LUSTRE_MDS_OBJID,
- NULL, 0, 0);
- if (err)
- CERROR("error deleting old LOV EA on %lu/%u: rc %d\n",
- inode->i_ino, inode->i_generation, err);
- }
-#endif
- unlock_kernel();
-
- if (rc)
- CERROR("error adding MD data to inode %lu: rc = %d\n",
- inode->i_ino, rc);
- return rc;
-}
-
-/* Must be called with i_sem held */
-static int fsfilt_extN_get_md(struct inode *inode, void *lmm, int lmm_size)
-{
- int rc;
-
- LASSERT(down_trylock(&inode->i_sem) != 0);
- lock_kernel();
- /* Keep support for reading "inline EAs" until we convert
- * users over to new format entirely. See bug 841/2097. */
- if (inode->i_blocks == 0 && EXTN_I(inode)->i_data[0]) {
- unsigned size = le32_to_cpu(EXTN_I(inode)->i_data[0]);
- void *handle;
-
- LASSERT(size < sizeof(EXTN_I(inode)->i_data));
- if (lmm) {
- if (size > lmm_size) {
- CERROR("inline EA on %lu/%u bad size %u > %u\n",
- inode->i_ino, inode->i_generation,
- size, lmm_size);
- return -ERANGE;
- }
- memcpy(lmm, &EXTN_I(inode)->i_data[1], size);
- }
-
-#ifndef INLINE_EA
- /* migrate LOV EA data to external block - keep same format */
- CWARN("DEBUG: migrate inline EA for inode %lu/%u to block\n",
- inode->i_ino, inode->i_generation);
-
- handle = journal_start(EXTN_JOURNAL(inode),
- EXTN_XATTR_TRANS_BLOCKS);
- if (!IS_ERR(handle)) {
- int err;
- rc = fsfilt_extN_set_md(inode, handle,
- &EXTN_I(inode)->i_data[1],size);
- if (rc == 0) {
- memset(EXTN_I(inode)->i_data, 0,
- sizeof(EXTN_I(inode)->i_data));
- mark_inode_dirty(inode);
- }
- err = journal_stop(handle);
- if (err && rc == 0)
- rc = err;
- } else {
- rc = PTR_ERR(handle);
- }
-#endif
- unlock_kernel();
- return size;
- }
-
- rc = extN_xattr_get(inode, EXTN_XATTR_INDEX_TRUSTED,
- XATTR_LUSTRE_MDS_LOV_EA, lmm, lmm_size);
- /* try old EA type if new one failed - MDS will convert it for us */
- if (rc == -ENODATA) {
- CDEBUG(D_INFO,"failed new LOV EA %d/%s from inode %lu: rc %d\n",
- EXTN_XATTR_INDEX_TRUSTED, XATTR_LUSTRE_MDS_LOV_EA,
- inode->i_ino, rc);
-
- rc = extN_xattr_get(inode, EXTN_XATTR_INDEX_LUSTRE,
- XATTR_LUSTRE_MDS_OBJID, lmm, lmm_size);
- }
- unlock_kernel();
-
- /* This gives us the MD size */
- if (lmm == NULL)
- return (rc == -ENODATA) ? 0 : rc;
-
- if (rc < 0) {
- CDEBUG(D_INFO, "error getting EA %d/%s from inode %lu: rc %d\n",
- EXTN_XATTR_INDEX_LUSTRE, XATTR_LUSTRE_MDS_OBJID,
- inode->i_ino, rc);
- memset(lmm, 0, lmm_size);
- return (rc == -ENODATA) ? 0 : rc;
- }
-
- return rc;
-}
-
-static ssize_t fsfilt_extN_readpage(struct file *file, char *buf, size_t count,
- loff_t *off)
-{
- struct inode *inode = file->f_dentry->d_inode;
- int rc = 0;
-
- if (S_ISREG(inode->i_mode))
- rc = file->f_op->read(file, buf, count, off);
- else {
- const int blkbits = inode->i_sb->s_blocksize_bits;
- const int blksize = inode->i_sb->s_blocksize;
-
- CDEBUG(D_EXT2, "reading "LPSZ" at dir %lu+%llu\n",
- count, inode->i_ino, *off);
- while (count > 0) {
- struct buffer_head *bh;
-
- bh = NULL;
- if (*off < inode->i_size) {
- int err = 0;
-
- bh = extN_bread(NULL, inode, *off >> blkbits,
- 0, &err);
-
- CDEBUG(D_EXT2, "read %u@%llu\n", blksize, *off);
-
- if (bh) {
- memcpy(buf, bh->b_data, blksize);
- brelse(bh);
- } else if (err) {
- /* XXX in theory we should just fake
- * this buffer and continue like extN,
- * especially if this is a partial read
- */
- CERROR("error read dir %lu+%llu: %d\n",
- inode->i_ino, *off, err);
- RETURN(err);
- }
- }
- if (!bh) {
- struct extN_dir_entry_2 *fake = (void *)buf;
-
- CDEBUG(D_EXT2, "fake %u@%llu\n", blksize, *off);
- memset(fake, 0, sizeof(*fake));
- fake->rec_len = cpu_to_le32(blksize);
- }
- count -= blksize;
- buf += blksize;
- *off += blksize;
- rc += blksize;
- }
- }
-
- return rc;
-}
-
-static void fsfilt_extN_cb_func(struct journal_callback *jcb, int error)
-{
- struct fsfilt_cb_data *fcb = (struct fsfilt_cb_data *)jcb;
-
- fcb->cb_func(fcb->cb_obd, fcb->cb_last_rcvd, fcb->cb_data, error);
-
- OBD_SLAB_FREE(fcb, fcb_cache, sizeof *fcb);
- atomic_dec(&fcb_cache_count);
-}
-
-static int fsfilt_extN_add_journal_cb(struct obd_device *obd, __u64 last_rcvd,
- void *handle, fsfilt_cb_t cb_func,
- void *cb_data)
-{
- struct fsfilt_cb_data *fcb;
-
- OBD_SLAB_ALLOC(fcb, fcb_cache, GFP_NOFS, sizeof *fcb);
- if (fcb == NULL)
- RETURN(-ENOMEM);
-
- atomic_inc(&fcb_cache_count);
- fcb->cb_func = cb_func;
- fcb->cb_obd = obd;
- fcb->cb_last_rcvd = last_rcvd;
- fcb->cb_data = cb_data;
-
- CDEBUG(D_EXT2, "set callback for last_rcvd: "LPD64"\n", last_rcvd);
- lock_kernel();
- journal_callback_set(handle, fsfilt_extN_cb_func,
- (struct journal_callback *)fcb);
- unlock_kernel();
-
- return 0;
-}
-
-/*
- * We need to hack the return value for the free inode counts because
- * the current EA code requires one filesystem block per inode with EAs,
- * so it is possible to run out of blocks before we run out of inodes.
- *
- * This can be removed when the extN EA code is fixed.
- */
-static int fsfilt_extN_statfs(struct super_block *sb, struct obd_statfs *osfs)
-{
- struct kstatfs sfs;
- int rc;
-
- memset(&sfs, 0, sizeof(sfs));
-
- rc = sb->s_op->statfs(sb, &sfs);
-
- if (!rc && sfs.f_bfree < sfs.f_ffree) {
- sfs.f_files = (sfs.f_files - sfs.f_ffree) + sfs.f_bfree;
- sfs.f_ffree = sfs.f_bfree;
- }
-
- statfs_pack(osfs, &sfs);
- return rc;
-}
-
-static int fsfilt_extN_sync(struct super_block *sb)
-{
- return extN_force_commit(sb);
-}
-
-extern int extN_map_inode_page(struct inode *inode, struct page *page,
- unsigned long *blocks, int *created, int create);
-int fsfilt_extN_map_inode_page(struct inode *inode, struct page *page,
- unsigned long *blocks, int *created, int create)
-{
- return extN_map_inode_page(inode, page, blocks, created, create);
-}
-
-extern int extN_prep_san_write(struct inode *inode, long *blocks,
- int nblocks, loff_t newsize);
-static int fsfilt_extN_prep_san_write(struct inode *inode, long *blocks,
- int nblocks, loff_t newsize)
-{
- return extN_prep_san_write(inode, blocks, nblocks, newsize);
-}
-
-static int fsfilt_extN_read_record(struct file * file, void *buf,
- int size, loff_t *offs)
-{
- struct buffer_head *bh;
- unsigned long block, boffs;
- struct inode *inode = file->f_dentry->d_inode;
- int err;
-
- if (inode->i_size < *offs + size) {
- size = inode->i_size - *offs;
- if (size < 0) {
- CERROR("size %llu is too short for read %u@%llu\n",
- inode->i_size, size, *offs);
- return -EIO;
- } else if (size == 0)
- return 0;
- }
-
- block = *offs >> inode->i_blkbits;
- bh = extN_bread(NULL, inode, block, 0, &err);
- if (!bh) {
- CERROR("can't read block: %d\n", err);
- return err;
- }
-
- boffs = (unsigned)*offs % bh->b_size;
- if (boffs + size > bh->b_size) {
- CERROR("request crosses block's border. offset %llu, size %u\n",
- *offs, size);
- brelse(bh);
- return -EIO;
- }
-
- memcpy(buf, bh->b_data + boffs, size);
- brelse(bh);
- *offs += size;
- return 0;
-}
-
-static int fsfilt_extN_write_record(struct file *file, void *buf, int size,
- loff_t *offs, int force_sync)
-{
- struct buffer_head *bh;
- unsigned long block, boffs;
- struct inode *inode = file->f_dentry->d_inode;
- loff_t old_size = inode->i_size;
- journal_t *journal;
- handle_t *handle;
- int err;
-
- journal = EXTN_SB(inode->i_sb)->s_journal;
- handle = journal_start(journal, EXTN_DATA_TRANS_BLOCKS + 2);
- if (IS_ERR(handle)) {
- CERROR("can't start transaction\n");
- return PTR_ERR(handle);
- }
-
- block = *offs >> inode->i_blkbits;
- if (*offs + size > inode->i_size) {
- down(&inode->i_sem);
- if (*offs + size > inode->i_size)
- inode->i_size = *offs + size;
- if (inode->i_size > EXTN_I(inode)->i_disksize)
- EXTN_I(inode)->i_disksize = inode->i_size;
- up(&inode->i_sem);
- }
-
- bh = extN_bread(handle, inode, block, 1, &err);
- if (!bh) {
- CERROR("can't read/create block: %d\n", err);
- goto out;
- }
-
- /* This is a hack only needed because extN_get_block_handle() updates
- * i_disksize after marking the inode dirty in extN_splice_branch().
- * We will fix that when we get a chance, as extN_mark_inode_dirty()
- * is not without cost, nor is it even exported.
- */
- if (inode->i_size > old_size)
- mark_inode_dirty(inode);
-
- boffs = (unsigned)*offs % bh->b_size;
- if (boffs + size > bh->b_size) {
- CERROR("request crosses block's border. offset %llu, size %u\n",
- *offs, size);
- err = -EIO;
- goto out;
- }
-
- err = extN_journal_get_write_access(handle, bh);
- if (err) {
- CERROR("journal_get_write_access() returned error %d\n", err);
- goto out;
- }
- memcpy(bh->b_data + boffs, buf, size);
- err = extN_journal_dirty_metadata(handle, bh);
- if (err) {
- CERROR("journal_dirty_metadata() returned error %d\n", err);
- goto out;
- }
-
- if (force_sync)
- handle->h_sync = 1; /* recovery likes this */
-out:
- if (bh)
- brelse(bh);
- journal_stop(handle);
- if (err == 0)
- *offs += size;
- return err;
-}
-
-static int fsfilt_extN_setup(struct super_block *sb)
-{
-#if 0
- EXTN_SB(sb)->dx_lock = fsfilt_extN_dx_lock;
- EXTN_SB(sb)->dx_unlock = fsfilt_extN_dx_unlock;
-#endif
-#ifdef S_PDIROPS
- CWARN("Enabling PDIROPS\n");
- set_opt(EXTN_SB(sb)->s_mount_opt, PDIROPS);
- sb->s_flags |= S_PDIROPS;
-#endif
- return 0;
-}
-
-static struct fsfilt_operations fsfilt_extN_ops = {
- fs_type: "extN",
- fs_owner: THIS_MODULE,
- fs_start: fsfilt_extN_start,
- fs_brw_start: fsfilt_extN_brw_start,
- fs_commit: fsfilt_extN_commit,
- fs_commit_async: fsfilt_extN_commit_async,
- fs_commit_wait: fsfilt_extN_commit_wait,
- fs_setattr: fsfilt_extN_setattr,
- fs_iocontrol: fsfilt_extN_iocontrol,
- fs_set_md: fsfilt_extN_set_md,
- fs_get_md: fsfilt_extN_get_md,
- fs_readpage: fsfilt_extN_readpage,
- fs_add_journal_cb: fsfilt_extN_add_journal_cb,
- fs_statfs: fsfilt_extN_statfs,
- fs_sync: fsfilt_extN_sync,
- fs_map_inode_page: fsfilt_extN_map_inode_page,
- fs_prep_san_write: fsfilt_extN_prep_san_write,
- fs_write_record: fsfilt_extN_write_record,
- fs_read_record: fsfilt_extN_read_record,
- fs_setup: fsfilt_extN_setup,
-};
-
-static int __init fsfilt_extN_init(void)
-{
- int rc;
-
- //rc = extN_xattr_register();
- fcb_cache = kmem_cache_create("fsfilt_extN_fcb",
- sizeof(struct fsfilt_cb_data), 0,
- 0, NULL, NULL);
- if (!fcb_cache) {
- CERROR("error allocating fsfilt journal callback cache\n");
- GOTO(out, rc = -ENOMEM);
- }
-
- rc = fsfilt_register_ops(&fsfilt_extN_ops);
-
- if (rc)
- kmem_cache_destroy(fcb_cache);
-out:
- return rc;
-}
-
-static void __exit fsfilt_extN_exit(void)
-{
- int rc;
-
- fsfilt_unregister_ops(&fsfilt_extN_ops);
- rc = kmem_cache_destroy(fcb_cache);
-
- if (rc || atomic_read(&fcb_cache_count)) {
- CERROR("can't free fsfilt callback cache: count %d, rc = %d\n",
- atomic_read(&fcb_cache_count), rc);
- }
-
- //rc = extN_xattr_unregister();
-}
-
-module_init(fsfilt_extN_init);
-module_exit(fsfilt_extN_exit);
-
-MODULE_AUTHOR("Cluster File Systems, Inc. <info@clusterfs.com>");
-MODULE_DESCRIPTION("Lustre extN Filesystem Helper v0.1");
-MODULE_LICENSE("GPL");
#define DEBUG_SUBSYSTEM S_FILTER
#include <linux/fs.h>
-#include <linux/jbd.h>
#include <linux/slab.h>
#include <linux/pagemap.h>
#include <linux/quotaops.h>
#include <linux/module.h>
#include <linux/init.h>
+/* XXX We cannot include linux/reiserfs_fs.h here, because of symbols clash,
+ but we need MAX_HEIGHT definition for proper reserve calculations
+#include <linux/reiserfs_fs.h>
+*/
+#define MAX_HEIGHT 5 /* maximal height of a tree. don't change this without
+ changing JOURNAL_PER_BALANCE_CNT */
+
static void *fsfilt_reiserfs_start(struct inode *inode, int op,
- void *desc_private)
+ void *desc_private, int logs)
{
return (void *)0xf00f00be;
}
static void *fsfilt_reiserfs_brw_start(int objcount, struct fsfilt_objinfo *fso,
int niocount, struct niobuf_local *nb,
- void *desc_private)
+ void *desc_private, int logs)
{
return (void *)0xf00f00be;
}
return fsync_dev(sb->s_dev);
}
+/* If fso is NULL, op is FSFILT operation, otherwise op is number of fso
+ objects. Logs is number of logfiles to update */
+static int fsfilt_reiserfs_get_op_len(int op, struct fsfilt_objinfo *fso,
+ int logs)
+{
+ if ( !fso ) {
+ switch(op) {
+ case FSFILT_OP_CREATE:
+ /* directory leaf, index & indirect & EA*/
+ return MAX_HEIGHT + logs;
+ case FSFILT_OP_UNLINK:
+ return MAX_HEIGHT + logs;
+ }
+
+ } else {
+ int i;
+ int needed = MAX_HEIGHT;
+ struct super_block *sb = fso->fso_dentry->d_inode->i_sb;
+ int blockpp = 1 << (PAGE_CACHE_SHIFT - sb->s_blocksize_bits);
+ for (i = 0; i < op; i++, fso++) {
+ int nblocks = fso->fso_bufcnt * blockpp;
+
+ needed += nblocks;
+ }
+ return needed + logs;
+ }
+
+ return 0;
+}
static struct fsfilt_operations fsfilt_reiserfs_ops = {
fs_type: "reiserfs",
fs_owner: THIS_MODULE,
fs_add_journal_cb: fsfilt_reiserfs_add_journal_cb,
fs_statfs: fsfilt_reiserfs_statfs,
fs_sync: fsfilt_reiserfs_sync,
+ fs_get_op_len: fsfilt_reiserfs_get_op_len,
};
static int __init fsfilt_reiserfs_init(void)
med->med_idx, med->med_off, med->med_mcd->mcd_uuid);
LASSERT(bitmap);
+
/* Clear the bit _after_ zeroing out the client so we don't
race with mds_client_add and zero out new clients.*/
if (!test_bit(med->med_idx, bitmap)) {
dentry = lookup_one_len("__iopen__", current->fs->pwd,
strlen("__iopen__"));
- if (IS_ERR(dentry) || !dentry->d_inode) {
- rc = (IS_ERR(dentry)) ? PTR_ERR(dentry): -ENOENT;
- CERROR("cannot open iopen FH directory: rc = %d\n", rc);
+ if (IS_ERR(dentry)) {
+ rc = PTR_ERR(dentry);
+ CERROR("cannot lookup __iopen__ directory: rc = %d\n", rc);
GOTO(err_pop, rc);
}
+ if (!dentry->d_inode) {
+ rc = -ENOENT;
+ CERROR("__iopen__ directory has no inode? rc = %d\n", rc);
+ GOTO(err_fid, rc);
+ }
mds->mds_fid_de = dentry;
dentry = simple_mkdir(current->fs->pwd, "PENDING", 0777, 1);
handle = fsfilt_start(exp->exp_obd, mds->mds_objects_dir->d_inode,
FSFILT_OP_RENAME, NULL);
- if (IS_ERR(handle))
+ if (IS_ERR(handle))
GOTO(out_dput, rc = PTR_ERR(handle));
-
+
lock_kernel();
rc = vfs_rename(mds->mds_objects_dir->d_inode, filp->f_dentry,
mds->mds_objects_dir->d_inode, new_child);
GOTO(out_dput, rc = IS_ERR(de) ? PTR_ERR(de) : -ENOENT);
}
- handle = fsfilt_start(obd, mds->mds_objects_dir->d_inode,
- FSFILT_OP_UNLINK_LOG, oti);
+ /* Stripe count is 1 here since this is some MDS specific stuff
+ that is unlinked, not spanned across multiple OSTs */
+ handle = fsfilt_start_log(obd, mds->mds_objects_dir->d_inode,
+ FSFILT_OP_UNLINK, oti, 1);
if (IS_ERR(handle)) {
GOTO(out_dput, rc = PTR_ERR(handle));
}
* opened this file and is only replaying the RPC, so we open the
* inode by fid (at some large expense in security). */
if (lustre_msg_get_flags(req->rq_reqmsg) & MSG_REPLAY) {
- DEBUG_REQ(D_HA, req, "open replay, disp: "LPX64"\n",
+ DEBUG_REQ(D_HA, req, "open replay, disp: "LPX64"\n",
rep->lock_policy_res1);
LASSERT(rec->ur_fid2->id);
-
+
rc = mds_open_by_fid(req, rec->ur_fid2, body, rec->ur_flags,
rec, rep);
- if (rc != -ENOENT)
+ if (rc != -ENOENT)
RETURN(rc);
/* We didn't find the correct inode on disk either, so we
* need to re-create it via a regular replay. */
void *handle = NULL;
struct mds_body *request_body = NULL, *reply_body = NULL;
struct dentry_params dp;
+ struct lov_mds_md *lmm;
ENTRY;
if (req != NULL) {
LASSERT(pending_child->d_inode != NULL);
cleanup_phase = 2; /* dput(pending_child) when finished */
- handle = fsfilt_start(obd, pending_dir, FSFILT_OP_UNLINK_LOG,
- NULL);
+ lmm = lustre_msg_buf(req->rq_repmsg, 1, 0);
+ handle = fsfilt_start_log(obd, pending_dir,
+ FSFILT_OP_UNLINK, NULL,
+ le32_to_cpu(lmm->lmm_stripe_count));
if (IS_ERR(handle)) {
rc = PTR_ERR(handle);
handle = NULL;
if (req != NULL &&
(reply_body->valid & OBD_MD_FLEASIZE) &&
mds_log_op_unlink(obd, pending_child->d_inode,
- lustre_msg_buf(req->rq_repmsg, 1, 0),
- req->rq_repmsg->buflens[1],
- lustre_msg_buf(req->rq_repmsg, 2, 0),
- req->rq_repmsg->buflens[2]) > 0) {
+ lustre_msg_buf(req->rq_repmsg, 1, 0),
+ req->rq_repmsg->buflens[1],
+ lustre_msg_buf(req->rq_repmsg, 2, 0),
+ req->rq_repmsg->buflens[2]) > 0) {
reply_body->valid |= OBD_MD_FLCOOKIE;
}
rc = vfs_rmdir(dparent->d_inode, dchild);
break;
case S_IFREG: {
- handle = fsfilt_start(obd, dparent->d_inode,
- FSFILT_OP_UNLINK_LOG, NULL);
+ struct lov_mds_md *lmm = lustre_msg_buf(req->rq_repmsg,
+ offset + 1, 0);
+ handle = fsfilt_start_log(obd, dparent->d_inode,
+ FSFILT_OP_UNLINK, NULL,
+ le32_to_cpu(lmm->lmm_stripe_count));
if (IS_ERR(handle))
GOTO(cleanup, rc = PTR_ERR(handle));
rc = 0;
}
- handle = fsfilt_start(obd, pending_dir, FSFILT_OP_UNLINK_LOG, NULL);
+ handle = fsfilt_start_log(obd, pending_dir, FSFILT_OP_UNLINK, NULL,
+ le32_to_cpu(lmm->lmm_stripe_count));
if (IS_ERR(handle)) {
rc = PTR_ERR(handle);
CERROR("error fsfilt_start: %d\n", rc);
#ifdef __KERNEL__
#include <linux/lustre_version.h>
#define LUSTRE_MIN_VERSION 28
-#define LUSTRE_MAX_VERSION 33
+#define LUSTRE_MAX_VERSION 34
#if (LUSTRE_KERNEL_VERSION < LUSTRE_MIN_VERSION)
# error Cannot continue: Your Lustre kernel patch is older than the sources
#elif (LUSTRE_KERNEL_VERSION > LUSTRE_MAX_VERSION)
rc = llog_lvfs_read_blob(obd, handle->lgh_file, handle->lgh_hdr,
LLOG_CHUNK_SIZE, 0);
if (rc) {
- CERROR("error reading log header\n");
+ CERROR("error reading log header from %*s\n",
+ handle->lgh_file->f_dentry->d_name.len,
+ handle->lgh_file->f_dentry->d_name.name);
} else {
struct llog_rec_hdr *llh_hdr = &handle->lgh_hdr->llh_hdr;
/*
* These need to be fixed for bug 1987
*/
if (llh_hdr->lrh_type != LLOG_HDR_MAGIC) {
- CERROR("bad log header magic: %#x (expecting %#x)\n",
+ CERROR("bad log %*s header magic: %#x (expected %#x)\n",
+ handle->lgh_file->f_dentry->d_name.len,
+ handle->lgh_file->f_dentry->d_name.name,
llh_hdr->lrh_type, LLOG_HDR_MAGIC);
rc = -EIO;
} else if (llh_hdr->lrh_len != LLOG_CHUNK_SIZE) {
- CERROR("incorrectly sized log header: %#x "
- "(expecting %#x)\n",
+ CERROR("incorrectly sized log %*s header: %#x "
+ "(expected %#x)\n",
+ handle->lgh_file->f_dentry->d_name.len,
+ handle->lgh_file->f_dentry->d_name.name,
llh_hdr->lrh_len, LLOG_CHUNK_SIZE);
CERROR("you may need to re-run lconf --write_conf.\n");
rc = -EIO;
}
}
-
handle->lgh_last_idx = handle->lgh_hdr->llh_tail.lrt_index;
handle->lgh_file->f_pos = handle->lgh_file->f_dentry->d_inode->i_size;
int rc;
ENTRY;
- fdentry = handle->lgh_file->f_dentry;
+ fdentry = handle->lgh_file->f_dentry;
if (!strcmp(fdentry->d_parent->d_name.name, "LOGS")) {
+ struct obd_device *obd = handle->lgh_ctxt->loc_exp->exp_obd;
struct inode *inode = fdentry->d_parent->d_inode;
+ struct obd_run_ctxt saved;
+
+ push_ctxt(&saved, &obd->obd_ctxt, NULL);
+ dget(fdentry);
rc = llog_lvfs_close(handle);
- if (rc)
- RETURN(rc);
- down(&inode->i_sem);
- rc = vfs_unlink(inode, fdentry);
- up(&inode->i_sem);
- RETURN(rc);
+ if (rc == 0) {
+ down(&inode->i_sem);
+ rc = vfs_unlink(inode, fdentry);
+ up(&inode->i_sem);
+ }
+
+ dput(fdentry);
+ pop_ctxt(&saved, &obd->obd_ctxt, NULL);
+ RETURN(rc);
}
oa = obdo_alloc();
} else {
CERROR("Serious error: objid %*s already "
"exists; is this filesystem corrupt?\n",
- dchild->d_name.len, dchild->d_name.name);
+ dchild->d_name.len, dchild->d_name.name);
}
GOTO(cleanup, rc = -EEXIST);
}
- handle = fsfilt_start(obd, dparent->d_inode,
- FSFILT_OP_CREATE_LOG, NULL);
+ handle = fsfilt_start_log(obd, dparent->d_inode,
+ FSFILT_OP_CREATE, NULL, 1);
if (IS_ERR(handle))
GOTO(cleanup, rc = PTR_ERR(handle));
cleanup_phase = 3;
goto acquire_locks;
}
- handle = fsfilt_start(obd, dparent->d_inode, FSFILT_OP_UNLINK_LOG, oti);
+ handle = fsfilt_start_log(obd, dparent->d_inode,FSFILT_OP_UNLINK,oti,1);
if (IS_ERR(handle))
GOTO(cleanup, rc = PTR_ERR(handle));
cleanup_phase = 3;
EXIT;
}
-#define GRANT_FOR_LLOG 16
+#define GRANT_FOR_LLOG(obd) 16
/* Figure out how much space is available between what we've granted
* and what remains in the filesystem. Compensate for ext3 indirect
avail = obd->obd_osfs.os_bavail;
left = avail - (avail >> (blockbits - 3)); /* (d)indirect */
- if (left > GRANT_FOR_LLOG) {
- left = (left - GRANT_FOR_LLOG) << blockbits;
+ if (left > GRANT_FOR_LLOG(obd)) {
+ left = (left - GRANT_FOR_LLOG(obd)) << blockbits;
} else {
left = 0 /* << blockbits */;
}
* avoid overgranting in face of multiple RPCs in flight). This
* essentially will be able to control the OSC_MAX_RIF for a client.
*
- * If we do have a large disparity and multiple RPCs in flight we
- * might grant "too much" but that's OK because it means we are
- * dirtying a lot on the client and will likely use it up quickly. */
+ * If we do have a large disparity between what the client thinks it
+ * has and what we think it has, don't grant very much and let the
+ * client consume its grant first. Either it just has lots of RPCs
+ * in flight, or it was evicted and its grants will soon be used up. */
if (current_grant < want) {
+ if (current_grant > fed->fed_grant + FILTER_GRANT_CHUNK)
+ want = 65536;
grant = min((want >> blockbits) / 2,
(fs_space_left >> blockbits) / 8);
grant <<= blockbits;
if (dentry->d_inode->i_size > lvb->lvb_size || !increase) {
CDEBUG(D_DLMTRACE, "res: "LPU64" updating lvb size from disk: "
- LPU64" -> "LPU64"\n", res->lr_name.name[0],
+ LPU64" -> %llu\n", res->lr_name.name[0],
lvb->lvb_size, dentry->d_inode->i_size);
lvb->lvb_size = dentry->d_inode->i_size;
}
if (dentry->d_inode->i_mtime > lvb->lvb_mtime || !increase) {
CDEBUG(D_DLMTRACE, "res: "LPU64" updating lvb mtime from disk: "
- LPU64" -> "LPU64"\n", res->lr_name.name[0],
- lvb->lvb_mtime,(__u64)LTIME_S(dentry->d_inode->i_mtime));
+ LPU64" -> %lu\n", res->lr_name.name[0],
+ lvb->lvb_mtime, LTIME_S(dentry->d_inode->i_mtime));
lvb->lvb_mtime = LTIME_S(dentry->d_inode->i_mtime);
}
f_dput(dentry);
LASSERT(cathandle != NULL);
inode = cathandle->lgh_file->f_dentry->d_inode;
- handle = fsfilt_start(disk_obd, inode,
- FSFILT_OP_CANCEL_UNLINK_LOG, NULL);
+ handle = fsfilt_start_log(disk_obd, inode,
+ FSFILT_OP_CANCEL_UNLINK, NULL, 1);
if (IS_ERR(handle)) {
CERROR("fsfilt_start failed: %ld\n", PTR_ERR(handle));
GOTO(pop_ctxt, rc = PTR_ERR(handle));
spin_lock_irqsave(&imp->imp_lock, flags);
if (imp->imp_state != LUSTRE_IMP_DISCON) {
in_recovery = 1;
- }
+ }
spin_unlock_irqrestore(&imp->imp_lock, flags);
if (in_recovery == 1)
RETURN(-EALREADY);
-
rc = ptlrpc_connect_import(imp, new_uuid);
if (rc)
RETURN(rc);
- CDEBUG(D_ERROR, "%s: recovery started, waiting\n",
+ CDEBUG(D_ERROR, "%s: recovery started, waiting\n",
imp->imp_target_uuid.uuid);
lwi = LWI_TIMEOUT(MAX(obd_timeout * HZ, 1), NULL, NULL);
- rc = l_wait_event(imp->imp_recovery_waitq,
+ rc = l_wait_event(imp->imp_recovery_waitq,
!ptlrpc_import_in_recovery(imp), &lwi);
- CDEBUG(D_ERROR, "%s: recovery finished\n",
+ CDEBUG(D_ERROR, "%s: recovery finished\n",
imp->imp_target_uuid.uuid);
RETURN(rc);
-
}
void ptlrpc_fail_export(struct obd_export *exp)
test_6() {
f=$DIR/$tfile
- sync
+ rm $f 2>/dev/null && sync && sleep 2 && sync # wait for delete thread
+ grep [0-9] /proc/fs/lustre/osc/OSC*MNT*/kbytes*
before=`kbytesfree`
dd if=/dev/urandom bs=1024 count=5120 of=$f
#define OBD_FAIL_MDS_REINT_NET_REP 0x119
do_facet mds "sysctl -w lustre.fail_loc=0x80000119"
sync
+ sleep 1 # ensure we have a fresh statfs
+ grep [0-9] /proc/fs/lustre/osc/OSC*MNT*/kbytes*
after_dd=`kbytesfree`
echo "before: $before after_dd: $after_dd"
- (( before > after_dd )) || return 1
+ (( $before > $after_dd )) || return 1
rm -f $f
fail ost
$CHECKSTAT -t file $f && return 2 || true
sync
# let the delete happen
sleep 2
+ grep [0-9] /proc/fs/lustre/osc/OSC*MNT*/kbytes*
after=`kbytesfree`
echo "before: $before after: $after"
- (( before == after )) || return 3
+ (( $before <= $after + 40 )) || return 3 # take OST logs into account
}
run_test 6 "Fail OST before obd_destroy"
set -e
ONLY=${ONLY:-"$*"}
-# bug number for skipped test:
-ALWAYS_EXCEPT=${ALWAYS_EXCEPT:-""}
+# bug number for skipped test: 2399 (temporarily until new kernels arrive)
+ALWAYS_EXCEPT=${ALWAYS_EXCEPT:-"48"}
# UPDATE THE COMMENT ABOVE WITH BUG NUMBERS WHEN CHANGING ALWAYS_EXCEPT!
[ "$ALWAYS_EXCEPT$EXCEPT" ] && echo "Skipping tests: $ALWAYS_EXCEPT $EXCEPT"
}
run_test 47 "Device nodes check ================================"
-test_48() {
- mkdir $DIR/d48
- cd $DIR/d48
- mv $DIR/d48 $DIR/d48.new || error "move directory failed"
- mkdir $DIR/d48 || error "recreate diectory failed"
- ls || error "can't list after recreate directory"
-}
-run_test 48 "Access renamed current working directory =========="
+test_48a() {
+ mkdir $DIR/d48a
+ cd $DIR/d48a
+ mv $DIR/d48a $DIR/d48.new || error "move directory failed"
+ mkdir $DIR/d48a || error "recreate directory failed"
+ touch foo || error "'touch foo' failed after recreating cwd"
+ mkdir bar || error "'mkdir foo' failed after recreating cwd"
+ ls . || error "'ls .' failed after recreating cwd"
+ ls .. || error "'ls ..' failed after removing cwd"
+ cd . || error "'cd .' failed after recreating cwd"
+ mkdir . && error "'mkdir .' worked after recreating cwd"
+ rmdir . && error "'rmdir .' worked after recreating cwd"
+ ln -s . baz || error "'ln -s .' failed after recreating cwd"
+}
+run_test 48a "Access renamed working dir (should return errors)="
+
+test_48b() {
+ mkdir $DIR/d48b
+ cd $DIR/d48b
+ rmdir $DIR/d48b || error "remove cwd $DIR/d48b failed"
+ touch foo && error "'touch foo' worked after removing cwd"
+ mkdir foo && error "'mkdir foo' worked after removing cwd"
+ ls . && error "'ls .' worked after removing cwd"
+ ls .. || error "'ls ..' failed after removing cwd"
+ cd . && error "'cd .' worked after recreate cwd"
+ mkdir . && error "'mkdir .' worked after removing cwd"
+ rmdir . && error "'rmdir .' worked after removing cwd"
+ ln -s . foo && error "'ln -s .' worked after removing cwd" || true
+}
+run_test 48b "Access removed working dir (should return errors)="
test_50() {
# bug 1485