Blame view

fs/jfs/namei.c 37.4 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
  /*
   *   Copyright (C) International Business Machines Corp., 2000-2004
   *   Portions Copyright (C) Christoph Hellwig, 2001-2002
   *
   *   This program is free software;  you can redistribute it and/or modify
   *   it under the terms of the GNU General Public License as published by
63f83c9fc   Dave Kleikamp   JFS: White space ...
7
   *   the Free Software Foundation; either version 2 of the License, or
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8
   *   (at your option) any later version.
63f83c9fc   Dave Kleikamp   JFS: White space ...
9
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10
11
12
13
14
15
   *   This program 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
63f83c9fc   Dave Kleikamp   JFS: White space ...
16
   *   along with this program;  if not, write to the Free Software
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
18
19
20
   *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
   */
  
  #include <linux/fs.h>
2bc334dcc   Nick Piggin   jfs: dont overwri...
21
  #include <linux/namei.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
23
  #include <linux/ctype.h>
  #include <linux/quotaops.h>
d425de704   Christoph Hellwig   jfs: new export ops
24
  #include <linux/exportfs.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
26
27
28
29
30
31
32
33
34
  #include "jfs_incore.h"
  #include "jfs_superblock.h"
  #include "jfs_inode.h"
  #include "jfs_dinode.h"
  #include "jfs_dmap.h"
  #include "jfs_unicode.h"
  #include "jfs_metapage.h"
  #include "jfs_xattr.h"
  #include "jfs_acl.h"
  #include "jfs_debug.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
36
37
  /*
   * forward references
   */
ad28b4ef1   Al Viro   constify dentry_o...
38
  const struct dentry_operations jfs_ci_dentry_operations;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
40
41
42
  
  static s64 commitZeroLink(tid_t, struct inode *);
  
  /*
4f4b401bf   Dave Kleikamp   JFS: allow extend...
43
44
   * NAME:	free_ea_wmap(inode)
   *
63f83c9fc   Dave Kleikamp   JFS: White space ...
45
   * FUNCTION:	free uncommitted extended attributes from working map
4f4b401bf   Dave Kleikamp   JFS: allow extend...
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
   *
   */
  static inline void free_ea_wmap(struct inode *inode)
  {
  	dxd_t *ea = &JFS_IP(inode)->ea;
  
  	if (ea->flag & DXD_EXTENT) {
  		/* free EA pages from cache */
  		invalidate_dxd_metapages(inode, *ea);
  		dbFree(inode, addressDXD(ea), lengthDXD(ea));
  	}
  	ea->flag = 0;
  }
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61
62
63
64
65
   * NAME:	jfs_create(dip, dentry, mode)
   *
   * FUNCTION:	create a regular file in the parent directory <dip>
   *		with name = <from dentry> and mode = <mode>
   *
63f83c9fc   Dave Kleikamp   JFS: White space ...
66
   * PARAMETER:	dip	- parent directory vnode
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
68
69
70
71
72
73
   *		dentry	- dentry of new file
   *		mode	- create mode (rwxrwxrwx).
   *		nd- nd struct
   *
   * RETURN:	Errors from subroutines
   *
   */
4acdaf27e   Al Viro   switch ->create()...
74
  static int jfs_create(struct inode *dip, struct dentry *dentry, umode_t mode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
76
77
78
79
80
81
82
83
84
85
86
  		struct nameidata *nd)
  {
  	int rc = 0;
  	tid_t tid;		/* transaction id */
  	struct inode *ip = NULL;	/* child directory inode */
  	ino_t ino;
  	struct component_name dname;	/* child directory name */
  	struct btstack btstack;
  	struct inode *iplist[2];
  	struct tblock *tblk;
  
  	jfs_info("jfs_create: dip:0x%p name:%s", dip, dentry->d_name.name);
871a29315   Christoph Hellwig   dquot: cleanup dq...
87
  	dquot_initialize(dip);
907f4554e   Christoph Hellwig   dquot: move dquot...
88

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89
90
91
92
93
94
95
96
97
98
99
100
101
  	/*
  	 * search parent directory for entry/freespace
  	 * (dtSearch() returns parent directory page pinned)
  	 */
  	if ((rc = get_UCSname(&dname, dentry)))
  		goto out1;
  
  	/*
  	 * Either iAlloc() or txBegin() may block.  Deadlock can occur if we
  	 * block there while holding dtree page, so we allocate the inode &
  	 * begin the transaction before we search the directory.
  	 */
  	ip = ialloc(dip, mode);
087387f90   Akinobu Mita   [PATCH] JFS: retu...
102
103
  	if (IS_ERR(ip)) {
  		rc = PTR_ERR(ip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
104
105
106
107
  		goto out2;
  	}
  
  	tid = txBegin(dip->i_sb, 0);
82d5b9a7c   Dave Kleikamp   JFS: Add lockdep ...
108
109
  	mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);
  	mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110

4f4b401bf   Dave Kleikamp   JFS: allow extend...
111
112
113
  	rc = jfs_init_acl(tid, ip, dip);
  	if (rc)
  		goto out3;
2a7dba391   Eric Paris   fs/vfs/security: ...
114
  	rc = jfs_init_security(tid, ip, dip, &dentry->d_name);
1d15b10f9   Dave Kleikamp   JFS: Implement jf...
115
116
117
118
  	if (rc) {
  		txAbort(tid, 0);
  		goto out3;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
119
120
  	if ((rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE))) {
  		jfs_err("jfs_create: dtSearch returned %d", rc);
4f4b401bf   Dave Kleikamp   JFS: allow extend...
121
  		txAbort(tid, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
  		goto out3;
  	}
  
  	tblk = tid_to_tblock(tid);
  	tblk->xflag |= COMMIT_CREATE;
  	tblk->ino = ip->i_ino;
  	tblk->u.ixpxd = JFS_IP(ip)->ixpxd;
  
  	iplist[0] = dip;
  	iplist[1] = ip;
  
  	/*
  	 * initialize the child XAD tree root in-line in inode
  	 */
  	xtInitRoot(tid, ip);
  
  	/*
  	 * create entry in parent directory for child directory
  	 * (dtInsert() releases parent directory page)
  	 */
  	ino = ip->i_ino;
  	if ((rc = dtInsert(tid, dip, &dname, &ino, &btstack))) {
  		if (rc == -EIO) {
  			jfs_err("jfs_create: dtInsert returned -EIO");
  			txAbort(tid, 1);	/* Marks Filesystem dirty */
  		} else
  			txAbort(tid, 0);	/* Filesystem full */
  		goto out3;
  	}
  
  	ip->i_op = &jfs_file_inode_operations;
  	ip->i_fop = &jfs_file_operations;
  	ip->i_mapping->a_ops = &jfs_aops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
155
156
157
158
159
160
161
162
163
164
  	mark_inode_dirty(ip);
  
  	dip->i_ctime = dip->i_mtime = CURRENT_TIME;
  
  	mark_inode_dirty(dip);
  
  	rc = txCommit(tid, 2, &iplist[0], 0);
  
        out3:
  	txEnd(tid);
1de87444f   Ingo Molnar   JFS: semaphore to...
165
  	mutex_unlock(&JFS_IP(ip)->commit_mutex);
48ce8b056   Evgeniy Dushistov   JFS: commit_mutex...
166
  	mutex_unlock(&JFS_IP(dip)->commit_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
167
  	if (rc) {
4f4b401bf   Dave Kleikamp   JFS: allow extend...
168
  		free_ea_wmap(ip);
6d6b77f16   Miklos Szeredi   filesystems: add ...
169
  		clear_nlink(ip);
1f3403fa6   Dave Kleikamp   nfsd race fixes: jfs
170
  		unlock_new_inode(ip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171
  		iput(ip);
1f3403fa6   Dave Kleikamp   nfsd race fixes: jfs
172
  	} else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
173
  		d_instantiate(dentry, ip);
1f3403fa6   Dave Kleikamp   nfsd race fixes: jfs
174
175
  		unlock_new_inode(ip);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
176
177
178
  
        out2:
  	free_UCSname(&dname);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179
180
181
182
183
184
185
186
187
188
189
190
191
        out1:
  
  	jfs_info("jfs_create: rc:%d", rc);
  	return rc;
  }
  
  
  /*
   * NAME:	jfs_mkdir(dip, dentry, mode)
   *
   * FUNCTION:	create a child directory in the parent directory <dip>
   *		with name = <from dentry> and mode = <mode>
   *
63f83c9fc   Dave Kleikamp   JFS: White space ...
192
   * PARAMETER:	dip	- parent directory vnode
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
193
194
195
196
197
198
199
200
   *		dentry	- dentry of child directory
   *		mode	- create mode (rwxrwxrwx).
   *
   * RETURN:	Errors from subroutines
   *
   * note:
   * EACCESS: user needs search+write permission on the parent directory
   */
18bb1db3e   Al Viro   switch vfs_mkdir(...
201
  static int jfs_mkdir(struct inode *dip, struct dentry *dentry, umode_t mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
202
203
204
205
206
207
208
209
210
211
212
  {
  	int rc = 0;
  	tid_t tid;		/* transaction id */
  	struct inode *ip = NULL;	/* child directory inode */
  	ino_t ino;
  	struct component_name dname;	/* child directory name */
  	struct btstack btstack;
  	struct inode *iplist[2];
  	struct tblock *tblk;
  
  	jfs_info("jfs_mkdir: dip:0x%p name:%s", dip, dentry->d_name.name);
871a29315   Christoph Hellwig   dquot: cleanup dq...
213
  	dquot_initialize(dip);
907f4554e   Christoph Hellwig   dquot: move dquot...
214

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
  	/* link count overflow on parent directory ? */
  	if (dip->i_nlink == JFS_LINK_MAX) {
  		rc = -EMLINK;
  		goto out1;
  	}
  
  	/*
  	 * search parent directory for entry/freespace
  	 * (dtSearch() returns parent directory page pinned)
  	 */
  	if ((rc = get_UCSname(&dname, dentry)))
  		goto out1;
  
  	/*
  	 * Either iAlloc() or txBegin() may block.  Deadlock can occur if we
  	 * block there while holding dtree page, so we allocate the inode &
  	 * begin the transaction before we search the directory.
  	 */
  	ip = ialloc(dip, S_IFDIR | mode);
087387f90   Akinobu Mita   [PATCH] JFS: retu...
234
235
  	if (IS_ERR(ip)) {
  		rc = PTR_ERR(ip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
236
237
238
239
  		goto out2;
  	}
  
  	tid = txBegin(dip->i_sb, 0);
82d5b9a7c   Dave Kleikamp   JFS: Add lockdep ...
240
241
  	mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);
  	mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
242

4f4b401bf   Dave Kleikamp   JFS: allow extend...
243
244
245
  	rc = jfs_init_acl(tid, ip, dip);
  	if (rc)
  		goto out3;
2a7dba391   Eric Paris   fs/vfs/security: ...
246
  	rc = jfs_init_security(tid, ip, dip, &dentry->d_name);
1d15b10f9   Dave Kleikamp   JFS: Implement jf...
247
248
249
250
  	if (rc) {
  		txAbort(tid, 0);
  		goto out3;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
251
252
  	if ((rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE))) {
  		jfs_err("jfs_mkdir: dtSearch returned %d", rc);
4f4b401bf   Dave Kleikamp   JFS: allow extend...
253
  		txAbort(tid, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
  		goto out3;
  	}
  
  	tblk = tid_to_tblock(tid);
  	tblk->xflag |= COMMIT_CREATE;
  	tblk->ino = ip->i_ino;
  	tblk->u.ixpxd = JFS_IP(ip)->ixpxd;
  
  	iplist[0] = dip;
  	iplist[1] = ip;
  
  	/*
  	 * initialize the child directory in-line in inode
  	 */
  	dtInitRoot(tid, ip, dip->i_ino);
  
  	/*
  	 * create entry in parent directory for child directory
  	 * (dtInsert() releases parent directory page)
  	 */
  	ino = ip->i_ino;
  	if ((rc = dtInsert(tid, dip, &dname, &ino, &btstack))) {
  		if (rc == -EIO) {
  			jfs_err("jfs_mkdir: dtInsert returned -EIO");
  			txAbort(tid, 1);	/* Marks Filesystem dirty */
  		} else
  			txAbort(tid, 0);	/* Filesystem full */
  		goto out3;
  	}
bfe868486   Miklos Szeredi   filesystems: add ...
283
  	set_nlink(ip, 2);	/* for '.' */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
284
285
  	ip->i_op = &jfs_dir_inode_operations;
  	ip->i_fop = &jfs_dir_operations;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
286
287
288
  	mark_inode_dirty(ip);
  
  	/* update parent directory inode */
d8c76e6f4   Dave Hansen   [PATCH] r/o bind ...
289
  	inc_nlink(dip);		/* for '..' from child directory */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
290
291
292
293
294
295
296
  	dip->i_ctime = dip->i_mtime = CURRENT_TIME;
  	mark_inode_dirty(dip);
  
  	rc = txCommit(tid, 2, &iplist[0], 0);
  
        out3:
  	txEnd(tid);
1de87444f   Ingo Molnar   JFS: semaphore to...
297
  	mutex_unlock(&JFS_IP(ip)->commit_mutex);
48ce8b056   Evgeniy Dushistov   JFS: commit_mutex...
298
  	mutex_unlock(&JFS_IP(dip)->commit_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
299
  	if (rc) {
4f4b401bf   Dave Kleikamp   JFS: allow extend...
300
  		free_ea_wmap(ip);
6d6b77f16   Miklos Szeredi   filesystems: add ...
301
  		clear_nlink(ip);
1f3403fa6   Dave Kleikamp   nfsd race fixes: jfs
302
  		unlock_new_inode(ip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
303
  		iput(ip);
1f3403fa6   Dave Kleikamp   nfsd race fixes: jfs
304
  	} else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
305
  		d_instantiate(dentry, ip);
1f3403fa6   Dave Kleikamp   nfsd race fixes: jfs
306
307
  		unlock_new_inode(ip);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
308
309
310
  
        out2:
  	free_UCSname(&dname);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
311
312
313
314
315
316
317
318
319
320
321
322
  
        out1:
  
  	jfs_info("jfs_mkdir: rc:%d", rc);
  	return rc;
  }
  
  /*
   * NAME:	jfs_rmdir(dip, dentry)
   *
   * FUNCTION:	remove a link to child directory
   *
63f83c9fc   Dave Kleikamp   JFS: White space ...
323
   * PARAMETER:	dip	- parent inode
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
324
325
326
   *		dentry	- child directory dentry
   *
   * RETURN:	-EINVAL	- if name is . or ..
f720e3ba5   Dave Kleikamp   JFS: Whitespace c...
327
   *		-EINVAL - if . or .. exist but are invalid.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
328
329
330
   *		errors from subroutines
   *
   * note:
63f83c9fc   Dave Kleikamp   JFS: White space ...
331
332
333
334
   * if other threads have the directory open when the last link
   * is removed, the "." and ".." entries, if present, are removed before
   * rmdir() returns and no new entries may be created in the directory,
   * but the directory is not removed until the last reference to
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
   * the directory is released (cf.unlink() of regular file).
   */
  static int jfs_rmdir(struct inode *dip, struct dentry *dentry)
  {
  	int rc;
  	tid_t tid;		/* transaction id */
  	struct inode *ip = dentry->d_inode;
  	ino_t ino;
  	struct component_name dname;
  	struct inode *iplist[2];
  	struct tblock *tblk;
  
  	jfs_info("jfs_rmdir: dip:0x%p name:%s", dip, dentry->d_name.name);
  
  	/* Init inode for quota operations. */
871a29315   Christoph Hellwig   dquot: cleanup dq...
350
351
  	dquot_initialize(dip);
  	dquot_initialize(ip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
352
353
354
355
356
357
358
359
360
361
362
363
  
  	/* directory must be empty to be removed */
  	if (!dtEmpty(ip)) {
  		rc = -ENOTEMPTY;
  		goto out;
  	}
  
  	if ((rc = get_UCSname(&dname, dentry))) {
  		goto out;
  	}
  
  	tid = txBegin(dip->i_sb, 0);
82d5b9a7c   Dave Kleikamp   JFS: Add lockdep ...
364
365
  	mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);
  	mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
  
  	iplist[0] = dip;
  	iplist[1] = ip;
  
  	tblk = tid_to_tblock(tid);
  	tblk->xflag |= COMMIT_DELETE;
  	tblk->u.ip = ip;
  
  	/*
  	 * delete the entry of target directory from parent directory
  	 */
  	ino = ip->i_ino;
  	if ((rc = dtDelete(tid, dip, &dname, &ino, JFS_REMOVE))) {
  		jfs_err("jfs_rmdir: dtDelete returned %d", rc);
  		if (rc == -EIO)
  			txAbort(tid, 1);
  		txEnd(tid);
1de87444f   Ingo Molnar   JFS: semaphore to...
383
  		mutex_unlock(&JFS_IP(ip)->commit_mutex);
48ce8b056   Evgeniy Dushistov   JFS: commit_mutex...
384
  		mutex_unlock(&JFS_IP(dip)->commit_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
385
386
387
388
389
390
391
  
  		goto out2;
  	}
  
  	/* update parent directory's link count corresponding
  	 * to ".." entry of the target directory deleted
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
392
  	dip->i_ctime = dip->i_mtime = CURRENT_TIME;
9a53c3a78   Dave Hansen   [PATCH] r/o bind ...
393
  	inode_dec_link_count(dip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
  
  	/*
  	 * OS/2 could have created EA and/or ACL
  	 */
  	/* free EA from both persistent and working map */
  	if (JFS_IP(ip)->ea.flag & DXD_EXTENT) {
  		/* free EA pages */
  		txEA(tid, ip, &JFS_IP(ip)->ea, NULL);
  	}
  	JFS_IP(ip)->ea.flag = 0;
  
  	/* free ACL from both persistent and working map */
  	if (JFS_IP(ip)->acl.flag & DXD_EXTENT) {
  		/* free ACL pages */
  		txEA(tid, ip, &JFS_IP(ip)->acl, NULL);
  	}
  	JFS_IP(ip)->acl.flag = 0;
  
  	/* mark the target directory as deleted */
ce71ec368   Dave Hansen   [PATCH] r/o bind ...
413
  	clear_nlink(ip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
414
415
416
417
418
  	mark_inode_dirty(ip);
  
  	rc = txCommit(tid, 2, &iplist[0], 0);
  
  	txEnd(tid);
1de87444f   Ingo Molnar   JFS: semaphore to...
419
  	mutex_unlock(&JFS_IP(ip)->commit_mutex);
48ce8b056   Evgeniy Dushistov   JFS: commit_mutex...
420
  	mutex_unlock(&JFS_IP(dip)->commit_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
  
  	/*
  	 * Truncating the directory index table is not guaranteed.  It
  	 * may need to be done iteratively
  	 */
  	if (test_cflag(COMMIT_Stale, dip)) {
  		if (dip->i_size > 1)
  			jfs_truncate_nolock(dip, 0);
  
  		clear_cflag(COMMIT_Stale, dip);
  	}
  
        out2:
  	free_UCSname(&dname);
  
        out:
  	jfs_info("jfs_rmdir: rc:%d", rc);
  	return rc;
  }
  
  /*
   * NAME:	jfs_unlink(dip, dentry)
   *
63f83c9fc   Dave Kleikamp   JFS: White space ...
444
   * FUNCTION:	remove a link to object <vp> named by <name>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
445
446
   *		from parent directory <dvp>
   *
63f83c9fc   Dave Kleikamp   JFS: White space ...
447
448
   * PARAMETER:	dip	- inode of parent directory
   *		dentry	- dentry of object to be removed
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
   *
   * RETURN:	errors from subroutines
   *
   * note:
   * temporary file: if one or more processes have the file open
   * when the last link is removed, the link will be removed before
   * unlink() returns, but the removal of the file contents will be
   * postponed until all references to the files are closed.
   *
   * JFS does NOT support unlink() on directories.
   *
   */
  static int jfs_unlink(struct inode *dip, struct dentry *dentry)
  {
  	int rc;
  	tid_t tid;		/* transaction id */
  	struct inode *ip = dentry->d_inode;
  	ino_t ino;
  	struct component_name dname;	/* object name */
  	struct inode *iplist[2];
  	struct tblock *tblk;
  	s64 new_size = 0;
  	int commit_flag;
  
  	jfs_info("jfs_unlink: dip:0x%p name:%s", dip, dentry->d_name.name);
  
  	/* Init inode for quota operations. */
871a29315   Christoph Hellwig   dquot: cleanup dq...
476
477
  	dquot_initialize(dip);
  	dquot_initialize(ip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
478
479
480
  
  	if ((rc = get_UCSname(&dname, dentry)))
  		goto out;
82d5b9a7c   Dave Kleikamp   JFS: Add lockdep ...
481
  	IWRITE_LOCK(ip, RDWRLOCK_NORMAL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
482
483
  
  	tid = txBegin(dip->i_sb, 0);
82d5b9a7c   Dave Kleikamp   JFS: Add lockdep ...
484
485
  	mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);
  	mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
486
487
488
489
490
491
492
493
494
495
496
497
498
  
  	iplist[0] = dip;
  	iplist[1] = ip;
  
  	/*
  	 * delete the entry of target file from parent directory
  	 */
  	ino = ip->i_ino;
  	if ((rc = dtDelete(tid, dip, &dname, &ino, JFS_REMOVE))) {
  		jfs_err("jfs_unlink: dtDelete returned %d", rc);
  		if (rc == -EIO)
  			txAbort(tid, 1);	/* Marks FS Dirty */
  		txEnd(tid);
1de87444f   Ingo Molnar   JFS: semaphore to...
499
  		mutex_unlock(&JFS_IP(ip)->commit_mutex);
48ce8b056   Evgeniy Dushistov   JFS: commit_mutex...
500
  		mutex_unlock(&JFS_IP(dip)->commit_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
501
502
503
504
505
506
507
508
509
510
  		IWRITE_UNLOCK(ip);
  		goto out1;
  	}
  
  	ASSERT(ip->i_nlink);
  
  	ip->i_ctime = dip->i_ctime = dip->i_mtime = CURRENT_TIME;
  	mark_inode_dirty(dip);
  
  	/* update target's inode */
9a53c3a78   Dave Hansen   [PATCH] r/o bind ...
511
  	inode_dec_link_count(ip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
512
513
  
  	/*
f720e3ba5   Dave Kleikamp   JFS: Whitespace c...
514
  	 *	commit zero link count object
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
515
516
517
518
519
520
521
  	 */
  	if (ip->i_nlink == 0) {
  		assert(!test_cflag(COMMIT_Nolink, ip));
  		/* free block resources */
  		if ((new_size = commitZeroLink(tid, ip)) < 0) {
  			txAbort(tid, 1);	/* Marks FS Dirty */
  			txEnd(tid);
1de87444f   Ingo Molnar   JFS: semaphore to...
522
  			mutex_unlock(&JFS_IP(ip)->commit_mutex);
48ce8b056   Evgeniy Dushistov   JFS: commit_mutex...
523
  			mutex_unlock(&JFS_IP(dip)->commit_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
  			IWRITE_UNLOCK(ip);
  			rc = new_size;
  			goto out1;
  		}
  		tblk = tid_to_tblock(tid);
  		tblk->xflag |= COMMIT_DELETE;
  		tblk->u.ip = ip;
  	}
  
  	/*
  	 * Incomplete truncate of file data can
  	 * result in timing problems unless we synchronously commit the
  	 * transaction.
  	 */
  	if (new_size)
  		commit_flag = COMMIT_SYNC;
  	else
  		commit_flag = 0;
  
  	/*
  	 * If xtTruncate was incomplete, commit synchronously to avoid
  	 * timing complications
  	 */
  	rc = txCommit(tid, 2, &iplist[0], commit_flag);
  
  	txEnd(tid);
1de87444f   Ingo Molnar   JFS: semaphore to...
550
  	mutex_unlock(&JFS_IP(ip)->commit_mutex);
48ce8b056   Evgeniy Dushistov   JFS: commit_mutex...
551
  	mutex_unlock(&JFS_IP(dip)->commit_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
552
553
554
  
  	while (new_size && (rc == 0)) {
  		tid = txBegin(dip->i_sb, 0);
1de87444f   Ingo Molnar   JFS: semaphore to...
555
  		mutex_lock(&JFS_IP(ip)->commit_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
556
557
558
559
560
561
562
  		new_size = xtTruncate_pmap(tid, ip, new_size);
  		if (new_size < 0) {
  			txAbort(tid, 1);	/* Marks FS Dirty */
  			rc = new_size;
  		} else
  			rc = txCommit(tid, 2, &iplist[0], COMMIT_SYNC);
  		txEnd(tid);
1de87444f   Ingo Molnar   JFS: semaphore to...
563
  		mutex_unlock(&JFS_IP(ip)->commit_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
  	}
  
  	if (ip->i_nlink == 0)
  		set_cflag(COMMIT_Nolink, ip);
  
  	IWRITE_UNLOCK(ip);
  
  	/*
  	 * Truncating the directory index table is not guaranteed.  It
  	 * may need to be done iteratively
  	 */
  	if (test_cflag(COMMIT_Stale, dip)) {
  		if (dip->i_size > 1)
  			jfs_truncate_nolock(dip, 0);
  
  		clear_cflag(COMMIT_Stale, dip);
  	}
  
        out1:
  	free_UCSname(&dname);
        out:
  	jfs_info("jfs_unlink: rc:%d", rc);
  	return rc;
  }
  
  /*
   * NAME:	commitZeroLink()
   *
f720e3ba5   Dave Kleikamp   JFS: Whitespace c...
592
   * FUNCTION:	for non-directory, called by jfs_remove(),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
593
   *		truncate a regular file, directory or symbolic
63f83c9fc   Dave Kleikamp   JFS: White space ...
594
   *		link to zero length. return 0 if type is not
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
595
596
597
598
599
600
601
602
603
   *		one of these.
   *
   *		if the file is currently associated with a VM segment
   *		only permanent disk and inode map resources are freed,
   *		and neither the inode nor indirect blocks are modified
   *		so that the resources can be later freed in the work
   *		map by ctrunc1.
   *		if there is no VM segment on entry, the resources are
   *		freed in both work and permanent map.
63f83c9fc   Dave Kleikamp   JFS: White space ...
604
   *		(? for temporary file - memory object is cached even
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
   *		after no reference:
   *		reference count > 0 -   )
   *
   * PARAMETERS:	cd	- pointer to commit data structure.
   *			  current inode is the one to truncate.
   *
   * RETURN:	Errors from subroutines
   */
  static s64 commitZeroLink(tid_t tid, struct inode *ip)
  {
  	int filetype;
  	struct tblock *tblk;
  
  	jfs_info("commitZeroLink: tid = %d, ip = 0x%p", tid, ip);
  
  	filetype = ip->i_mode & S_IFMT;
  	switch (filetype) {
  	case S_IFREG:
  		break;
  	case S_IFLNK:
  		/* fast symbolic link */
  		if (ip->i_size < IDATASIZE) {
  			ip->i_size = 0;
  			return 0;
  		}
  		break;
  	default:
  		assert(filetype != S_IFDIR);
  		return 0;
  	}
  
  	set_cflag(COMMIT_Freewmap, ip);
  
  	/* mark transaction of block map update type */
  	tblk = tid_to_tblock(tid);
  	tblk->xflag |= COMMIT_PMAP;
  
  	/*
  	 * free EA
  	 */
  	if (JFS_IP(ip)->ea.flag & DXD_EXTENT)
  		/* acquire maplock on EA to be freed from block map */
  		txEA(tid, ip, &JFS_IP(ip)->ea, NULL);
  
  	/*
  	 * free ACL
  	 */
  	if (JFS_IP(ip)->acl.flag & DXD_EXTENT)
  		/* acquire maplock on EA to be freed from block map */
  		txEA(tid, ip, &JFS_IP(ip)->acl, NULL);
  
  	/*
  	 * free xtree/data (truncate to zero length):
63f83c9fc   Dave Kleikamp   JFS: White space ...
658
  	 * free xtree/data pages from cache if COMMIT_PWMAP,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
659
660
661
662
663
664
665
666
667
668
669
  	 * free xtree/data blocks from persistent block map, and
  	 * free xtree/data blocks from working block map if COMMIT_PWMAP;
  	 */
  	if (ip->i_size)
  		return xtTruncate_pmap(tid, ip, 0);
  
  	return 0;
  }
  
  
  /*
1868f4aa5   Dave Kleikamp   JFS: fix sparse w...
670
   * NAME:	jfs_free_zero_link()
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
671
   *
f720e3ba5   Dave Kleikamp   JFS: Whitespace c...
672
   * FUNCTION:	for non-directory, called by iClose(),
63f83c9fc   Dave Kleikamp   JFS: White space ...
673
   *		free resources of a file from cache and WORKING map
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
674
675
676
677
   *		for a file previously committed with zero link count
   *		while associated with a pager object,
   *
   * PARAMETER:	ip	- pointer to inode of file.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
678
   */
1868f4aa5   Dave Kleikamp   JFS: fix sparse w...
679
  void jfs_free_zero_link(struct inode *ip)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
680
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
681
  	int type;
1868f4aa5   Dave Kleikamp   JFS: fix sparse w...
682
  	jfs_info("jfs_free_zero_link: ip = 0x%p", ip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
683
684
685
686
687
688
689
690
691
692
693
694
  
  	/* return if not reg or symbolic link or if size is
  	 * already ok.
  	 */
  	type = ip->i_mode & S_IFMT;
  
  	switch (type) {
  	case S_IFREG:
  		break;
  	case S_IFLNK:
  		/* if its contained in inode nothing to do */
  		if (ip->i_size < IDATASIZE)
1868f4aa5   Dave Kleikamp   JFS: fix sparse w...
695
  			return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
696
697
  		break;
  	default:
1868f4aa5   Dave Kleikamp   JFS: fix sparse w...
698
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
  	}
  
  	/*
  	 * free EA
  	 */
  	if (JFS_IP(ip)->ea.flag & DXD_EXTENT) {
  		s64 xaddr = addressDXD(&JFS_IP(ip)->ea);
  		int xlen = lengthDXD(&JFS_IP(ip)->ea);
  		struct maplock maplock;	/* maplock for COMMIT_WMAP */
  		struct pxd_lock *pxdlock;	/* maplock for COMMIT_WMAP */
  
  		/* free EA pages from cache */
  		invalidate_dxd_metapages(ip, JFS_IP(ip)->ea);
  
  		/* free EA extent from working block map */
  		maplock.index = 1;
  		pxdlock = (struct pxd_lock *) & maplock;
  		pxdlock->flag = mlckFREEPXD;
  		PXDaddress(&pxdlock->pxd, xaddr);
  		PXDlength(&pxdlock->pxd, xlen);
  		txFreeMap(ip, pxdlock, NULL, COMMIT_WMAP);
  	}
  
  	/*
  	 * free ACL
  	 */
  	if (JFS_IP(ip)->acl.flag & DXD_EXTENT) {
  		s64 xaddr = addressDXD(&JFS_IP(ip)->acl);
  		int xlen = lengthDXD(&JFS_IP(ip)->acl);
  		struct maplock maplock;	/* maplock for COMMIT_WMAP */
  		struct pxd_lock *pxdlock;	/* maplock for COMMIT_WMAP */
  
  		invalidate_dxd_metapages(ip, JFS_IP(ip)->acl);
  
  		/* free ACL extent from working block map */
  		maplock.index = 1;
  		pxdlock = (struct pxd_lock *) & maplock;
  		pxdlock->flag = mlckFREEPXD;
  		PXDaddress(&pxdlock->pxd, xaddr);
  		PXDlength(&pxdlock->pxd, xlen);
  		txFreeMap(ip, pxdlock, NULL, COMMIT_WMAP);
  	}
  
  	/*
  	 * free xtree/data (truncate to zero length):
  	 * free xtree/data pages from cache, and
  	 * free xtree/data blocks from working block map;
  	 */
  	if (ip->i_size)
1868f4aa5   Dave Kleikamp   JFS: fix sparse w...
748
  		xtTruncate(0, ip, 0, COMMIT_WMAP);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
749
750
751
752
753
754
755
756
  }
  
  /*
   * NAME:	jfs_link(vp, dvp, name, crp)
   *
   * FUNCTION:	create a link to <vp> by the name = <name>
   *		in the parent directory <dvp>
   *
63f83c9fc   Dave Kleikamp   JFS: White space ...
757
   * PARAMETER:	vp	- target object
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
   *		dvp	- parent directory of new link
   *		name	- name of new link to target object
   *		crp	- credential
   *
   * RETURN:	Errors from subroutines
   *
   * note:
   * JFS does NOT support link() on directories (to prevent circular
   * path in the directory hierarchy);
   * EPERM: the target object is a directory, and either the caller
   * does not have appropriate privileges or the implementation prohibits
   * using link() on directories [XPG4.2].
   *
   * JFS does NOT support links between file systems:
   * EXDEV: target object and new link are on different file systems and
   * implementation does not support links between file systems [XPG4.2].
   */
  static int jfs_link(struct dentry *old_dentry,
  	     struct inode *dir, struct dentry *dentry)
  {
  	int rc;
  	tid_t tid;
  	struct inode *ip = old_dentry->d_inode;
  	ino_t ino;
  	struct component_name dname;
  	struct btstack btstack;
  	struct inode *iplist[2];
  
  	jfs_info("jfs_link: %s %s", old_dentry->d_name.name,
  		 dentry->d_name.name);
  
  	if (ip->i_nlink == JFS_LINK_MAX)
  		return -EMLINK;
871a29315   Christoph Hellwig   dquot: cleanup dq...
791
  	dquot_initialize(dir);
907f4554e   Christoph Hellwig   dquot: move dquot...
792

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
793
  	tid = txBegin(ip->i_sb, 0);
82d5b9a7c   Dave Kleikamp   JFS: Add lockdep ...
794
795
  	mutex_lock_nested(&JFS_IP(dir)->commit_mutex, COMMIT_MUTEX_PARENT);
  	mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
  
  	/*
  	 * scan parent directory for entry/freespace
  	 */
  	if ((rc = get_UCSname(&dname, dentry)))
  		goto out;
  
  	if ((rc = dtSearch(dir, &dname, &ino, &btstack, JFS_CREATE)))
  		goto free_dname;
  
  	/*
  	 * create entry for new link in parent directory
  	 */
  	ino = ip->i_ino;
  	if ((rc = dtInsert(tid, dir, &dname, &ino, &btstack)))
  		goto free_dname;
  
  	/* update object inode */
d8c76e6f4   Dave Hansen   [PATCH] r/o bind ...
814
  	inc_nlink(ip);		/* for new link */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
815
  	ip->i_ctime = CURRENT_TIME;
988a6490a   Dave Kleikamp   JFS: set i_ctime ...
816
  	dir->i_ctime = dir->i_mtime = CURRENT_TIME;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
817
  	mark_inode_dirty(dir);
7de9c6ee3   Al Viro   new helper: ihold()
818
  	ihold(ip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
819
820
821
822
823
824
  
  	iplist[0] = ip;
  	iplist[1] = dir;
  	rc = txCommit(tid, 2, &iplist[0], 0);
  
  	if (rc) {
6d6b77f16   Miklos Szeredi   filesystems: add ...
825
  		drop_nlink(ip); /* never instantiated */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
826
827
828
829
830
831
832
833
834
  		iput(ip);
  	} else
  		d_instantiate(dentry, ip);
  
        free_dname:
  	free_UCSname(&dname);
  
        out:
  	txEnd(tid);
1de87444f   Ingo Molnar   JFS: semaphore to...
835
  	mutex_unlock(&JFS_IP(ip)->commit_mutex);
48ce8b056   Evgeniy Dushistov   JFS: commit_mutex...
836
  	mutex_unlock(&JFS_IP(dir)->commit_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
837
838
839
840
841
842
843
844
845
  
  	jfs_info("jfs_link: rc:%d", rc);
  	return rc;
  }
  
  /*
   * NAME:	jfs_symlink(dip, dentry, name)
   *
   * FUNCTION:	creates a symbolic link to <symlink> by name <name>
f720e3ba5   Dave Kleikamp   JFS: Whitespace c...
846
   *			in directory <dip>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
847
   *
f720e3ba5   Dave Kleikamp   JFS: Whitespace c...
848
849
850
851
   * PARAMETER:	dip	- parent directory vnode
   *		dentry	- dentry of symbolic link
   *		name	- the path name of the existing object
   *			  that will be the source of the link
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
   *
   * RETURN:	errors from subroutines
   *
   * note:
   * ENAMETOOLONG: pathname resolution of a symbolic link produced
   * an intermediate result whose length exceeds PATH_MAX [XPG4.2]
  */
  
  static int jfs_symlink(struct inode *dip, struct dentry *dentry,
  		const char *name)
  {
  	int rc;
  	tid_t tid;
  	ino_t ino = 0;
  	struct component_name dname;
  	int ssize;		/* source pathname size */
  	struct btstack btstack;
  	struct inode *ip = dentry->d_inode;
  	unchar *i_fastsymlink;
  	s64 xlen = 0;
  	int bmask = 0, xsize;
3c2c22628   Dave Kleikamp   jfs: clean up som...
873
  	s64 xaddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
874
875
876
877
878
879
880
  	struct metapage *mp;
  	struct super_block *sb;
  	struct tblock *tblk;
  
  	struct inode *iplist[2];
  
  	jfs_info("jfs_symlink: dip:0x%p name:%s", dip, name);
871a29315   Christoph Hellwig   dquot: cleanup dq...
881
  	dquot_initialize(dip);
907f4554e   Christoph Hellwig   dquot: move dquot...
882

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
  	ssize = strlen(name) + 1;
  
  	/*
  	 * search parent directory for entry/freespace
  	 * (dtSearch() returns parent directory page pinned)
  	 */
  
  	if ((rc = get_UCSname(&dname, dentry)))
  		goto out1;
  
  	/*
  	 * allocate on-disk/in-memory inode for symbolic link:
  	 * (iAlloc() returns new, locked inode)
  	 */
  	ip = ialloc(dip, S_IFLNK | 0777);
087387f90   Akinobu Mita   [PATCH] JFS: retu...
898
899
  	if (IS_ERR(ip)) {
  		rc = PTR_ERR(ip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
900
901
902
903
  		goto out2;
  	}
  
  	tid = txBegin(dip->i_sb, 0);
82d5b9a7c   Dave Kleikamp   JFS: Add lockdep ...
904
905
  	mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);
  	mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
906

2a7dba391   Eric Paris   fs/vfs/security: ...
907
  	rc = jfs_init_security(tid, ip, dip, &dentry->d_name);
1d15b10f9   Dave Kleikamp   JFS: Implement jf...
908
909
  	if (rc)
  		goto out3;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
910
911
912
913
914
915
  	tblk = tid_to_tblock(tid);
  	tblk->xflag |= COMMIT_CREATE;
  	tblk->ino = ip->i_ino;
  	tblk->u.ixpxd = JFS_IP(ip)->ixpxd;
  
  	/* fix symlink access permission
63f83c9fc   Dave Kleikamp   JFS: White space ...
916
  	 * (dir_create() ANDs in the u.u_cmask,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
917
918
919
920
921
922
923
924
925
926
927
928
929
930
  	 * but symlinks really need to be 777 access)
  	 */
  	ip->i_mode |= 0777;
  
  	/*
  	 * write symbolic link target path name
  	 */
  	xtInitRoot(tid, ip);
  
  	/*
  	 * write source path name inline in on-disk inode (fast symbolic link)
  	 */
  
  	if (ssize <= IDATASIZE) {
c7f2e1f0a   Dmitry Monakhov   jfs: add jfs spec...
931
  		ip->i_op = &jfs_fast_symlink_inode_operations;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
  
  		i_fastsymlink = JFS_IP(ip)->i_inline;
  		memcpy(i_fastsymlink, name, ssize);
  		ip->i_size = ssize - 1;
  
  		/*
  		 * if symlink is > 128 bytes, we don't have the space to
  		 * store inline extended attributes
  		 */
  		if (ssize > sizeof (JFS_IP(ip)->i_inline))
  			JFS_IP(ip)->mode2 &= ~INLINEEA;
  
  		jfs_info("jfs_symlink: fast symlink added  ssize:%d name:%s ",
  			 ssize, name);
  	}
  	/*
  	 * write source path name in a single extent
  	 */
  	else {
  		jfs_info("jfs_symlink: allocate extent ip:0x%p", ip);
c7f2e1f0a   Dmitry Monakhov   jfs: add jfs spec...
952
  		ip->i_op = &jfs_symlink_inode_operations;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
953
954
955
  		ip->i_mapping->a_ops = &jfs_aops;
  
  		/*
63f83c9fc   Dave Kleikamp   JFS: White space ...
956
  		 * even though the data of symlink object (source
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
957
958
959
960
961
962
963
964
965
966
  		 * path name) is treated as non-journaled user data,
  		 * it is read/written thru buffer cache for performance.
  		 */
  		sb = ip->i_sb;
  		bmask = JFS_SBI(sb)->bsize - 1;
  		xsize = (ssize + bmask) & ~bmask;
  		xaddr = 0;
  		xlen = xsize >> JFS_SBI(sb)->l2bsize;
  		if ((rc = xtInsert(tid, ip, 0, 0, xlen, &xaddr, 0))) {
  			txAbort(tid, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
967
968
  			goto out3;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
  		ip->i_size = ssize - 1;
  		while (ssize) {
  			/* This is kind of silly since PATH_MAX == 4K */
  			int copy_size = min(ssize, PSIZE);
  
  			mp = get_metapage(ip, xaddr, PSIZE, 1);
  
  			if (mp == NULL) {
  				xtTruncate(tid, ip, 0, COMMIT_PWMAP);
  				rc = -EIO;
  				txAbort(tid, 0);
  				goto out3;
  			}
  			memcpy(mp->data, name, copy_size);
  			flush_metapage(mp);
  			ssize -= copy_size;
  			name += copy_size;
  			xaddr += JFS_SBI(sb)->nbperpage;
  		}
  	}
  
  	/*
  	 * create entry for symbolic link in parent directory
  	 */
  	rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE);
  	if (rc == 0) {
  		ino = ip->i_ino;
  		rc = dtInsert(tid, dip, &dname, &ino, &btstack);
  	}
  	if (rc) {
  		if (xlen)
  			xtTruncate(tid, ip, 0, COMMIT_PWMAP);
  		txAbort(tid, 0);
  		/* discard new inode */
  		goto out3;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1005
  	mark_inode_dirty(ip);
988a6490a   Dave Kleikamp   JFS: set i_ctime ...
1006
1007
  	dip->i_ctime = dip->i_mtime = CURRENT_TIME;
  	mark_inode_dirty(dip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
  	/*
  	 * commit update of parent directory and link object
  	 */
  
  	iplist[0] = dip;
  	iplist[1] = ip;
  	rc = txCommit(tid, 2, &iplist[0], 0);
  
        out3:
  	txEnd(tid);
1de87444f   Ingo Molnar   JFS: semaphore to...
1018
  	mutex_unlock(&JFS_IP(ip)->commit_mutex);
48ce8b056   Evgeniy Dushistov   JFS: commit_mutex...
1019
  	mutex_unlock(&JFS_IP(dip)->commit_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1020
  	if (rc) {
4f4b401bf   Dave Kleikamp   JFS: allow extend...
1021
  		free_ea_wmap(ip);
6d6b77f16   Miklos Szeredi   filesystems: add ...
1022
  		clear_nlink(ip);
1f3403fa6   Dave Kleikamp   nfsd race fixes: jfs
1023
  		unlock_new_inode(ip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1024
  		iput(ip);
1f3403fa6   Dave Kleikamp   nfsd race fixes: jfs
1025
  	} else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1026
  		d_instantiate(dentry, ip);
1f3403fa6   Dave Kleikamp   nfsd race fixes: jfs
1027
1028
  		unlock_new_inode(ip);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1029
1030
1031
  
        out2:
  	free_UCSname(&dname);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1032
1033
1034
1035
1036
1037
1038
        out1:
  	jfs_info("jfs_symlink: rc:%d", rc);
  	return rc;
  }
  
  
  /*
f720e3ba5   Dave Kleikamp   JFS: Whitespace c...
1039
   * NAME:	jfs_rename
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1040
   *
f720e3ba5   Dave Kleikamp   JFS: Whitespace c...
1041
   * FUNCTION:	rename a file or directory
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
   */
  static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
  	       struct inode *new_dir, struct dentry *new_dentry)
  {
  	struct btstack btstack;
  	ino_t ino;
  	struct component_name new_dname;
  	struct inode *new_ip;
  	struct component_name old_dname;
  	struct inode *old_ip;
  	int rc;
  	tid_t tid;
  	struct tlock *tlck;
  	struct dt_lock *dtlck;
  	struct lv *lv;
  	int ipcount;
  	struct inode *iplist[4];
  	struct tblock *tblk;
  	s64 new_size = 0;
  	int commit_flag;
  
  
  	jfs_info("jfs_rename: %s %s", old_dentry->d_name.name,
  		 new_dentry->d_name.name);
871a29315   Christoph Hellwig   dquot: cleanup dq...
1066
1067
  	dquot_initialize(old_dir);
  	dquot_initialize(new_dir);
907f4554e   Christoph Hellwig   dquot: move dquot...
1068

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
  	old_ip = old_dentry->d_inode;
  	new_ip = new_dentry->d_inode;
  
  	if ((rc = get_UCSname(&old_dname, old_dentry)))
  		goto out1;
  
  	if ((rc = get_UCSname(&new_dname, new_dentry)))
  		goto out2;
  
  	/*
  	 * Make sure source inode number is what we think it is
  	 */
  	rc = dtSearch(old_dir, &old_dname, &ino, &btstack, JFS_LOOKUP);
  	if (rc || (ino != old_ip->i_ino)) {
  		rc = -ENOENT;
  		goto out3;
  	}
  
  	/*
  	 * Make sure dest inode number (if any) is what we think it is
  	 */
  	rc = dtSearch(new_dir, &new_dname, &ino, &btstack, JFS_LOOKUP);
09aaa749f   Joe Perches   JFS: Remove defco...
1091
  	if (!rc) {
da8a41d19   Dave Kleikamp   JFS: FIx one more...
1092
  		if ((!new_ip) || (ino != new_ip->i_ino)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
  			rc = -ESTALE;
  			goto out3;
  		}
  	} else if (rc != -ENOENT)
  		goto out3;
  	else if (new_ip) {
  		/* no entry exists, but one was expected */
  		rc = -ESTALE;
  		goto out3;
  	}
  
  	if (S_ISDIR(old_ip->i_mode)) {
  		if (new_ip) {
  			if (!dtEmpty(new_ip)) {
  				rc = -ENOTEMPTY;
  				goto out3;
  			}
  		} else if ((new_dir != old_dir) &&
  			   (new_dir->i_nlink == JFS_LINK_MAX)) {
  			rc = -EMLINK;
  			goto out3;
  		}
  	} else if (new_ip) {
82d5b9a7c   Dave Kleikamp   JFS: Add lockdep ...
1116
  		IWRITE_LOCK(new_ip, RDWRLOCK_NORMAL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1117
  		/* Init inode for quota operations. */
871a29315   Christoph Hellwig   dquot: cleanup dq...
1118
  		dquot_initialize(new_ip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1119
1120
1121
1122
1123
1124
  	}
  
  	/*
  	 * The real work starts here
  	 */
  	tid = txBegin(new_dir->i_sb, 0);
82d5b9a7c   Dave Kleikamp   JFS: Add lockdep ...
1125
1126
1127
1128
1129
1130
1131
1132
  	/*
  	 * How do we know the locking is safe from deadlocks?
  	 * The vfs does the hard part for us.  Any time we are taking nested
  	 * commit_mutexes, the vfs already has i_mutex held on the parent.
  	 * Here, the vfs has already taken i_mutex on both old_dir and new_dir.
  	 */
  	mutex_lock_nested(&JFS_IP(new_dir)->commit_mutex, COMMIT_MUTEX_PARENT);
  	mutex_lock_nested(&JFS_IP(old_ip)->commit_mutex, COMMIT_MUTEX_CHILD);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1133
  	if (old_dir != new_dir)
82d5b9a7c   Dave Kleikamp   JFS: Add lockdep ...
1134
1135
  		mutex_lock_nested(&JFS_IP(old_dir)->commit_mutex,
  				  COMMIT_MUTEX_SECOND_PARENT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1136
1137
  
  	if (new_ip) {
82d5b9a7c   Dave Kleikamp   JFS: Add lockdep ...
1138
1139
  		mutex_lock_nested(&JFS_IP(new_ip)->commit_mutex,
  				  COMMIT_MUTEX_VICTIM);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1140
1141
1142
1143
1144
1145
1146
1147
  		/*
  		 * Change existing directory entry to new inode number
  		 */
  		ino = new_ip->i_ino;
  		rc = dtModify(tid, new_dir, &new_dname, &ino,
  			      old_ip->i_ino, JFS_RENAME);
  		if (rc)
  			goto out4;
9a53c3a78   Dave Hansen   [PATCH] r/o bind ...
1148
  		drop_nlink(new_ip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1149
  		if (S_ISDIR(new_ip->i_mode)) {
9a53c3a78   Dave Hansen   [PATCH] r/o bind ...
1150
  			drop_nlink(new_ip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1151
  			if (new_ip->i_nlink) {
48ce8b056   Evgeniy Dushistov   JFS: commit_mutex...
1152
  				mutex_unlock(&JFS_IP(new_ip)->commit_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1153
  				if (old_dir != new_dir)
1de87444f   Ingo Molnar   JFS: semaphore to...
1154
  					mutex_unlock(&JFS_IP(old_dir)->commit_mutex);
48ce8b056   Evgeniy Dushistov   JFS: commit_mutex...
1155
1156
  				mutex_unlock(&JFS_IP(old_ip)->commit_mutex);
  				mutex_unlock(&JFS_IP(new_dir)->commit_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
  				if (!S_ISDIR(old_ip->i_mode) && new_ip)
  					IWRITE_UNLOCK(new_ip);
  				jfs_error(new_ip->i_sb,
  					  "jfs_rename: new_ip->i_nlink != 0");
  				return -EIO;
  			}
  			tblk = tid_to_tblock(tid);
  			tblk->xflag |= COMMIT_DELETE;
  			tblk->u.ip = new_ip;
  		} else if (new_ip->i_nlink == 0) {
  			assert(!test_cflag(COMMIT_Nolink, new_ip));
  			/* free block resources */
  			if ((new_size = commitZeroLink(tid, new_ip)) < 0) {
  				txAbort(tid, 1);	/* Marks FS Dirty */
63f83c9fc   Dave Kleikamp   JFS: White space ...
1171
  				rc = new_size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
  				goto out4;
  			}
  			tblk = tid_to_tblock(tid);
  			tblk->xflag |= COMMIT_DELETE;
  			tblk->u.ip = new_ip;
  		} else {
  			new_ip->i_ctime = CURRENT_TIME;
  			mark_inode_dirty(new_ip);
  		}
  	} else {
  		/*
  		 * Add new directory entry
  		 */
  		rc = dtSearch(new_dir, &new_dname, &ino, &btstack,
  			      JFS_CREATE);
  		if (rc) {
  			jfs_err("jfs_rename didn't expect dtSearch to fail "
  				"w/rc = %d", rc);
  			goto out4;
  		}
  
  		ino = old_ip->i_ino;
  		rc = dtInsert(tid, new_dir, &new_dname, &ino, &btstack);
  		if (rc) {
  			if (rc == -EIO)
  				jfs_err("jfs_rename: dtInsert returned -EIO");
  			goto out4;
  		}
  		if (S_ISDIR(old_ip->i_mode))
d8c76e6f4   Dave Hansen   [PATCH] r/o bind ...
1201
  			inc_nlink(new_dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
  	}
  	/*
  	 * Remove old directory entry
  	 */
  
  	ino = old_ip->i_ino;
  	rc = dtDelete(tid, old_dir, &old_dname, &ino, JFS_REMOVE);
  	if (rc) {
  		jfs_err("jfs_rename did not expect dtDelete to return rc = %d",
  			rc);
  		txAbort(tid, 1);	/* Marks Filesystem dirty */
  		goto out4;
  	}
  	if (S_ISDIR(old_ip->i_mode)) {
9a53c3a78   Dave Hansen   [PATCH] r/o bind ...
1216
  		drop_nlink(old_dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
  		if (old_dir != new_dir) {
  			/*
  			 * Change inode number of parent for moved directory
  			 */
  
  			JFS_IP(old_ip)->i_dtroot.header.idotdot =
  				cpu_to_le32(new_dir->i_ino);
  
  			/* Linelock header of dtree */
  			tlck = txLock(tid, old_ip,
  				    (struct metapage *) &JFS_IP(old_ip)->bxflag,
  				      tlckDTREE | tlckBTROOT | tlckRELINK);
  			dtlck = (struct dt_lock *) & tlck->lock;
  			ASSERT(dtlck->index == 0);
  			lv = & dtlck->lv[0];
  			lv->offset = 0;
  			lv->length = 1;
  			dtlck->index++;
  		}
  	}
  
  	/*
  	 * Update ctime on changed/moved inodes & mark dirty
  	 */
  	old_ip->i_ctime = CURRENT_TIME;
  	mark_inode_dirty(old_ip);
  
  	new_dir->i_ctime = new_dir->i_mtime = current_fs_time(new_dir->i_sb);
  	mark_inode_dirty(new_dir);
  
  	/* Build list of inodes modified by this transaction */
  	ipcount = 0;
  	iplist[ipcount++] = old_ip;
  	if (new_ip)
  		iplist[ipcount++] = new_ip;
  	iplist[ipcount++] = old_dir;
  
  	if (old_dir != new_dir) {
  		iplist[ipcount++] = new_dir;
  		old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
  		mark_inode_dirty(old_dir);
  	}
  
  	/*
  	 * Incomplete truncate of file data can
  	 * result in timing problems unless we synchronously commit the
  	 * transaction.
  	 */
  	if (new_size)
  		commit_flag = COMMIT_SYNC;
  	else
  		commit_flag = 0;
  
  	rc = txCommit(tid, ipcount, iplist, commit_flag);
  
        out4:
  	txEnd(tid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1274
  	if (new_ip)
1de87444f   Ingo Molnar   JFS: semaphore to...
1275
  		mutex_unlock(&JFS_IP(new_ip)->commit_mutex);
48ce8b056   Evgeniy Dushistov   JFS: commit_mutex...
1276
1277
1278
1279
  	if (old_dir != new_dir)
  		mutex_unlock(&JFS_IP(old_dir)->commit_mutex);
  	mutex_unlock(&JFS_IP(old_ip)->commit_mutex);
  	mutex_unlock(&JFS_IP(new_dir)->commit_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1280
1281
1282
  
  	while (new_size && (rc == 0)) {
  		tid = txBegin(new_ip->i_sb, 0);
1de87444f   Ingo Molnar   JFS: semaphore to...
1283
  		mutex_lock(&JFS_IP(new_ip)->commit_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1284
1285
1286
  		new_size = xtTruncate_pmap(tid, new_ip, new_size);
  		if (new_size < 0) {
  			txAbort(tid, 1);
63f83c9fc   Dave Kleikamp   JFS: White space ...
1287
  			rc = new_size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1288
1289
1290
  		} else
  			rc = txCommit(tid, 1, &new_ip, COMMIT_SYNC);
  		txEnd(tid);
1de87444f   Ingo Molnar   JFS: semaphore to...
1291
  		mutex_unlock(&JFS_IP(new_ip)->commit_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
  	}
  	if (new_ip && (new_ip->i_nlink == 0))
  		set_cflag(COMMIT_Nolink, new_ip);
        out3:
  	free_UCSname(&new_dname);
        out2:
  	free_UCSname(&old_dname);
        out1:
  	if (new_ip && !S_ISDIR(new_ip->i_mode))
  		IWRITE_UNLOCK(new_ip);
  	/*
  	 * Truncating the directory index table is not guaranteed.  It
  	 * may need to be done iteratively
  	 */
  	if (test_cflag(COMMIT_Stale, old_dir)) {
  		if (old_dir->i_size > 1)
  			jfs_truncate_nolock(old_dir, 0);
  
  		clear_cflag(COMMIT_Stale, old_dir);
  	}
  
  	jfs_info("jfs_rename: returning %d", rc);
  	return rc;
  }
  
  
  /*
f720e3ba5   Dave Kleikamp   JFS: Whitespace c...
1319
   * NAME:	jfs_mknod
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1320
   *
f720e3ba5   Dave Kleikamp   JFS: Whitespace c...
1321
   * FUNCTION:	Create a special file (device)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1322
1323
   */
  static int jfs_mknod(struct inode *dir, struct dentry *dentry,
1a67aafb5   Al Viro   switch ->mknod() ...
1324
  		umode_t mode, dev_t rdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
  {
  	struct jfs_inode_info *jfs_ip;
  	struct btstack btstack;
  	struct component_name dname;
  	ino_t ino;
  	struct inode *ip;
  	struct inode *iplist[2];
  	int rc;
  	tid_t tid;
  	struct tblock *tblk;
  
  	if (!new_valid_dev(rdev))
  		return -EINVAL;
  
  	jfs_info("jfs_mknod: %s", dentry->d_name.name);
871a29315   Christoph Hellwig   dquot: cleanup dq...
1340
  	dquot_initialize(dir);
907f4554e   Christoph Hellwig   dquot: move dquot...
1341

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1342
1343
1344
1345
  	if ((rc = get_UCSname(&dname, dentry)))
  		goto out;
  
  	ip = ialloc(dir, mode);
087387f90   Akinobu Mita   [PATCH] JFS: retu...
1346
1347
  	if (IS_ERR(ip)) {
  		rc = PTR_ERR(ip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1348
1349
1350
1351
1352
  		goto out1;
  	}
  	jfs_ip = JFS_IP(ip);
  
  	tid = txBegin(dir->i_sb, 0);
82d5b9a7c   Dave Kleikamp   JFS: Add lockdep ...
1353
1354
  	mutex_lock_nested(&JFS_IP(dir)->commit_mutex, COMMIT_MUTEX_PARENT);
  	mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1355

4f4b401bf   Dave Kleikamp   JFS: allow extend...
1356
1357
  	rc = jfs_init_acl(tid, ip, dir);
  	if (rc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1358
  		goto out3;
2a7dba391   Eric Paris   fs/vfs/security: ...
1359
  	rc = jfs_init_security(tid, ip, dir, &dentry->d_name);
1d15b10f9   Dave Kleikamp   JFS: Implement jf...
1360
1361
1362
1363
  	if (rc) {
  		txAbort(tid, 0);
  		goto out3;
  	}
4f4b401bf   Dave Kleikamp   JFS: allow extend...
1364
1365
1366
1367
  	if ((rc = dtSearch(dir, &dname, &ino, &btstack, JFS_CREATE))) {
  		txAbort(tid, 0);
  		goto out3;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1368
1369
1370
1371
1372
1373
  	tblk = tid_to_tblock(tid);
  	tblk->xflag |= COMMIT_CREATE;
  	tblk->ino = ip->i_ino;
  	tblk->u.ixpxd = JFS_IP(ip)->ixpxd;
  
  	ino = ip->i_ino;
4f4b401bf   Dave Kleikamp   JFS: allow extend...
1374
1375
  	if ((rc = dtInsert(tid, dir, &dname, &ino, &btstack))) {
  		txAbort(tid, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1376
  		goto out3;
4f4b401bf   Dave Kleikamp   JFS: allow extend...
1377
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1378
1379
1380
1381
  
  	ip->i_op = &jfs_file_inode_operations;
  	jfs_ip->dev = new_encode_dev(rdev);
  	init_special_inode(ip, ip->i_mode, rdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
  	mark_inode_dirty(ip);
  
  	dir->i_ctime = dir->i_mtime = CURRENT_TIME;
  
  	mark_inode_dirty(dir);
  
  	iplist[0] = dir;
  	iplist[1] = ip;
  	rc = txCommit(tid, 2, iplist, 0);
  
        out3:
  	txEnd(tid);
1de87444f   Ingo Molnar   JFS: semaphore to...
1394
1395
  	mutex_unlock(&JFS_IP(ip)->commit_mutex);
  	mutex_unlock(&JFS_IP(dir)->commit_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1396
  	if (rc) {
4f4b401bf   Dave Kleikamp   JFS: allow extend...
1397
  		free_ea_wmap(ip);
6d6b77f16   Miklos Szeredi   filesystems: add ...
1398
  		clear_nlink(ip);
1f3403fa6   Dave Kleikamp   nfsd race fixes: jfs
1399
  		unlock_new_inode(ip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1400
  		iput(ip);
1f3403fa6   Dave Kleikamp   nfsd race fixes: jfs
1401
  	} else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1402
  		d_instantiate(dentry, ip);
1f3403fa6   Dave Kleikamp   nfsd race fixes: jfs
1403
1404
  		unlock_new_inode(ip);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1405
1406
1407
  
        out1:
  	free_UCSname(&dname);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
        out:
  	jfs_info("jfs_mknod: returning %d", rc);
  	return rc;
  }
  
  static struct dentry *jfs_lookup(struct inode *dip, struct dentry *dentry, struct nameidata *nd)
  {
  	struct btstack btstack;
  	ino_t inum;
  	struct inode *ip;
  	struct component_name key;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1419
  	int rc;
79ac5a46c   Al Viro   jfs_lookup(): don...
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
  	jfs_info("jfs_lookup: name = %s", dentry->d_name.name);
  
  	if ((rc = get_UCSname(&key, dentry)))
  		return ERR_PTR(rc);
  	rc = dtSearch(dip, &key, &inum, &btstack, JFS_LOOKUP);
  	free_UCSname(&key);
  	if (rc == -ENOENT) {
  		ip = NULL;
  	} else if (rc) {
  		jfs_err("jfs_lookup: dtSearch returned %d", rc);
  		ip = ERR_PTR(rc);
  	} else {
  		ip = jfs_iget(dip->i_sb, inum);
  		if (IS_ERR(ip))
  			jfs_err("jfs_lookup: iget failed on inum %d", (uint)inum);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1435
  	}
94b77bd86   Al Viro   switch jfs to ->s...
1436
  	return d_splice_alias(ip, dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1437
  }
d425de704   Christoph Hellwig   jfs: new export ops
1438
1439
  static struct inode *jfs_nfs_get_inode(struct super_block *sb,
  		u64 ino, u32 generation)
5ca296073   Christoph Hellwig   knfsd: exportfs: ...
1440
  {
5ca296073   Christoph Hellwig   knfsd: exportfs: ...
1441
  	struct inode *inode;
5ca296073   Christoph Hellwig   knfsd: exportfs: ...
1442
1443
1444
  
  	if (ino == 0)
  		return ERR_PTR(-ESTALE);
eab1df71a   David Howells   iget: stop JFS fr...
1445
1446
1447
  	inode = jfs_iget(sb, ino);
  	if (IS_ERR(inode))
  		return ERR_CAST(inode);
5ca296073   Christoph Hellwig   knfsd: exportfs: ...
1448

eab1df71a   David Howells   iget: stop JFS fr...
1449
  	if (generation && inode->i_generation != generation) {
d425de704   Christoph Hellwig   jfs: new export ops
1450
1451
  		iput(inode);
  		return ERR_PTR(-ESTALE);
5ca296073   Christoph Hellwig   knfsd: exportfs: ...
1452
  	}
d425de704   Christoph Hellwig   jfs: new export ops
1453
1454
  	return inode;
  }
5ca296073   Christoph Hellwig   knfsd: exportfs: ...
1455

d425de704   Christoph Hellwig   jfs: new export ops
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
  struct dentry *jfs_fh_to_dentry(struct super_block *sb, struct fid *fid,
  		int fh_len, int fh_type)
  {
  	return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
  				    jfs_nfs_get_inode);
  }
  
  struct dentry *jfs_fh_to_parent(struct super_block *sb, struct fid *fid,
  		int fh_len, int fh_type)
  {
  	return generic_fh_to_parent(sb, fid, fh_len, fh_type,
  				    jfs_nfs_get_inode);
5ca296073   Christoph Hellwig   knfsd: exportfs: ...
1468
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1469
1470
  struct dentry *jfs_get_parent(struct dentry *dentry)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1471
1472
1473
1474
  	unsigned long parent_ino;
  
  	parent_ino =
  		le32_to_cpu(JFS_IP(dentry->d_inode)->i_dtroot.header.idotdot);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1475

440037287   Christoph Hellwig   [PATCH] switch al...
1476
  	return d_obtain_alias(jfs_iget(dentry->d_inode->i_sb, parent_ino));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1477
  }
92e1d5be9   Arjan van de Ven   [PATCH] mark stru...
1478
  const struct inode_operations jfs_dir_inode_operations = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
  	.create		= jfs_create,
  	.lookup		= jfs_lookup,
  	.link		= jfs_link,
  	.unlink		= jfs_unlink,
  	.symlink	= jfs_symlink,
  	.mkdir		= jfs_mkdir,
  	.rmdir		= jfs_rmdir,
  	.mknod		= jfs_mknod,
  	.rename		= jfs_rename,
  	.setxattr	= jfs_setxattr,
  	.getxattr	= jfs_getxattr,
  	.listxattr	= jfs_listxattr,
  	.removexattr	= jfs_removexattr,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1492
  	.setattr	= jfs_setattr,
759bfee65   Christoph Hellwig   dquot: move dquot...
1493
  #ifdef CONFIG_JFS_POSIX_ACL
4e34e719e   Christoph Hellwig   fs: take the ACL ...
1494
  	.get_acl	= jfs_get_acl,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1495
1496
  #endif
  };
4b6f5d20b   Arjan van de Ven   [PATCH] Make most...
1497
  const struct file_operations jfs_dir_operations = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1498
1499
1500
  	.read		= generic_read_dir,
  	.readdir	= jfs_readdir,
  	.fsync		= jfs_fsync,
baab81fa5   Andi Kleen   BKL-removal: Use ...
1501
  	.unlocked_ioctl = jfs_ioctl,
ef1fc2f01   Andi Kleen   BKL-removal: Impl...
1502
1503
1504
  #ifdef CONFIG_COMPAT
  	.compat_ioctl	= jfs_compat_ioctl,
  #endif
3222a3e55   Christoph Hellwig   [PATCH] fix ->lls...
1505
  	.llseek		= generic_file_llseek,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1506
  };
b1e6a015a   Nick Piggin   fs: change d_hash...
1507
1508
  static int jfs_ci_hash(const struct dentry *dir, const struct inode *inode,
  		struct qstr *this)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
  {
  	unsigned long hash;
  	int i;
  
  	hash = init_name_hash();
  	for (i=0; i < this->len; i++)
  		hash = partial_name_hash(tolower(this->name[i]), hash);
  	this->hash = end_name_hash(hash);
  
  	return 0;
  }
621e155a3   Nick Piggin   fs: change d_comp...
1520
1521
1522
1523
  static int jfs_ci_compare(const struct dentry *parent,
  		const struct inode *pinode,
  		const struct dentry *dentry, const struct inode *inode,
  		unsigned int len, const char *str, const struct qstr *name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1524
1525
  {
  	int i, result = 1;
621e155a3   Nick Piggin   fs: change d_comp...
1526
  	if (len != name->len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1527
  		goto out;
621e155a3   Nick Piggin   fs: change d_comp...
1528
1529
  	for (i=0; i < len; i++) {
  		if (tolower(str[i]) != tolower(name->name[i]))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1530
1531
1532
  			goto out;
  	}
  	result = 0;
2bc334dcc   Nick Piggin   jfs: dont overwri...
1533
1534
1535
  out:
  	return result;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1536

2bc334dcc   Nick Piggin   jfs: dont overwri...
1537
1538
  static int jfs_ci_revalidate(struct dentry *dentry, struct nameidata *nd)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1539
  	/*
2bc334dcc   Nick Piggin   jfs: dont overwri...
1540
1541
1542
1543
1544
1545
1546
1547
  	 * This is not negative dentry. Always valid.
  	 *
  	 * Note, rename() to existing directory entry will have ->d_inode,
  	 * and will use existing name which isn't specified name by user.
  	 *
  	 * We may be able to drop this positive dentry here. But dropping
  	 * positive dentry isn't good idea. So it's unsupported like
  	 * rename("filename", "FILENAME") for now.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1548
  	 */
2bc334dcc   Nick Piggin   jfs: dont overwri...
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
  	if (dentry->d_inode)
  		return 1;
  
  	/*
  	 * This may be nfsd (or something), anyway, we can't see the
  	 * intent of this. So, since this can be for creation, drop it.
  	 */
  	if (!nd)
  		return 0;
  
  	/*
  	 * Drop the negative dentry, in order to make sure to use the
  	 * case sensitive name which is specified by user if this is
  	 * for creation.
  	 */
407938e79   Al Viro   LOOKUP_CREATE and...
1564
1565
  	if (nd->flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET))
  		return 0;
2bc334dcc   Nick Piggin   jfs: dont overwri...
1566
  	return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1567
  }
ad28b4ef1   Al Viro   constify dentry_o...
1568
  const struct dentry_operations jfs_ci_dentry_operations =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1569
1570
1571
  {
  	.d_hash = jfs_ci_hash,
  	.d_compare = jfs_ci_compare,
2bc334dcc   Nick Piggin   jfs: dont overwri...
1572
  	.d_revalidate = jfs_ci_revalidate,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1573
  };