diff options
Diffstat (limited to 'fs/minix/namei.c')
-rw-r--r-- | fs/minix/namei.c | 293 |
1 files changed, 125 insertions, 168 deletions
diff --git a/fs/minix/namei.c b/fs/minix/namei.c index b6041ad92..718d3dd07 100644 --- a/fs/minix/namei.c +++ b/fs/minix/namei.c @@ -47,9 +47,6 @@ static int minix_match(int len, const char * name, *offset += info->s_dirsize; if (!de->inode || len > info->s_namelen) return 0; - /* "" means "." ---> so paths like "/usr/lib//libc.a" work */ - if (!len && (de->name[0]=='.') && (de->name[1]=='\0')) - return 1; return namecompare(len,info->s_namelen,name,de->name); } @@ -104,31 +101,22 @@ static struct buffer_head * minix_find_entry(struct inode * dir, return NULL; } -int minix_lookup(struct inode * dir,const char * name, int len, - struct inode ** result) +int minix_lookup(struct inode * dir, struct dentry *dentry) { - int ino; + struct inode * inode = NULL; struct minix_dir_entry * de; struct buffer_head * bh; - *result = NULL; - if (!dir) - return -ENOENT; - if (!S_ISDIR(dir->i_mode)) { - iput(dir); - return -ENOENT; - } - if (!(bh = minix_find_entry(dir,name,len,&de))) { - iput(dir); - return -ENOENT; - } - ino = de->inode; - brelse(bh); - if (!(*result = iget(dir->i_sb,ino))) { - iput(dir); - return -EACCES; - } - iput(dir); + bh = minix_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de); + if (bh) { + unsigned long ino = le32_to_cpu(de->inode); + brelse (bh); + inode = iget(dir->i_sb, ino); + + if (!inode) + return -EACCES; + } + d_add(dentry, inode); return 0; } @@ -180,7 +168,7 @@ static int minix_add_entry(struct inode * dir, if (block*bh->b_size + offset > dir->i_size) { de->inode = 0; dir->i_size = block*bh->b_size + offset; - dir->i_dirt = 1; + mark_inode_dirty(dir); } if (de->inode) { if (namecompare(namelen, info->s_namelen, name, de->name)) { @@ -189,7 +177,7 @@ static int minix_add_entry(struct inode * dir, } } else { dir->i_mtime = dir->i_ctime = CURRENT_TIME; - dir->i_dirt = 1; + mark_inode_dirty(dir); for (i = 0; i < info->s_namelen ; i++) de->name[i] = (i < namelen) ? name[i] : 0; dir->i_version = ++event; @@ -208,42 +196,37 @@ static int minix_add_entry(struct inode * dir, return 0; } -int minix_create(struct inode * dir,const char * name, int len, int mode, - struct inode ** result) +int minix_create(struct inode * dir, struct dentry *dentry, int mode) { int error; struct inode * inode; struct buffer_head * bh; struct minix_dir_entry * de; - *result = NULL; if (!dir) return -ENOENT; inode = minix_new_inode(dir); - if (!inode) { - iput(dir); + if (!inode) return -ENOSPC; - } inode->i_op = &minix_file_inode_operations; inode->i_mode = mode; - inode->i_dirt = 1; - error = minix_add_entry(dir,name,len, &bh ,&de); + mark_inode_dirty(inode); + error = minix_add_entry(dir, dentry->d_name.name, + dentry->d_name.len, &bh ,&de); if (error) { inode->i_nlink--; - inode->i_dirt = 1; + mark_inode_dirty(inode); iput(inode); - iput(dir); return error; } de->inode = inode->i_ino; mark_buffer_dirty(bh, 1); brelse(bh); - iput(dir); - *result = inode; + d_instantiate(dentry, inode); return 0; } -int minix_mknod(struct inode * dir, const char * name, int len, int mode, int rdev) +int minix_mknod(struct inode * dir, struct dentry *dentry, int mode, int rdev) { int error; struct inode * inode; @@ -252,17 +235,15 @@ int minix_mknod(struct inode * dir, const char * name, int len, int mode, int rd if (!dir) return -ENOENT; - bh = minix_find_entry(dir,name,len,&de); + bh = minix_find_entry(dir, dentry->d_name.name, + dentry->d_name.len, &de); if (bh) { brelse(bh); - iput(dir); return -EEXIST; } inode = minix_new_inode(dir); - if (!inode) { - iput(dir); + if (!inode) return -ENOSPC; - } inode->i_uid = current->fsuid; inode->i_mode = mode; inode->i_op = NULL; @@ -283,24 +264,22 @@ int minix_mknod(struct inode * dir, const char * name, int len, int mode, int rd init_fifo(inode); if (S_ISBLK(mode) || S_ISCHR(mode)) inode->i_rdev = to_kdev_t(rdev); - inode->i_dirt = 1; - error = minix_add_entry(dir, name, len, &bh, &de); + mark_inode_dirty(inode); + error = minix_add_entry(dir, dentry->d_name.name, dentry->d_name.len, &bh, &de); if (error) { inode->i_nlink--; - inode->i_dirt = 1; + mark_inode_dirty(inode); iput(inode); - iput(dir); return error; } de->inode = inode->i_ino; mark_buffer_dirty(bh, 1); brelse(bh); - iput(dir); - iput(inode); + d_instantiate(dentry, inode); return 0; } -int minix_mkdir(struct inode * dir, const char * name, int len, int mode) +int minix_mkdir(struct inode * dir, struct dentry *dentry, int mode) { int error; struct inode * inode; @@ -308,33 +287,26 @@ int minix_mkdir(struct inode * dir, const char * name, int len, int mode) struct minix_dir_entry * de; struct minix_sb_info * info; - if (!dir || !dir->i_sb) { - iput(dir); + if (!dir || !dir->i_sb) return -EINVAL; - } info = &dir->i_sb->u.minix_sb; - bh = minix_find_entry(dir,name,len,&de); + bh = minix_find_entry(dir, dentry->d_name.name, + dentry->d_name.len, &de); if (bh) { brelse(bh); - iput(dir); return -EEXIST; } - if (dir->i_nlink >= MINIX_LINK_MAX) { - iput(dir); + if (dir->i_nlink >= MINIX_LINK_MAX) return -EMLINK; - } inode = minix_new_inode(dir); - if (!inode) { - iput(dir); + if (!inode) return -ENOSPC; - } inode->i_op = &minix_dir_inode_operations; inode->i_size = 2 * info->s_dirsize; dir_block = minix_bread(inode,0,1); if (!dir_block) { - iput(dir); inode->i_nlink--; - inode->i_dirt = 1; + mark_inode_dirty(inode); iput(inode); return -ENOSPC; } @@ -350,10 +322,10 @@ int minix_mkdir(struct inode * dir, const char * name, int len, int mode) inode->i_mode = S_IFDIR | (mode & 0777 & ~current->fs->umask); if (dir->i_mode & S_ISGID) inode->i_mode |= S_ISGID; - inode->i_dirt = 1; - error = minix_add_entry(dir, name, len, &bh, &de); + mark_inode_dirty(inode); + error = minix_add_entry(dir, dentry->d_name.name, + dentry->d_name.len, &bh, &de); if (error) { - iput(dir); inode->i_nlink=0; iput(inode); return error; @@ -361,10 +333,9 @@ int minix_mkdir(struct inode * dir, const char * name, int len, int mode) de->inode = inode->i_ino; mark_buffer_dirty(bh, 1); dir->i_nlink++; - dir->i_dirt = 1; - iput(dir); - iput(inode); + mark_inode_dirty(dir); brelse(bh); + d_instantiate(dentry, inode); return 0; } @@ -427,7 +398,7 @@ bad_dir: return 1; } -int minix_rmdir(struct inode * dir, const char * name, int len) +int minix_rmdir(struct inode * dir, struct dentry *dentry) { int retval; struct inode * inode; @@ -435,13 +406,14 @@ int minix_rmdir(struct inode * dir, const char * name, int len) struct minix_dir_entry * de; inode = NULL; - bh = minix_find_entry(dir,name,len,&de); + bh = minix_find_entry(dir, dentry->d_name.name, + dentry->d_name.len, &de); retval = -ENOENT; if (!bh) goto end_rmdir; retval = -EPERM; - if (!(inode = iget(dir->i_sb, de->inode))) - goto end_rmdir; + inode = dentry->d_inode; + if ((dir->i_mode & S_ISVTX) && !fsuser() && current->fsuid != inode->i_uid && current->fsuid != dir->i_uid) @@ -462,7 +434,7 @@ int minix_rmdir(struct inode * dir, const char * name, int len) retval = -ENOENT; goto end_rmdir; } - if (atomic_read(&inode->i_count) > 1) { + if (inode->i_count > 1) { retval = -EBUSY; goto end_rmdir; } @@ -472,19 +444,18 @@ int minix_rmdir(struct inode * dir, const char * name, int len) dir->i_version = ++event; mark_buffer_dirty(bh, 1); inode->i_nlink=0; - inode->i_dirt=1; + mark_inode_dirty(inode); inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; dir->i_nlink--; - dir->i_dirt=1; + mark_inode_dirty(dir); + d_delete(dentry); retval = 0; end_rmdir: - iput(dir); - iput(inode); brelse(bh); return retval; } -int minix_unlink(struct inode * dir, const char * name, int len) +int minix_unlink(struct inode * dir, struct dentry *dentry) { int retval; struct inode * inode; @@ -494,16 +465,16 @@ int minix_unlink(struct inode * dir, const char * name, int len) repeat: retval = -ENOENT; inode = NULL; - bh = minix_find_entry(dir,name,len,&de); + bh = minix_find_entry(dir, dentry->d_name.name, + dentry->d_name.len, &de); if (!bh) goto end_unlink; - if (!(inode = iget(dir->i_sb, de->inode))) - goto end_unlink; + inode = dentry->d_inode; + retval = -EPERM; if (S_ISDIR(inode->i_mode)) goto end_unlink; if (de->inode != inode->i_ino) { - iput(inode); brelse(bh); current->counter = 0; schedule(); @@ -527,19 +498,19 @@ repeat: dir->i_version = ++event; mark_buffer_dirty(bh, 1); dir->i_ctime = dir->i_mtime = CURRENT_TIME; - dir->i_dirt = 1; + mark_inode_dirty(dir); inode->i_nlink--; inode->i_ctime = dir->i_ctime; - inode->i_dirt = 1; + mark_inode_dirty(inode); + d_delete(dentry); /* This also frees the inode */ retval = 0; end_unlink: brelse(bh); - iput(inode); - iput(dir); return retval; } -int minix_symlink(struct inode * dir, const char * name, int len, const char * symname) +int minix_symlink(struct inode * dir, struct dentry *dentry, + const char * symname) { struct minix_dir_entry * de; struct inode * inode = NULL; @@ -547,17 +518,15 @@ int minix_symlink(struct inode * dir, const char * name, int len, const char * s int i; char c; - if (!(inode = minix_new_inode(dir))) { - iput(dir); + if (!(inode = minix_new_inode(dir))) return -ENOSPC; - } + inode->i_mode = S_IFLNK | 0777; inode->i_op = &minix_symlink_inode_operations; name_block = minix_bread(inode,0,1); if (!name_block) { - iput(dir); inode->i_nlink--; - inode->i_dirt = 1; + mark_inode_dirty(inode); iput(inode); return -ENOSPC; } @@ -568,93 +537,81 @@ int minix_symlink(struct inode * dir, const char * name, int len, const char * s mark_buffer_dirty(name_block, 1); brelse(name_block); inode->i_size = i; - inode->i_dirt = 1; - bh = minix_find_entry(dir,name,len,&de); + mark_inode_dirty(inode); + bh = minix_find_entry(dir, dentry->d_name.name, + dentry->d_name.len, &de); if (bh) { inode->i_nlink--; - inode->i_dirt = 1; + mark_inode_dirty(inode); iput(inode); brelse(bh); - iput(dir); return -EEXIST; } - i = minix_add_entry(dir, name, len, &bh, &de); + i = minix_add_entry(dir, dentry->d_name.name, + dentry->d_name.len, &bh, &de); if (i) { inode->i_nlink--; - inode->i_dirt = 1; + mark_inode_dirty(inode); iput(inode); - iput(dir); return i; } de->inode = inode->i_ino; mark_buffer_dirty(bh, 1); brelse(bh); - iput(dir); - iput(inode); + d_instantiate(dentry, inode); return 0; } -int minix_link(struct inode * oldinode, struct inode * dir, const char * name, int len) +int minix_link(struct inode * inode, struct inode * dir, + struct dentry *dentry) { int error; struct minix_dir_entry * de; struct buffer_head * bh; - if (S_ISDIR(oldinode->i_mode)) { - iput(oldinode); - iput(dir); + if (S_ISDIR(inode->i_mode)) return -EPERM; - } - if (oldinode->i_nlink >= MINIX_LINK_MAX) { - iput(oldinode); - iput(dir); + + if (inode->i_nlink >= MINIX_LINK_MAX) return -EMLINK; - } - bh = minix_find_entry(dir,name,len,&de); + + bh = minix_find_entry(dir, dentry->d_name.name, + dentry->d_name.len, &de); if (bh) { brelse(bh); - iput(dir); - iput(oldinode); return -EEXIST; } - error = minix_add_entry(dir, name, len, &bh, &de); + error = minix_add_entry(dir, dentry->d_name.name, + dentry->d_name.len, &bh, &de); if (error) { - iput(dir); - iput(oldinode); + brelse(bh); return error; } - de->inode = oldinode->i_ino; + de->inode = inode->i_ino; mark_buffer_dirty(bh, 1); brelse(bh); - iput(dir); - oldinode->i_nlink++; - oldinode->i_ctime = CURRENT_TIME; - oldinode->i_dirt = 1; - iput(oldinode); + inode->i_nlink++; + inode->i_ctime = CURRENT_TIME; + mark_inode_dirty(inode); + d_instantiate(dentry, inode); return 0; } -static int subdir(struct inode * new_inode, struct inode * old_inode) +static int subdir(struct dentry * new_dentry, struct dentry * old_dentry) { - int ino; - int result; + int result = 0; - atomic_inc(&new_inode->i_count); - result = 0; for (;;) { - if (new_inode == old_inode) { - result = 1; - break; + if (new_dentry != old_dentry) { + struct dentry * parent = new_dentry->d_parent; + if (parent == new_dentry) + break; + new_dentry = parent; + continue; } - if (new_inode->i_dev != old_inode->i_dev) - break; - ino = new_inode->i_ino; - if (minix_lookup(new_inode,"..",2,&new_inode)) - break; - if (new_inode->i_ino == ino) - break; + result = 1; + break; } - iput(new_inode); return result; } @@ -671,8 +628,8 @@ static int subdir(struct inode * new_inode, struct inode * old_inode) * Anybody can rename anything with this: the permission checks are left to the * higher-level routines. */ -static int do_minix_rename(struct inode * old_dir, const char * old_name, int old_len, - struct inode * new_dir, const char * new_name, int new_len) +static int do_minix_rename(struct inode * old_dir, struct dentry *old_dentry, + struct inode * new_dir, struct dentry *new_dentry) { struct inode * old_inode, * new_inode; struct buffer_head * old_bh, * new_bh, * dir_bh; @@ -686,28 +643,26 @@ try_again: brelse(old_bh); brelse(new_bh); brelse(dir_bh); - iput(old_inode); - iput(new_inode); current->counter = 0; schedule(); start_up: old_inode = new_inode = NULL; old_bh = new_bh = dir_bh = NULL; - old_bh = minix_find_entry(old_dir,old_name,old_len,&old_de); + old_bh = minix_find_entry(old_dir, old_dentry->d_name.name, + old_dentry->d_name.len, &old_de); retval = -ENOENT; if (!old_bh) goto end_rename; - old_inode = __iget(old_dir->i_sb, old_de->inode,0); /* don't cross mnt-points */ - if (!old_inode) - goto end_rename; + old_inode = old_dentry->d_inode; retval = -EPERM; if ((old_dir->i_mode & S_ISVTX) && current->fsuid != old_inode->i_uid && current->fsuid != old_dir->i_uid && !fsuser()) goto end_rename; - new_bh = minix_find_entry(new_dir,new_name,new_len,&new_de); + new_inode = new_dentry->d_inode; + new_bh = minix_find_entry(new_dir, new_dentry->d_name.name, + new_dentry->d_name.len, &new_de); if (new_bh) { - new_inode = __iget(new_dir->i_sb, new_de->inode, 0); if (!new_inode) { brelse(new_bh); new_bh = NULL; @@ -722,13 +677,13 @@ start_up: if (!S_ISDIR(old_inode->i_mode)) goto end_rename; retval = -EINVAL; - if (subdir(new_dir, old_inode)) + if (subdir(new_dentry, old_dentry)) goto end_rename; retval = -ENOTEMPTY; if (!empty_dir(new_inode)) goto end_rename; retval = -EBUSY; - if (atomic_read(&new_inode->i_count) > 1) + if (new_inode->i_count > 1) goto end_rename; } retval = -EPERM; @@ -741,7 +696,7 @@ start_up: if (new_inode && !S_ISDIR(new_inode->i_mode)) goto end_rename; retval = -EINVAL; - if (subdir(new_dir, old_inode)) + if (subdir(new_dentry, old_dentry)) goto end_rename; retval = -EIO; dir_bh = minix_bread(old_inode,0,0); @@ -754,7 +709,10 @@ start_up: goto end_rename; } if (!new_bh) { - retval = minix_add_entry(new_dir,new_name,new_len,&new_bh,&new_de); + retval = minix_add_entry(new_dir, + new_dentry->d_name.name, + new_dentry->d_name.len, + &new_bh, &new_de); if (retval) goto end_rename; } @@ -769,15 +727,15 @@ start_up: old_de->inode = 0; new_de->inode = old_inode->i_ino; old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME; - old_dir->i_dirt = 1; + mark_inode_dirty(old_dir); old_dir->i_version = ++event; new_dir->i_ctime = new_dir->i_mtime = CURRENT_TIME; - new_dir->i_dirt = 1; + mark_inode_dirty(new_dir); new_dir->i_version = ++event; if (new_inode) { new_inode->i_nlink--; new_inode->i_ctime = CURRENT_TIME; - new_inode->i_dirt = 1; + mark_inode_dirty(new_inode); } mark_buffer_dirty(old_bh, 1); mark_buffer_dirty(new_bh, 1); @@ -785,24 +743,23 @@ start_up: PARENT_INO(dir_bh->b_data) = new_dir->i_ino; mark_buffer_dirty(dir_bh, 1); old_dir->i_nlink--; - old_dir->i_dirt = 1; + mark_inode_dirty(old_dir); if (new_inode) { new_inode->i_nlink--; - new_inode->i_dirt = 1; + mark_inode_dirty(new_inode); } else { new_dir->i_nlink++; - new_dir->i_dirt = 1; + mark_inode_dirty(new_dir); } } + /* Update the dcache */ + d_move(old_dentry, new_dentry->d_parent, &new_dentry->d_name); + d_delete(new_dentry); retval = 0; end_rename: brelse(dir_bh); brelse(old_bh); brelse(new_bh); - iput(old_inode); - iput(new_inode); - iput(old_dir); - iput(new_dir); return retval; } @@ -815,8 +772,8 @@ end_rename: * the same device that races occur: many renames can happen at once, as long * as they are on different partitions. */ -int minix_rename(struct inode * old_dir, const char * old_name, int old_len, - struct inode * new_dir, const char * new_name, int new_len) +int minix_rename(struct inode * old_dir, struct dentry *old_dentry, + struct inode * new_dir, struct dentry *new_dentry) { static struct wait_queue * wait = NULL; static int lock = 0; @@ -825,8 +782,8 @@ int minix_rename(struct inode * old_dir, const char * old_name, int old_len, while (lock) sleep_on(&wait); lock = 1; - result = do_minix_rename(old_dir, old_name, old_len, - new_dir, new_name, new_len); + result = do_minix_rename(old_dir, old_dentry, + new_dir, new_dentry); lock = 0; wake_up(&wait); return result; |