namei.c 7.7 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3
/*
 * linux/fs/ufs/namei.c
 *
4 5 6
 * Migration to usage of "page cache" on May 2006 by
 * Evgeniy Dushistov <dushistov@mail.ru> based on ext2 code base.
 *
L
Linus Torvalds 已提交
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
 * Copyright (C) 1998
 * Daniel Pirkl <daniel.pirkl@email.cz>
 * Charles University, Faculty of Mathematics and Physics
 *
 *  from
 *
 *  linux/fs/ext2/namei.c
 *
 * Copyright (C) 1992, 1993, 1994, 1995
 * Remy Card (card@masi.ibp.fr)
 * Laboratoire MASI - Institut Blaise Pascal
 * Universite Pierre et Marie Curie (Paris VI)
 *
 *  from
 *
 *  linux/fs/minix/namei.c
 *
 *  Copyright (C) 1991, 1992  Linus Torvalds
 *
 *  Big-endian to little-endian byte-swapping/bitmaps by
 *        David S. Miller (davem@caip.rutgers.edu), 1995
 */

#include <linux/time.h>
#include <linux/fs.h>
#include <linux/ufs_fs.h>
#include <linux/smp_lock.h>
34
#include "ufs.h"
L
Linus Torvalds 已提交
35 36 37 38 39 40 41 42 43
#include "util.h"

static inline int ufs_add_nondir(struct dentry *dentry, struct inode *inode)
{
	int err = ufs_add_link(dentry, inode);
	if (!err) {
		d_instantiate(dentry, inode);
		return 0;
	}
44
	inode_dec_link_count(inode);
L
Linus Torvalds 已提交
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
	iput(inode);
	return err;
}

static struct dentry *ufs_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd)
{
	struct inode * inode = NULL;
	ino_t ino;
	
	if (dentry->d_name.len > UFS_MAXNAMLEN)
		return ERR_PTR(-ENAMETOOLONG);

	lock_kernel();
	ino = ufs_inode_by_name(dir, dentry);
	if (ino) {
60 61
		inode = ufs_iget(dir->i_sb, ino);
		if (IS_ERR(inode)) {
L
Linus Torvalds 已提交
62
			unlock_kernel();
63
			return ERR_CAST(inode);
L
Linus Torvalds 已提交
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
		}
	}
	unlock_kernel();
	d_add(dentry, inode);
	return NULL;
}

/*
 * By the time this is called, we already have created
 * the directory cache entry for the new file, but it
 * is so far negative - it has no inode.
 *
 * If the create succeeds, we fill in the inode information
 * with d_instantiate(). 
 */
static int ufs_create (struct inode * dir, struct dentry * dentry, int mode,
		struct nameidata *nd)
{
E
Evgeniy Dushistov 已提交
82 83 84 85 86 87 88
	struct inode *inode;
	int err;

	UFSD("BEGIN\n");
	inode = ufs_new_inode(dir, mode);
	err = PTR_ERR(inode);

L
Linus Torvalds 已提交
89 90 91 92 93 94 95 96 97
	if (!IS_ERR(inode)) {
		inode->i_op = &ufs_file_inode_operations;
		inode->i_fop = &ufs_file_operations;
		inode->i_mapping->a_ops = &ufs_aops;
		mark_inode_dirty(inode);
		lock_kernel();
		err = ufs_add_nondir(dentry, inode);
		unlock_kernel();
	}
E
Evgeniy Dushistov 已提交
98
	UFSD("END: err=%d\n", err);
L
Linus Torvalds 已提交
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
	return err;
}

static int ufs_mknod (struct inode * dir, struct dentry *dentry, int mode, dev_t rdev)
{
	struct inode *inode;
	int err;

	if (!old_valid_dev(rdev))
		return -EINVAL;
	inode = ufs_new_inode(dir, mode);
	err = PTR_ERR(inode);
	if (!IS_ERR(inode)) {
		init_special_inode(inode, mode, rdev);
		ufs_set_inode_dev(inode->i_sb, UFS_I(inode), rdev);
		mark_inode_dirty(inode);
		lock_kernel();
		err = ufs_add_nondir(dentry, inode);
		unlock_kernel();
	}
	return err;
}

static int ufs_symlink (struct inode * dir, struct dentry * dentry,
	const char * symname)
{
	struct super_block * sb = dir->i_sb;
	int err = -ENAMETOOLONG;
	unsigned l = strlen(symname)+1;
	struct inode * inode;

	if (l > sb->s_blocksize)
131
		goto out_notlocked;
L
Linus Torvalds 已提交
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156

	lock_kernel();
	inode = ufs_new_inode(dir, S_IFLNK | S_IRWXUGO);
	err = PTR_ERR(inode);
	if (IS_ERR(inode))
		goto out;

	if (l > UFS_SB(sb)->s_uspi->s_maxsymlinklen) {
		/* slow symlink */
		inode->i_op = &page_symlink_inode_operations;
		inode->i_mapping->a_ops = &ufs_aops;
		err = page_symlink(inode, symname, l);
		if (err)
			goto out_fail;
	} else {
		/* fast symlink */
		inode->i_op = &ufs_fast_symlink_inode_operations;
		memcpy((char*)&UFS_I(inode)->i_u1.i_data,symname,l);
		inode->i_size = l-1;
	}
	mark_inode_dirty(inode);

	err = ufs_add_nondir(dentry, inode);
out:
	unlock_kernel();
157
out_notlocked:
L
Linus Torvalds 已提交
158 159 160
	return err;

out_fail:
161
	inode_dec_link_count(inode);
L
Linus Torvalds 已提交
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
	iput(inode);
	goto out;
}

static int ufs_link (struct dentry * old_dentry, struct inode * dir,
	struct dentry *dentry)
{
	struct inode *inode = old_dentry->d_inode;
	int error;

	lock_kernel();
	if (inode->i_nlink >= UFS_LINK_MAX) {
		unlock_kernel();
		return -EMLINK;
	}

	inode->i_ctime = CURRENT_TIME_SEC;
179
	inode_inc_link_count(inode);
L
Linus Torvalds 已提交
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
	atomic_inc(&inode->i_count);

	error = ufs_add_nondir(dentry, inode);
	unlock_kernel();
	return error;
}

static int ufs_mkdir(struct inode * dir, struct dentry * dentry, int mode)
{
	struct inode * inode;
	int err = -EMLINK;

	if (dir->i_nlink >= UFS_LINK_MAX)
		goto out;

	lock_kernel();
196
	inode_inc_link_count(dir);
L
Linus Torvalds 已提交
197 198 199 200 201 202 203 204

	inode = ufs_new_inode(dir, S_IFDIR|mode);
	err = PTR_ERR(inode);
	if (IS_ERR(inode))
		goto out_dir;

	inode->i_op = &ufs_dir_inode_operations;
	inode->i_fop = &ufs_dir_operations;
205
	inode->i_mapping->a_ops = &ufs_aops;
L
Linus Torvalds 已提交
206

207
	inode_inc_link_count(inode);
L
Linus Torvalds 已提交
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222

	err = ufs_make_empty(inode, dir);
	if (err)
		goto out_fail;

	err = ufs_add_link(dentry, inode);
	if (err)
		goto out_fail;
	unlock_kernel();

	d_instantiate(dentry, inode);
out:
	return err;

out_fail:
223 224
	inode_dec_link_count(inode);
	inode_dec_link_count(inode);
L
Linus Torvalds 已提交
225 226
	iput (inode);
out_dir:
227
	inode_dec_link_count(dir);
L
Linus Torvalds 已提交
228 229 230 231
	unlock_kernel();
	goto out;
}

232
static int ufs_unlink(struct inode *dir, struct dentry *dentry)
L
Linus Torvalds 已提交
233 234
{
	struct inode * inode = dentry->d_inode;
235 236
	struct ufs_dir_entry *de;
	struct page *page;
L
Linus Torvalds 已提交
237 238
	int err = -ENOENT;

239
	de = ufs_find_entry(dir, dentry, &page);
L
Linus Torvalds 已提交
240 241 242
	if (!de)
		goto out;

243
	err = ufs_delete_entry(dir, de, page);
L
Linus Torvalds 已提交
244 245 246 247
	if (err)
		goto out;

	inode->i_ctime = dir->i_ctime;
248
	inode_dec_link_count(inode);
L
Linus Torvalds 已提交
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
	err = 0;
out:
	return err;
}

static int ufs_rmdir (struct inode * dir, struct dentry *dentry)
{
	struct inode * inode = dentry->d_inode;
	int err= -ENOTEMPTY;

	lock_kernel();
	if (ufs_empty_dir (inode)) {
		err = ufs_unlink(dir, dentry);
		if (!err) {
			inode->i_size = 0;
264 265
			inode_dec_link_count(inode);
			inode_dec_link_count(dir);
L
Linus Torvalds 已提交
266 267 268 269 270 271
		}
	}
	unlock_kernel();
	return err;
}

272 273
static int ufs_rename(struct inode *old_dir, struct dentry *old_dentry,
		      struct inode *new_dir, struct dentry *new_dentry)
L
Linus Torvalds 已提交
274 275 276
{
	struct inode *old_inode = old_dentry->d_inode;
	struct inode *new_inode = new_dentry->d_inode;
277 278 279
	struct page *dir_page = NULL;
	struct ufs_dir_entry * dir_de = NULL;
	struct page *old_page;
L
Linus Torvalds 已提交
280 281 282
	struct ufs_dir_entry *old_de;
	int err = -ENOENT;

283
	old_de = ufs_find_entry(old_dir, old_dentry, &old_page);
L
Linus Torvalds 已提交
284 285 286 287 288
	if (!old_de)
		goto out;

	if (S_ISDIR(old_inode->i_mode)) {
		err = -EIO;
289
		dir_de = ufs_dotdot(old_inode, &dir_page);
L
Linus Torvalds 已提交
290 291 292 293 294
		if (!dir_de)
			goto out_old;
	}

	if (new_inode) {
295
		struct page *new_page;
L
Linus Torvalds 已提交
296 297 298
		struct ufs_dir_entry *new_de;

		err = -ENOTEMPTY;
299
		if (dir_de && !ufs_empty_dir(new_inode))
L
Linus Torvalds 已提交
300
			goto out_dir;
301

L
Linus Torvalds 已提交
302
		err = -ENOENT;
303
		new_de = ufs_find_entry(new_dir, new_dentry, &new_page);
L
Linus Torvalds 已提交
304 305
		if (!new_de)
			goto out_dir;
306
		inode_inc_link_count(old_inode);
307
		ufs_set_link(new_dir, new_de, new_page, old_inode);
L
Linus Torvalds 已提交
308 309
		new_inode->i_ctime = CURRENT_TIME_SEC;
		if (dir_de)
310
			drop_nlink(new_inode);
311
		inode_dec_link_count(new_inode);
L
Linus Torvalds 已提交
312 313 314 315 316 317
	} else {
		if (dir_de) {
			err = -EMLINK;
			if (new_dir->i_nlink >= UFS_LINK_MAX)
				goto out_dir;
		}
318
		inode_inc_link_count(old_inode);
L
Linus Torvalds 已提交
319 320
		err = ufs_add_link(new_dentry, old_inode);
		if (err) {
321
			inode_dec_link_count(old_inode);
L
Linus Torvalds 已提交
322 323 324
			goto out_dir;
		}
		if (dir_de)
325
			inode_inc_link_count(new_dir);
L
Linus Torvalds 已提交
326 327
	}

328 329 330 331 332 333
	/*
	 * Like most other Unix systems, set the ctime for inodes on a
 	 * rename.
	 * inode_dec_link_count() will mark the inode dirty.
	 */
	old_inode->i_ctime = CURRENT_TIME_SEC;
L
Linus Torvalds 已提交
334

335
	ufs_delete_entry(old_dir, old_de, old_page);
336
	inode_dec_link_count(old_inode);
L
Linus Torvalds 已提交
337 338

	if (dir_de) {
339
		ufs_set_link(old_inode, dir_de, dir_page, new_dir);
340
		inode_dec_link_count(old_dir);
L
Linus Torvalds 已提交
341 342 343
	}
	return 0;

344

L
Linus Torvalds 已提交
345
out_dir:
346 347 348 349
	if (dir_de) {
		kunmap(dir_page);
		page_cache_release(dir_page);
	}
L
Linus Torvalds 已提交
350
out_old:
351 352
	kunmap(old_page);
	page_cache_release(old_page);
L
Linus Torvalds 已提交
353 354 355 356
out:
	return err;
}

357
const struct inode_operations ufs_dir_inode_operations = {
L
Linus Torvalds 已提交
358 359 360 361 362 363 364 365 366 367
	.create		= ufs_create,
	.lookup		= ufs_lookup,
	.link		= ufs_link,
	.unlink		= ufs_unlink,
	.symlink	= ufs_symlink,
	.mkdir		= ufs_mkdir,
	.rmdir		= ufs_rmdir,
	.mknod		= ufs_mknod,
	.rename		= ufs_rename,
};