Blame view

fs/ufs/namei.c 7.52 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>
e54205988   Mike Frysinger   drop linux/ufs_fs...
32
33
  
  #include "ufs_fs.h"
bcd6d4ecf   Christoph Hellwig   ufs: move non-lay...
34
  #include "ufs.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
  #include "util.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
37
38
39
40
41
42
  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...
43
  	inode_dec_link_count(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
45
46
47
48
49
50
51
52
53
54
  	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);
788257d61   Arnd Bergmann   ufs: remove the BKL
55
  	lock_ufs(dir->i_sb);
080497079   Alexey Dobriyan   ufs: pass qstr in...
56
  	ino = ufs_inode_by_name(dir, &dentry->d_name);
642c937b4   Al Viro   ufs should use d_...
57
  	if (ino)
b55c460da   David Howells   iget: stop UFS fr...
58
  		inode = ufs_iget(dir->i_sb, ino);
788257d61   Arnd Bergmann   ufs: remove the BKL
59
  	unlock_ufs(dir->i_sb);
642c937b4   Al Viro   ufs should use d_...
60
  	return d_splice_alias(inode, dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61
62
63
64
65
66
67
68
69
70
  }
  
  /*
   * 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(). 
   */
4acdaf27e   Al Viro   switch ->create()...
71
  static int ufs_create (struct inode * dir, struct dentry * dentry, umode_t mode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72
73
  		struct nameidata *nd)
  {
abf5d15fd   Evgeniy Dushistov   [PATCH] ufs: easy...
74
75
76
77
78
  	struct inode *inode;
  	int err;
  
  	UFSD("BEGIN
  ");
907f4554e   Christoph Hellwig   dquot: move dquot...
79

abf5d15fd   Evgeniy Dushistov   [PATCH] ufs: easy...
80
81
  	inode = ufs_new_inode(dir, mode);
  	err = PTR_ERR(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
82
83
84
85
86
  	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);
788257d61   Arnd Bergmann   ufs: remove the BKL
87
  		lock_ufs(dir->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
88
  		err = ufs_add_nondir(dentry, inode);
788257d61   Arnd Bergmann   ufs: remove the BKL
89
  		unlock_ufs(dir->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
90
  	}
abf5d15fd   Evgeniy Dushistov   [PATCH] ufs: easy...
91
92
  	UFSD("END: err=%d
  ", err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
93
94
  	return err;
  }
1a67aafb5   Al Viro   switch ->mknod() ...
95
  static int ufs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
96
97
98
99
100
101
  {
  	struct inode *inode;
  	int err;
  
  	if (!old_valid_dev(rdev))
  		return -EINVAL;
907f4554e   Christoph Hellwig   dquot: move dquot...
102

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
103
104
105
106
  	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
107
108
  		ufs_set_inode_dev(inode->i_sb, UFS_I(inode), rdev);
  		mark_inode_dirty(inode);
788257d61   Arnd Bergmann   ufs: remove the BKL
109
  		lock_ufs(dir->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110
  		err = ufs_add_nondir(dentry, inode);
788257d61   Arnd Bergmann   ufs: remove the BKL
111
  		unlock_ufs(dir->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
113
114
115
116
117
118
119
120
121
122
123
124
  	}
  	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...
125
  		goto out_notlocked;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126

788257d61   Arnd Bergmann   ufs: remove the BKL
127
  	lock_ufs(dir->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
128
129
130
131
132
133
134
  	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 */
311b9549e   Dmitry Monakhov   ufs: add ufs spec...
135
  		inode->i_op = &ufs_symlink_inode_operations;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
137
138
139
140
141
142
  		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...
143
  		memcpy(UFS_I(inode)->i_u1.i_symlink, symname, l);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
145
146
147
148
149
  		inode->i_size = l-1;
  	}
  	mark_inode_dirty(inode);
  
  	err = ufs_add_nondir(dentry, inode);
  out:
788257d61   Arnd Bergmann   ufs: remove the BKL
150
  	unlock_ufs(dir->i_sb);
344fe7866   Josh Triplett   [PATCH] ufs: remo...
151
  out_notlocked:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152
153
154
  	return err;
  
  out_fail:
3257545e4   Alexey Dobriyan   [PATCH] ufs: swit...
155
  	inode_dec_link_count(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
156
157
158
159
160
161
162
163
164
  	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;
788257d61   Arnd Bergmann   ufs: remove the BKL
165
  	lock_ufs(dir->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
166
  	if (inode->i_nlink >= UFS_LINK_MAX) {
788257d61   Arnd Bergmann   ufs: remove the BKL
167
  		unlock_ufs(dir->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168
169
170
171
  		return -EMLINK;
  	}
  
  	inode->i_ctime = CURRENT_TIME_SEC;
3257545e4   Alexey Dobriyan   [PATCH] ufs: swit...
172
  	inode_inc_link_count(inode);
7de9c6ee3   Al Viro   new helper: ihold()
173
  	ihold(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
174
175
  
  	error = ufs_add_nondir(dentry, inode);
788257d61   Arnd Bergmann   ufs: remove the BKL
176
  	unlock_ufs(dir->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
177
178
  	return error;
  }
18bb1db3e   Al Viro   switch vfs_mkdir(...
179
  static int ufs_mkdir(struct inode * dir, struct dentry * dentry, umode_t mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
180
181
182
183
184
185
  {
  	struct inode * inode;
  	int err = -EMLINK;
  
  	if (dir->i_nlink >= UFS_LINK_MAX)
  		goto out;
788257d61   Arnd Bergmann   ufs: remove the BKL
186
  	lock_ufs(dir->i_sb);
3257545e4   Alexey Dobriyan   [PATCH] ufs: swit...
187
  	inode_inc_link_count(dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
188
189
190
191
192
193
194
195
  
  	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...
196
  	inode->i_mapping->a_ops = &ufs_aops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
197

3257545e4   Alexey Dobriyan   [PATCH] ufs: swit...
198
  	inode_inc_link_count(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
199
200
201
202
203
204
205
206
  
  	err = ufs_make_empty(inode, dir);
  	if (err)
  		goto out_fail;
  
  	err = ufs_add_link(dentry, inode);
  	if (err)
  		goto out_fail;
788257d61   Arnd Bergmann   ufs: remove the BKL
207
  	unlock_ufs(dir->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208
209
210
211
212
213
  
  	d_instantiate(dentry, inode);
  out:
  	return err;
  
  out_fail:
3257545e4   Alexey Dobriyan   [PATCH] ufs: swit...
214
215
  	inode_dec_link_count(inode);
  	inode_dec_link_count(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
216
217
  	iput (inode);
  out_dir:
3257545e4   Alexey Dobriyan   [PATCH] ufs: swit...
218
  	inode_dec_link_count(dir);
788257d61   Arnd Bergmann   ufs: remove the BKL
219
  	unlock_ufs(dir->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
220
221
  	goto out;
  }
b71034e5e   Evgeniy Dushistov   [PATCH] ufs: dire...
222
  static int ufs_unlink(struct inode *dir, struct dentry *dentry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
223
224
  {
  	struct inode * inode = dentry->d_inode;
b71034e5e   Evgeniy Dushistov   [PATCH] ufs: dire...
225
226
  	struct ufs_dir_entry *de;
  	struct page *page;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
227
  	int err = -ENOENT;
080497079   Alexey Dobriyan   ufs: pass qstr in...
228
  	de = ufs_find_entry(dir, &dentry->d_name, &page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
229
230
  	if (!de)
  		goto out;
b71034e5e   Evgeniy Dushistov   [PATCH] ufs: dire...
231
  	err = ufs_delete_entry(dir, de, page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
232
233
234
235
  	if (err)
  		goto out;
  
  	inode->i_ctime = dir->i_ctime;
3257545e4   Alexey Dobriyan   [PATCH] ufs: swit...
236
  	inode_dec_link_count(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
237
238
  	err = 0;
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
239
240
241
242
243
244
245
  	return err;
  }
  
  static int ufs_rmdir (struct inode * dir, struct dentry *dentry)
  {
  	struct inode * inode = dentry->d_inode;
  	int err= -ENOTEMPTY;
788257d61   Arnd Bergmann   ufs: remove the BKL
246
  	lock_ufs(dir->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247
248
249
250
  	if (ufs_empty_dir (inode)) {
  		err = ufs_unlink(dir, dentry);
  		if (!err) {
  			inode->i_size = 0;
3257545e4   Alexey Dobriyan   [PATCH] ufs: swit...
251
252
  			inode_dec_link_count(inode);
  			inode_dec_link_count(dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
253
254
  		}
  	}
788257d61   Arnd Bergmann   ufs: remove the BKL
255
  	unlock_ufs(dir->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
256
257
  	return err;
  }
b71034e5e   Evgeniy Dushistov   [PATCH] ufs: dire...
258
259
  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
260
261
262
  {
  	struct inode *old_inode = old_dentry->d_inode;
  	struct inode *new_inode = new_dentry->d_inode;
b71034e5e   Evgeniy Dushistov   [PATCH] ufs: dire...
263
264
265
  	struct page *dir_page = NULL;
  	struct ufs_dir_entry * dir_de = NULL;
  	struct page *old_page;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
266
267
  	struct ufs_dir_entry *old_de;
  	int err = -ENOENT;
080497079   Alexey Dobriyan   ufs: pass qstr in...
268
  	old_de = ufs_find_entry(old_dir, &old_dentry->d_name, &old_page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
269
270
271
272
273
  	if (!old_de)
  		goto out;
  
  	if (S_ISDIR(old_inode->i_mode)) {
  		err = -EIO;
b71034e5e   Evgeniy Dushistov   [PATCH] ufs: dire...
274
  		dir_de = ufs_dotdot(old_inode, &dir_page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
275
276
277
278
279
  		if (!dir_de)
  			goto out_old;
  	}
  
  	if (new_inode) {
b71034e5e   Evgeniy Dushistov   [PATCH] ufs: dire...
280
  		struct page *new_page;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
281
282
283
  		struct ufs_dir_entry *new_de;
  
  		err = -ENOTEMPTY;
b71034e5e   Evgeniy Dushistov   [PATCH] ufs: dire...
284
  		if (dir_de && !ufs_empty_dir(new_inode))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
285
  			goto out_dir;
b71034e5e   Evgeniy Dushistov   [PATCH] ufs: dire...
286

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
287
  		err = -ENOENT;
080497079   Alexey Dobriyan   ufs: pass qstr in...
288
  		new_de = ufs_find_entry(new_dir, &new_dentry->d_name, &new_page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
289
290
  		if (!new_de)
  			goto out_dir;
b71034e5e   Evgeniy Dushistov   [PATCH] ufs: dire...
291
  		ufs_set_link(new_dir, new_de, new_page, old_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
292
293
  		new_inode->i_ctime = CURRENT_TIME_SEC;
  		if (dir_de)
9a53c3a78   Dave Hansen   [PATCH] r/o bind ...
294
  			drop_nlink(new_inode);
3257545e4   Alexey Dobriyan   [PATCH] ufs: swit...
295
  		inode_dec_link_count(new_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
296
297
298
299
300
301
  	} else {
  		if (dir_de) {
  			err = -EMLINK;
  			if (new_dir->i_nlink >= UFS_LINK_MAX)
  				goto out_dir;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
302
  		err = ufs_add_link(new_dentry, old_inode);
37750cdda   Al Viro   ufs: i_nlink race...
303
  		if (err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
304
  			goto out_dir;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
305
  		if (dir_de)
3257545e4   Alexey Dobriyan   [PATCH] ufs: swit...
306
  			inode_inc_link_count(new_dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
307
  	}
b71034e5e   Evgeniy Dushistov   [PATCH] ufs: dire...
308
309
310
  	/*
  	 * Like most other Unix systems, set the ctime for inodes on a
   	 * rename.
b71034e5e   Evgeniy Dushistov   [PATCH] ufs: dire...
311
312
  	 */
  	old_inode->i_ctime = CURRENT_TIME_SEC;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
313

b71034e5e   Evgeniy Dushistov   [PATCH] ufs: dire...
314
  	ufs_delete_entry(old_dir, old_de, old_page);
37750cdda   Al Viro   ufs: i_nlink race...
315
  	mark_inode_dirty(old_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
316
317
  
  	if (dir_de) {
b71034e5e   Evgeniy Dushistov   [PATCH] ufs: dire...
318
  		ufs_set_link(old_inode, dir_de, dir_page, new_dir);
3257545e4   Alexey Dobriyan   [PATCH] ufs: swit...
319
  		inode_dec_link_count(old_dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
320
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
321
  	return 0;
b71034e5e   Evgeniy Dushistov   [PATCH] ufs: dire...
322

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
323
  out_dir:
b71034e5e   Evgeniy Dushistov   [PATCH] ufs: dire...
324
325
326
327
  	if (dir_de) {
  		kunmap(dir_page);
  		page_cache_release(dir_page);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
328
  out_old:
b71034e5e   Evgeniy Dushistov   [PATCH] ufs: dire...
329
330
  	kunmap(old_page);
  	page_cache_release(old_page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
331
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
332
333
  	return err;
  }
c5ef1c42c   Arjan van de Ven   [PATCH] mark stru...
334
  const struct inode_operations ufs_dir_inode_operations = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
335
336
337
338
339
340
341
342
343
344
  	.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,
  };