Blame view

fs/ufs/namei.c 7.67 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
  /*
   * linux/fs/ufs/namei.c
   *
b71034e5e   Evgeniy Dushistov   [PATCH] ufs: dire...
4
5
6
   * Migration to usage of "page cache" on May 2006 by
   * Evgeniy Dushistov <dushistov@mail.ru> based on ext2 code base.
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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
   * 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>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
  #include <linux/smp_lock.h>
e54205988   Mike Frysinger   drop linux/ufs_fs...
33
34
  
  #include "ufs_fs.h"
bcd6d4ecf   Christoph Hellwig   ufs: move non-lay...
35
  #include "ufs.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
  #include "util.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
38
39
40
41
42
43
  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;
  	}
3257545e4   Alexey Dobriyan   [PATCH] ufs: swit...
44
  	inode_dec_link_count(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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) {
b55c460da   David Howells   iget: stop UFS fr...
60
61
  		inode = ufs_iget(dir->i_sb, ino);
  		if (IS_ERR(inode)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
  			unlock_kernel();
b55c460da   David Howells   iget: stop UFS fr...
63
  			return ERR_CAST(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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)
  {
abf5d15fd   Evgeniy Dushistov   [PATCH] ufs: easy...
82
83
84
85
86
87
88
  	struct inode *inode;
  	int err;
  
  	UFSD("BEGIN
  ");
  	inode = ufs_new_inode(dir, mode);
  	err = PTR_ERR(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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();
  	}
abf5d15fd   Evgeniy Dushistov   [PATCH] ufs: easy...
98
99
  	UFSD("END: err=%d
  ", err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100
101
102
103
104
105
106
107
108
109
110
111
112
113
  	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);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
  		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)
344fe7866   Josh Triplett   [PATCH] ufs: remo...
132
  		goto out_notlocked;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
  
  	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;
723be1f30   Duane Griffin   ufs: copy symlink...
150
  		memcpy(UFS_I(inode)->i_u1.i_symlink, symname, l);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151
152
153
154
155
156
157
  		inode->i_size = l-1;
  	}
  	mark_inode_dirty(inode);
  
  	err = ufs_add_nondir(dentry, inode);
  out:
  	unlock_kernel();
344fe7866   Josh Triplett   [PATCH] ufs: remo...
158
  out_notlocked:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
159
160
161
  	return err;
  
  out_fail:
3257545e4   Alexey Dobriyan   [PATCH] ufs: swit...
162
  	inode_dec_link_count(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
  	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;
3257545e4   Alexey Dobriyan   [PATCH] ufs: swit...
180
  	inode_inc_link_count(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
  	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();
3257545e4   Alexey Dobriyan   [PATCH] ufs: swit...
197
  	inode_inc_link_count(dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
198
199
200
201
202
203
204
205
  
  	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;
826843a34   Evgeniy Dushistov   [PATCH] ufs: dire...
206
  	inode->i_mapping->a_ops = &ufs_aops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
207

3257545e4   Alexey Dobriyan   [PATCH] ufs: swit...
208
  	inode_inc_link_count(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
  
  	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:
3257545e4   Alexey Dobriyan   [PATCH] ufs: swit...
224
225
  	inode_dec_link_count(inode);
  	inode_dec_link_count(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226
227
  	iput (inode);
  out_dir:
3257545e4   Alexey Dobriyan   [PATCH] ufs: swit...
228
  	inode_dec_link_count(dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
229
230
231
  	unlock_kernel();
  	goto out;
  }
b71034e5e   Evgeniy Dushistov   [PATCH] ufs: dire...
232
  static int ufs_unlink(struct inode *dir, struct dentry *dentry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
233
234
  {
  	struct inode * inode = dentry->d_inode;
b71034e5e   Evgeniy Dushistov   [PATCH] ufs: dire...
235
236
  	struct ufs_dir_entry *de;
  	struct page *page;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
237
  	int err = -ENOENT;
b71034e5e   Evgeniy Dushistov   [PATCH] ufs: dire...
238
  	de = ufs_find_entry(dir, dentry, &page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
239
240
  	if (!de)
  		goto out;
b71034e5e   Evgeniy Dushistov   [PATCH] ufs: dire...
241
  	err = ufs_delete_entry(dir, de, page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
242
243
244
245
  	if (err)
  		goto out;
  
  	inode->i_ctime = dir->i_ctime;
3257545e4   Alexey Dobriyan   [PATCH] ufs: swit...
246
  	inode_dec_link_count(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247
248
  	err = 0;
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
249
250
251
252
253
254
255
256
257
258
259
260
261
  	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;
3257545e4   Alexey Dobriyan   [PATCH] ufs: swit...
262
263
  			inode_dec_link_count(inode);
  			inode_dec_link_count(dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
264
265
266
267
268
  		}
  	}
  	unlock_kernel();
  	return err;
  }
b71034e5e   Evgeniy Dushistov   [PATCH] ufs: dire...
269
270
  static int ufs_rename(struct inode *old_dir, struct dentry *old_dentry,
  		      struct inode *new_dir, struct dentry *new_dentry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
271
272
273
  {
  	struct inode *old_inode = old_dentry->d_inode;
  	struct inode *new_inode = new_dentry->d_inode;
b71034e5e   Evgeniy Dushistov   [PATCH] ufs: dire...
274
275
276
  	struct page *dir_page = NULL;
  	struct ufs_dir_entry * dir_de = NULL;
  	struct page *old_page;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
277
278
  	struct ufs_dir_entry *old_de;
  	int err = -ENOENT;
b71034e5e   Evgeniy Dushistov   [PATCH] ufs: dire...
279
  	old_de = ufs_find_entry(old_dir, old_dentry, &old_page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
280
281
282
283
284
  	if (!old_de)
  		goto out;
  
  	if (S_ISDIR(old_inode->i_mode)) {
  		err = -EIO;
b71034e5e   Evgeniy Dushistov   [PATCH] ufs: dire...
285
  		dir_de = ufs_dotdot(old_inode, &dir_page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
286
287
288
289
290
  		if (!dir_de)
  			goto out_old;
  	}
  
  	if (new_inode) {
b71034e5e   Evgeniy Dushistov   [PATCH] ufs: dire...
291
  		struct page *new_page;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
292
293
294
  		struct ufs_dir_entry *new_de;
  
  		err = -ENOTEMPTY;
b71034e5e   Evgeniy Dushistov   [PATCH] ufs: dire...
295
  		if (dir_de && !ufs_empty_dir(new_inode))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
296
  			goto out_dir;
b71034e5e   Evgeniy Dushistov   [PATCH] ufs: dire...
297

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
298
  		err = -ENOENT;
b71034e5e   Evgeniy Dushistov   [PATCH] ufs: dire...
299
  		new_de = ufs_find_entry(new_dir, new_dentry, &new_page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
300
301
  		if (!new_de)
  			goto out_dir;
3257545e4   Alexey Dobriyan   [PATCH] ufs: swit...
302
  		inode_inc_link_count(old_inode);
b71034e5e   Evgeniy Dushistov   [PATCH] ufs: dire...
303
  		ufs_set_link(new_dir, new_de, new_page, old_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
304
305
  		new_inode->i_ctime = CURRENT_TIME_SEC;
  		if (dir_de)
9a53c3a78   Dave Hansen   [PATCH] r/o bind ...
306
  			drop_nlink(new_inode);
3257545e4   Alexey Dobriyan   [PATCH] ufs: swit...
307
  		inode_dec_link_count(new_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
308
309
310
311
312
313
  	} else {
  		if (dir_de) {
  			err = -EMLINK;
  			if (new_dir->i_nlink >= UFS_LINK_MAX)
  				goto out_dir;
  		}
3257545e4   Alexey Dobriyan   [PATCH] ufs: swit...
314
  		inode_inc_link_count(old_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
315
316
  		err = ufs_add_link(new_dentry, old_inode);
  		if (err) {
3257545e4   Alexey Dobriyan   [PATCH] ufs: swit...
317
  			inode_dec_link_count(old_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
318
319
320
  			goto out_dir;
  		}
  		if (dir_de)
3257545e4   Alexey Dobriyan   [PATCH] ufs: swit...
321
  			inode_inc_link_count(new_dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
322
  	}
b71034e5e   Evgeniy Dushistov   [PATCH] ufs: dire...
323
324
325
326
327
328
  	/*
  	 * 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;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
329

b71034e5e   Evgeniy Dushistov   [PATCH] ufs: dire...
330
  	ufs_delete_entry(old_dir, old_de, old_page);
3257545e4   Alexey Dobriyan   [PATCH] ufs: swit...
331
  	inode_dec_link_count(old_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
332
333
  
  	if (dir_de) {
b71034e5e   Evgeniy Dushistov   [PATCH] ufs: dire...
334
  		ufs_set_link(old_inode, dir_de, dir_page, new_dir);
3257545e4   Alexey Dobriyan   [PATCH] ufs: swit...
335
  		inode_dec_link_count(old_dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
336
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
337
  	return 0;
b71034e5e   Evgeniy Dushistov   [PATCH] ufs: dire...
338

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
339
  out_dir:
b71034e5e   Evgeniy Dushistov   [PATCH] ufs: dire...
340
341
342
343
  	if (dir_de) {
  		kunmap(dir_page);
  		page_cache_release(dir_page);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
344
  out_old:
b71034e5e   Evgeniy Dushistov   [PATCH] ufs: dire...
345
346
  	kunmap(old_page);
  	page_cache_release(old_page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
347
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
348
349
  	return err;
  }
c5ef1c42c   Arjan van de Ven   [PATCH] mark stru...
350
  const struct inode_operations ufs_dir_inode_operations = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
351
352
353
354
355
356
357
358
359
360
  	.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,
  };