VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[linux-2.6.git] / fs / jfs / namei.c
1 /*
2  *   Copyright (C) International Business Machines Corp., 2000-2004
3  *   Portions Copyright (C) Christoph Hellwig, 2001-2002
4  *
5  *   This program is free software;  you can redistribute it and/or modify
6  *   it under the terms of the GNU General Public License as published by
7  *   the Free Software Foundation; either version 2 of the License, or 
8  *   (at your option) any later version.
9  * 
10  *   This program is distributed in the hope that it will be useful,
11  *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
13  *   the GNU General Public License for more details.
14  *
15  *   You should have received a copy of the GNU General Public License
16  *   along with this program;  if not, write to the Free Software 
17  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  */
19
20 #include <linux/fs.h>
21 #include <linux/ctype.h>
22 #include "jfs_incore.h"
23 #include "jfs_superblock.h"
24 #include "jfs_inode.h"
25 #include "jfs_dinode.h"
26 #include "jfs_dmap.h"
27 #include "jfs_unicode.h"
28 #include "jfs_metapage.h"
29 #include "jfs_xattr.h"
30 #include "jfs_acl.h"
31 #include "jfs_debug.h"
32
33 extern struct inode_operations jfs_file_inode_operations;
34 extern struct inode_operations jfs_symlink_inode_operations;
35 extern struct file_operations jfs_file_operations;
36 extern struct address_space_operations jfs_aops;
37
38 extern int jfs_fsync(struct file *, struct dentry *, int);
39 extern void jfs_truncate_nolock(struct inode *, loff_t);
40 extern int jfs_init_acl(struct inode *, struct inode *);
41
42 /*
43  * forward references
44  */
45 struct inode_operations jfs_dir_inode_operations;
46 struct file_operations jfs_dir_operations;
47 struct dentry_operations jfs_ci_dentry_operations;
48
49 static s64 commitZeroLink(tid_t, struct inode *);
50
51 /*
52  * NAME:        jfs_create(dip, dentry, mode)
53  *
54  * FUNCTION:    create a regular file in the parent directory <dip>
55  *              with name = <from dentry> and mode = <mode>
56  *
57  * PARAMETER:   dip     - parent directory vnode
58  *              dentry  - dentry of new file
59  *              mode    - create mode (rwxrwxrwx).
60  *              nd- nd struct
61  *
62  * RETURN:      Errors from subroutines
63  *
64  */
65 static int jfs_create(struct inode *dip, struct dentry *dentry, int mode,
66                 struct nameidata *nd)
67 {
68         int rc = 0;
69         tid_t tid;              /* transaction id */
70         struct inode *ip = NULL;        /* child directory inode */
71         ino_t ino;
72         struct component_name dname;    /* child directory name */
73         struct btstack btstack;
74         struct inode *iplist[2];
75         struct tblock *tblk;
76
77         jfs_info("jfs_create: dip:0x%p name:%s", dip, dentry->d_name.name);
78
79         /*
80          * search parent directory for entry/freespace
81          * (dtSearch() returns parent directory page pinned)
82          */
83         if ((rc = get_UCSname(&dname, dentry)))
84                 goto out1;
85
86         /*
87          * Either iAlloc() or txBegin() may block.  Deadlock can occur if we
88          * block there while holding dtree page, so we allocate the inode &
89          * begin the transaction before we search the directory.
90          */
91         ip = ialloc(dip, mode);
92         if (ip == NULL) {
93                 rc = -ENOSPC;
94                 goto out2;
95         }
96
97         tid = txBegin(dip->i_sb, 0);
98
99         down(&JFS_IP(dip)->commit_sem);
100         down(&JFS_IP(ip)->commit_sem);
101
102         if ((rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE))) {
103                 jfs_err("jfs_create: dtSearch returned %d", rc);
104                 goto out3;
105         }
106
107         tblk = tid_to_tblock(tid);
108         tblk->xflag |= COMMIT_CREATE;
109         tblk->ino = ip->i_ino;
110         tblk->u.ixpxd = JFS_IP(ip)->ixpxd;
111
112         iplist[0] = dip;
113         iplist[1] = ip;
114
115         /*
116          * initialize the child XAD tree root in-line in inode
117          */
118         xtInitRoot(tid, ip);
119
120         /*
121          * create entry in parent directory for child directory
122          * (dtInsert() releases parent directory page)
123          */
124         ino = ip->i_ino;
125         if ((rc = dtInsert(tid, dip, &dname, &ino, &btstack))) {
126                 jfs_err("jfs_create: dtInsert returned %d", rc);
127                 if (rc == -EIO)
128                         txAbort(tid, 1);        /* Marks Filesystem dirty */
129                 else
130                         txAbort(tid, 0);        /* Filesystem full */
131                 goto out3;
132         }
133
134         ip->i_op = &jfs_file_inode_operations;
135         ip->i_fop = &jfs_file_operations;
136         ip->i_mapping->a_ops = &jfs_aops;
137
138         insert_inode_hash(ip);
139         mark_inode_dirty(ip);
140
141         dip->i_ctime = dip->i_mtime = CURRENT_TIME;
142
143         mark_inode_dirty(dip);
144
145         rc = txCommit(tid, 2, &iplist[0], 0);
146
147       out3:
148         txEnd(tid);
149         up(&JFS_IP(dip)->commit_sem);
150         up(&JFS_IP(ip)->commit_sem);
151         if (rc) {
152                 ip->i_nlink = 0;
153                 iput(ip);
154         } else
155                 d_instantiate(dentry, ip);
156
157       out2:
158         free_UCSname(&dname);
159
160 #ifdef CONFIG_JFS_POSIX_ACL
161         if (rc == 0)
162                 jfs_init_acl(ip, dip);
163 #endif
164
165       out1:
166
167         jfs_info("jfs_create: rc:%d", rc);
168         return rc;
169 }
170
171
172 /*
173  * NAME:        jfs_mkdir(dip, dentry, mode)
174  *
175  * FUNCTION:    create a child directory in the parent directory <dip>
176  *              with name = <from dentry> and mode = <mode>
177  *
178  * PARAMETER:   dip     - parent directory vnode
179  *              dentry  - dentry of child directory
180  *              mode    - create mode (rwxrwxrwx).
181  *
182  * RETURN:      Errors from subroutines
183  *
184  * note:
185  * EACCESS: user needs search+write permission on the parent directory
186  */
187 static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode)
188 {
189         int rc = 0;
190         tid_t tid;              /* transaction id */
191         struct inode *ip = NULL;        /* child directory inode */
192         ino_t ino;
193         struct component_name dname;    /* child directory name */
194         struct btstack btstack;
195         struct inode *iplist[2];
196         struct tblock *tblk;
197
198         jfs_info("jfs_mkdir: dip:0x%p name:%s", dip, dentry->d_name.name);
199
200         /* link count overflow on parent directory ? */
201         if (dip->i_nlink == JFS_LINK_MAX) {
202                 rc = -EMLINK;
203                 goto out1;
204         }
205
206         /*
207          * search parent directory for entry/freespace
208          * (dtSearch() returns parent directory page pinned)
209          */
210         if ((rc = get_UCSname(&dname, dentry)))
211                 goto out1;
212
213         /*
214          * Either iAlloc() or txBegin() may block.  Deadlock can occur if we
215          * block there while holding dtree page, so we allocate the inode &
216          * begin the transaction before we search the directory.
217          */
218         ip = ialloc(dip, S_IFDIR | mode);
219         if (ip == NULL) {
220                 rc = -ENOSPC;
221                 goto out2;
222         }
223
224         tid = txBegin(dip->i_sb, 0);
225
226         down(&JFS_IP(dip)->commit_sem);
227         down(&JFS_IP(ip)->commit_sem);
228
229         if ((rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE))) {
230                 jfs_err("jfs_mkdir: dtSearch returned %d", rc);
231                 goto out3;
232         }
233
234         tblk = tid_to_tblock(tid);
235         tblk->xflag |= COMMIT_CREATE;
236         tblk->ino = ip->i_ino;
237         tblk->u.ixpxd = JFS_IP(ip)->ixpxd;
238
239         iplist[0] = dip;
240         iplist[1] = ip;
241
242         /*
243          * initialize the child directory in-line in inode
244          */
245         dtInitRoot(tid, ip, dip->i_ino);
246
247         /*
248          * create entry in parent directory for child directory
249          * (dtInsert() releases parent directory page)
250          */
251         ino = ip->i_ino;
252         if ((rc = dtInsert(tid, dip, &dname, &ino, &btstack))) {
253                 jfs_err("jfs_mkdir: dtInsert returned %d", rc);
254
255                 if (rc == -EIO)
256                         txAbort(tid, 1);        /* Marks Filesystem dirty */
257                 else
258                         txAbort(tid, 0);        /* Filesystem full */
259                 goto out3;
260         }
261
262         ip->i_nlink = 2;        /* for '.' */
263         ip->i_op = &jfs_dir_inode_operations;
264         ip->i_fop = &jfs_dir_operations;
265         ip->i_mapping->a_ops = &jfs_aops;
266         mapping_set_gfp_mask(ip->i_mapping, GFP_NOFS);
267
268         insert_inode_hash(ip);
269         mark_inode_dirty(ip);
270
271         /* update parent directory inode */
272         dip->i_nlink++;         /* for '..' from child directory */
273         dip->i_ctime = dip->i_mtime = CURRENT_TIME;
274         mark_inode_dirty(dip);
275
276         rc = txCommit(tid, 2, &iplist[0], 0);
277
278       out3:
279         txEnd(tid);
280         up(&JFS_IP(dip)->commit_sem);
281         up(&JFS_IP(ip)->commit_sem);
282         if (rc) {
283                 ip->i_nlink = 0;
284                 iput(ip);
285         } else
286                 d_instantiate(dentry, ip);
287
288       out2:
289         free_UCSname(&dname);
290
291 #ifdef CONFIG_JFS_POSIX_ACL
292         if (rc == 0)
293                 jfs_init_acl(ip, dip);
294 #endif
295
296       out1:
297
298         jfs_info("jfs_mkdir: rc:%d", rc);
299         return rc;
300 }
301
302 /*
303  * NAME:        jfs_rmdir(dip, dentry)
304  *
305  * FUNCTION:    remove a link to child directory
306  *
307  * PARAMETER:   dip     - parent inode
308  *              dentry  - child directory dentry
309  *
310  * RETURN:      -EINVAL - if name is . or ..
311  *              -EINVAL  - if . or .. exist but are invalid.
312  *              errors from subroutines
313  *
314  * note:
315  * if other threads have the directory open when the last link 
316  * is removed, the "." and ".." entries, if present, are removed before 
317  * rmdir() returns and no new entries may be created in the directory, 
318  * but the directory is not removed until the last reference to 
319  * the directory is released (cf.unlink() of regular file).
320  */
321 static int jfs_rmdir(struct inode *dip, struct dentry *dentry)
322 {
323         int rc;
324         tid_t tid;              /* transaction id */
325         struct inode *ip = dentry->d_inode;
326         ino_t ino;
327         struct component_name dname;
328         struct inode *iplist[2];
329         struct tblock *tblk;
330
331         jfs_info("jfs_rmdir: dip:0x%p name:%s", dip, dentry->d_name.name);
332
333         /* directory must be empty to be removed */
334         if (!dtEmpty(ip)) {
335                 rc = -ENOTEMPTY;
336                 goto out;
337         }
338
339         if ((rc = get_UCSname(&dname, dentry))) {
340                 goto out;
341         }
342
343         tid = txBegin(dip->i_sb, 0);
344
345         down(&JFS_IP(dip)->commit_sem);
346         down(&JFS_IP(ip)->commit_sem);
347
348         iplist[0] = dip;
349         iplist[1] = ip;
350
351         tblk = tid_to_tblock(tid);
352         tblk->xflag |= COMMIT_DELETE;
353         tblk->u.ip = ip;
354
355         /*
356          * delete the entry of target directory from parent directory
357          */
358         ino = ip->i_ino;
359         if ((rc = dtDelete(tid, dip, &dname, &ino, JFS_REMOVE))) {
360                 jfs_err("jfs_rmdir: dtDelete returned %d", rc);
361                 if (rc == -EIO)
362                         txAbort(tid, 1);
363                 txEnd(tid);
364                 up(&JFS_IP(dip)->commit_sem);
365                 up(&JFS_IP(ip)->commit_sem);
366
367                 goto out2;
368         }
369
370         /* update parent directory's link count corresponding
371          * to ".." entry of the target directory deleted
372          */
373         dip->i_nlink--;
374         dip->i_ctime = dip->i_mtime = CURRENT_TIME;
375         mark_inode_dirty(dip);
376
377         /*
378          * OS/2 could have created EA and/or ACL
379          */
380         /* free EA from both persistent and working map */
381         if (JFS_IP(ip)->ea.flag & DXD_EXTENT) {
382                 /* free EA pages */
383                 txEA(tid, ip, &JFS_IP(ip)->ea, NULL);
384         }
385         JFS_IP(ip)->ea.flag = 0;
386
387         /* free ACL from both persistent and working map */
388         if (JFS_IP(ip)->acl.flag & DXD_EXTENT) {
389                 /* free ACL pages */
390                 txEA(tid, ip, &JFS_IP(ip)->acl, NULL);
391         }
392         JFS_IP(ip)->acl.flag = 0;
393
394         /* mark the target directory as deleted */
395         ip->i_nlink = 0;
396         mark_inode_dirty(ip);
397
398         rc = txCommit(tid, 2, &iplist[0], 0);
399
400         txEnd(tid);
401
402         up(&JFS_IP(dip)->commit_sem);
403         up(&JFS_IP(ip)->commit_sem);
404
405         /*
406          * Truncating the directory index table is not guaranteed.  It
407          * may need to be done iteratively
408          */
409         if (test_cflag(COMMIT_Stale, dip)) {
410                 if (dip->i_size > 1)
411                         jfs_truncate_nolock(dip, 0);
412
413                 clear_cflag(COMMIT_Stale, dip);
414         }
415
416       out2:
417         free_UCSname(&dname);
418
419       out:
420         jfs_info("jfs_rmdir: rc:%d", rc);
421         return rc;
422 }
423
424 /*
425  * NAME:        jfs_unlink(dip, dentry)
426  *
427  * FUNCTION:    remove a link to object <vp> named by <name> 
428  *              from parent directory <dvp>
429  *
430  * PARAMETER:   dip     - inode of parent directory
431  *              dentry  - dentry of object to be removed
432  *
433  * RETURN:      errors from subroutines
434  *
435  * note:
436  * temporary file: if one or more processes have the file open
437  * when the last link is removed, the link will be removed before
438  * unlink() returns, but the removal of the file contents will be
439  * postponed until all references to the files are closed.
440  *
441  * JFS does NOT support unlink() on directories.
442  *
443  */
444 static int jfs_unlink(struct inode *dip, struct dentry *dentry)
445 {
446         int rc;
447         tid_t tid;              /* transaction id */
448         struct inode *ip = dentry->d_inode;
449         ino_t ino;
450         struct component_name dname;    /* object name */
451         struct inode *iplist[2];
452         struct tblock *tblk;
453         s64 new_size = 0;
454         int commit_flag;
455
456         jfs_info("jfs_unlink: dip:0x%p name:%s", dip, dentry->d_name.name);
457
458         if ((rc = get_UCSname(&dname, dentry)))
459                 goto out;
460
461         IWRITE_LOCK(ip);
462
463         tid = txBegin(dip->i_sb, 0);
464
465         down(&JFS_IP(dip)->commit_sem);
466         down(&JFS_IP(ip)->commit_sem);
467
468         iplist[0] = dip;
469         iplist[1] = ip;
470
471         /*
472          * delete the entry of target file from parent directory
473          */
474         ino = ip->i_ino;
475         if ((rc = dtDelete(tid, dip, &dname, &ino, JFS_REMOVE))) {
476                 jfs_err("jfs_unlink: dtDelete returned %d", rc);
477                 if (rc == -EIO)
478                         txAbort(tid, 1);        /* Marks FS Dirty */
479                 txEnd(tid);
480                 up(&JFS_IP(dip)->commit_sem);
481                 up(&JFS_IP(ip)->commit_sem);
482                 IWRITE_UNLOCK(ip);
483                 goto out1;
484         }
485
486         ASSERT(ip->i_nlink);
487
488         ip->i_ctime = dip->i_ctime = dip->i_mtime = CURRENT_TIME;
489         mark_inode_dirty(dip);
490
491         /* update target's inode */
492         ip->i_nlink--;
493         mark_inode_dirty(ip);
494
495         /*
496          *      commit zero link count object
497          */
498         if (ip->i_nlink == 0) {
499                 assert(!test_cflag(COMMIT_Nolink, ip));
500                 /* free block resources */
501                 if ((new_size = commitZeroLink(tid, ip)) < 0) {
502                         txAbort(tid, 1);        /* Marks FS Dirty */
503                         txEnd(tid);
504                         up(&JFS_IP(dip)->commit_sem);
505                         up(&JFS_IP(ip)->commit_sem);
506                         IWRITE_UNLOCK(ip);
507                         rc = new_size;
508                         goto out1;
509                 }
510                 tblk = tid_to_tblock(tid);
511                 tblk->xflag |= COMMIT_DELETE;
512                 tblk->u.ip = ip;
513         }
514
515         /*
516          * Incomplete truncate of file data can
517          * result in timing problems unless we synchronously commit the
518          * transaction.
519          */
520         if (new_size)
521                 commit_flag = COMMIT_SYNC;
522         else
523                 commit_flag = 0;
524
525         /*
526          * If xtTruncate was incomplete, commit synchronously to avoid
527          * timing complications
528          */
529         rc = txCommit(tid, 2, &iplist[0], commit_flag);
530
531         txEnd(tid);
532
533         up(&JFS_IP(dip)->commit_sem);
534         up(&JFS_IP(ip)->commit_sem);
535
536
537         while (new_size && (rc == 0)) {
538                 tid = txBegin(dip->i_sb, 0);
539                 down(&JFS_IP(ip)->commit_sem);
540                 new_size = xtTruncate_pmap(tid, ip, new_size);
541                 if (new_size < 0) {
542                         txAbort(tid, 1);        /* Marks FS Dirty */
543                         rc = new_size;
544                 } else
545                         rc = txCommit(tid, 2, &iplist[0], COMMIT_SYNC);
546                 txEnd(tid);
547                 up(&JFS_IP(ip)->commit_sem);
548         }
549
550         if (ip->i_nlink == 0)
551                 set_cflag(COMMIT_Nolink, ip);
552
553         IWRITE_UNLOCK(ip);
554
555         /*
556          * Truncating the directory index table is not guaranteed.  It
557          * may need to be done iteratively
558          */
559         if (test_cflag(COMMIT_Stale, dip)) {
560                 if (dip->i_size > 1)
561                         jfs_truncate_nolock(dip, 0);
562
563                 clear_cflag(COMMIT_Stale, dip);
564         }
565
566       out1:
567         free_UCSname(&dname);
568       out:
569         jfs_info("jfs_unlink: rc:%d", rc);
570         return rc;
571 }
572
573 /*
574  * NAME:        commitZeroLink()
575  *
576  * FUNCTION:    for non-directory, called by jfs_remove(),
577  *              truncate a regular file, directory or symbolic
578  *              link to zero length. return 0 if type is not 
579  *              one of these.
580  *
581  *              if the file is currently associated with a VM segment
582  *              only permanent disk and inode map resources are freed,
583  *              and neither the inode nor indirect blocks are modified
584  *              so that the resources can be later freed in the work
585  *              map by ctrunc1.
586  *              if there is no VM segment on entry, the resources are
587  *              freed in both work and permanent map.
588  *              (? for temporary file - memory object is cached even 
589  *              after no reference:
590  *              reference count > 0 -   )
591  *
592  * PARAMETERS:  cd      - pointer to commit data structure.
593  *                        current inode is the one to truncate.
594  *
595  * RETURN:      Errors from subroutines
596  */
597 static s64 commitZeroLink(tid_t tid, struct inode *ip)
598 {
599         int filetype;
600         struct tblock *tblk;
601
602         jfs_info("commitZeroLink: tid = %d, ip = 0x%p", tid, ip);
603
604         filetype = ip->i_mode & S_IFMT;
605         switch (filetype) {
606         case S_IFREG:
607                 break;
608         case S_IFLNK:
609                 /* fast symbolic link */
610                 if (ip->i_size < IDATASIZE) {
611                         ip->i_size = 0;
612                         return 0;
613                 }
614                 break;
615         default:
616                 assert(filetype != S_IFDIR);
617                 return 0;
618         }
619
620         set_cflag(COMMIT_Freewmap, ip);
621
622         /* mark transaction of block map update type */
623         tblk = tid_to_tblock(tid);
624         tblk->xflag |= COMMIT_PMAP;
625
626         /*
627          * free EA
628          */
629         if (JFS_IP(ip)->ea.flag & DXD_EXTENT)
630                 /* acquire maplock on EA to be freed from block map */
631                 txEA(tid, ip, &JFS_IP(ip)->ea, NULL);
632
633         /*
634          * free ACL
635          */
636         if (JFS_IP(ip)->acl.flag & DXD_EXTENT)
637                 /* acquire maplock on EA to be freed from block map */
638                 txEA(tid, ip, &JFS_IP(ip)->acl, NULL);
639
640         /*
641          * free xtree/data (truncate to zero length):
642          * free xtree/data pages from cache if COMMIT_PWMAP, 
643          * free xtree/data blocks from persistent block map, and
644          * free xtree/data blocks from working block map if COMMIT_PWMAP;
645          */
646         if (ip->i_size)
647                 return xtTruncate_pmap(tid, ip, 0);
648
649         return 0;
650 }
651
652
653 /*
654  * NAME:        freeZeroLink()
655  *
656  * FUNCTION:    for non-directory, called by iClose(),
657  *              free resources of a file from cache and WORKING map 
658  *              for a file previously committed with zero link count
659  *              while associated with a pager object,
660  *
661  * PARAMETER:   ip      - pointer to inode of file.
662  *
663  * RETURN:      0 -ok
664  */
665 int freeZeroLink(struct inode *ip)
666 {
667         int rc = 0;
668         int type;
669
670         jfs_info("freeZeroLink: ip = 0x%p", ip);
671
672         /* return if not reg or symbolic link or if size is
673          * already ok.
674          */
675         type = ip->i_mode & S_IFMT;
676
677         switch (type) {
678         case S_IFREG:
679                 break;
680         case S_IFLNK:
681                 /* if its contained in inode nothing to do */
682                 if (ip->i_size < IDATASIZE)
683                         return 0;
684                 break;
685         default:
686                 return 0;
687         }
688
689         /*
690          * free EA
691          */
692         if (JFS_IP(ip)->ea.flag & DXD_EXTENT) {
693                 s64 xaddr = addressDXD(&JFS_IP(ip)->ea);
694                 int xlen = lengthDXD(&JFS_IP(ip)->ea);
695                 struct maplock maplock; /* maplock for COMMIT_WMAP */
696                 struct pxd_lock *pxdlock;       /* maplock for COMMIT_WMAP */
697
698                 /* free EA pages from cache */
699                 invalidate_dxd_metapages(ip, JFS_IP(ip)->ea);
700
701                 /* free EA extent from working block map */
702                 maplock.index = 1;
703                 pxdlock = (struct pxd_lock *) & maplock;
704                 pxdlock->flag = mlckFREEPXD;
705                 PXDaddress(&pxdlock->pxd, xaddr);
706                 PXDlength(&pxdlock->pxd, xlen);
707                 txFreeMap(ip, pxdlock, NULL, COMMIT_WMAP);
708         }
709
710         /*
711          * free ACL
712          */
713         if (JFS_IP(ip)->acl.flag & DXD_EXTENT) {
714                 s64 xaddr = addressDXD(&JFS_IP(ip)->acl);
715                 int xlen = lengthDXD(&JFS_IP(ip)->acl);
716                 struct maplock maplock; /* maplock for COMMIT_WMAP */
717                 struct pxd_lock *pxdlock;       /* maplock for COMMIT_WMAP */
718
719                 invalidate_dxd_metapages(ip, JFS_IP(ip)->acl);
720
721                 /* free ACL extent from working block map */
722                 maplock.index = 1;
723                 pxdlock = (struct pxd_lock *) & maplock;
724                 pxdlock->flag = mlckFREEPXD;
725                 PXDaddress(&pxdlock->pxd, xaddr);
726                 PXDlength(&pxdlock->pxd, xlen);
727                 txFreeMap(ip, pxdlock, NULL, COMMIT_WMAP);
728         }
729
730         /*
731          * free xtree/data (truncate to zero length):
732          * free xtree/data pages from cache, and
733          * free xtree/data blocks from working block map;
734          */
735         if (ip->i_size)
736                 rc = xtTruncate(0, ip, 0, COMMIT_WMAP);
737
738         return rc;
739 }
740
741 /*
742  * NAME:        jfs_link(vp, dvp, name, crp)
743  *
744  * FUNCTION:    create a link to <vp> by the name = <name>
745  *              in the parent directory <dvp>
746  *
747  * PARAMETER:   vp      - target object
748  *              dvp     - parent directory of new link
749  *              name    - name of new link to target object
750  *              crp     - credential
751  *
752  * RETURN:      Errors from subroutines
753  *
754  * note:
755  * JFS does NOT support link() on directories (to prevent circular
756  * path in the directory hierarchy);
757  * EPERM: the target object is a directory, and either the caller
758  * does not have appropriate privileges or the implementation prohibits
759  * using link() on directories [XPG4.2].
760  *
761  * JFS does NOT support links between file systems:
762  * EXDEV: target object and new link are on different file systems and
763  * implementation does not support links between file systems [XPG4.2].
764  */
765 static int jfs_link(struct dentry *old_dentry,
766              struct inode *dir, struct dentry *dentry)
767 {
768         int rc;
769         tid_t tid;
770         struct inode *ip = old_dentry->d_inode;
771         ino_t ino;
772         struct component_name dname;
773         struct btstack btstack;
774         struct inode *iplist[2];
775
776         jfs_info("jfs_link: %s %s", old_dentry->d_name.name,
777                  dentry->d_name.name);
778
779         if (ip->i_nlink == JFS_LINK_MAX)
780                 return -EMLINK;
781
782         if (ip->i_nlink == 0)
783                 return -ENOENT;
784
785         tid = txBegin(ip->i_sb, 0);
786
787         down(&JFS_IP(dir)->commit_sem);
788         down(&JFS_IP(ip)->commit_sem);
789
790         /*
791          * scan parent directory for entry/freespace
792          */
793         if ((rc = get_UCSname(&dname, dentry)))
794                 goto out;
795
796         if ((rc = dtSearch(dir, &dname, &ino, &btstack, JFS_CREATE)))
797                 goto free_dname;
798
799         /*
800          * create entry for new link in parent directory
801          */
802         ino = ip->i_ino;
803         if ((rc = dtInsert(tid, dir, &dname, &ino, &btstack)))
804                 goto free_dname;
805
806         /* update object inode */
807         ip->i_nlink++;          /* for new link */
808         ip->i_ctime = CURRENT_TIME;
809         mark_inode_dirty(dir);
810         atomic_inc(&ip->i_count);
811
812         iplist[0] = ip;
813         iplist[1] = dir;
814         rc = txCommit(tid, 2, &iplist[0], 0);
815
816         if (!rc)
817                 d_instantiate(dentry, ip);
818
819       free_dname:
820         free_UCSname(&dname);
821
822       out:
823         txEnd(tid);
824
825         up(&JFS_IP(dir)->commit_sem);
826         up(&JFS_IP(ip)->commit_sem);
827
828         jfs_info("jfs_link: rc:%d", rc);
829         return rc;
830 }
831
832 /*
833  * NAME:        jfs_symlink(dip, dentry, name)
834  *
835  * FUNCTION:    creates a symbolic link to <symlink> by name <name>
836  *                      in directory <dip>
837  *
838  * PARAMETER:   dip         - parent directory vnode
839  *                      dentry  - dentry of symbolic link
840  *                      name    - the path name of the existing object 
841  *                                    that will be the source of the link
842  *
843  * RETURN:      errors from subroutines
844  *
845  * note:
846  * ENAMETOOLONG: pathname resolution of a symbolic link produced
847  * an intermediate result whose length exceeds PATH_MAX [XPG4.2]
848 */
849
850 static int jfs_symlink(struct inode *dip, struct dentry *dentry,
851                 const char *name)
852 {
853         int rc;
854         tid_t tid;
855         ino_t ino = 0;
856         struct component_name dname;
857         int ssize;              /* source pathname size */
858         struct btstack btstack;
859         struct inode *ip = dentry->d_inode;
860         unchar *i_fastsymlink;
861         s64 xlen = 0;
862         int bmask = 0, xsize;
863         s64 extent = 0, xaddr;
864         struct metapage *mp;
865         struct super_block *sb;
866         struct tblock *tblk;
867
868         struct inode *iplist[2];
869
870         jfs_info("jfs_symlink: dip:0x%p name:%s", dip, name);
871
872         ssize = strlen(name) + 1;
873
874         /*
875          * search parent directory for entry/freespace
876          * (dtSearch() returns parent directory page pinned)
877          */
878
879         if ((rc = get_UCSname(&dname, dentry)))
880                 goto out1;
881
882         /*
883          * allocate on-disk/in-memory inode for symbolic link:
884          * (iAlloc() returns new, locked inode)
885          */
886         ip = ialloc(dip, S_IFLNK | 0777);
887         if (ip == NULL) {
888                 rc = -ENOSPC;
889                 goto out2;
890         }
891
892         tid = txBegin(dip->i_sb, 0);
893
894         down(&JFS_IP(dip)->commit_sem);
895         down(&JFS_IP(ip)->commit_sem);
896
897         tblk = tid_to_tblock(tid);
898         tblk->xflag |= COMMIT_CREATE;
899         tblk->ino = ip->i_ino;
900         tblk->u.ixpxd = JFS_IP(ip)->ixpxd;
901
902         /* fix symlink access permission
903          * (dir_create() ANDs in the u.u_cmask, 
904          * but symlinks really need to be 777 access)
905          */
906         ip->i_mode |= 0777;
907
908         /*
909          * write symbolic link target path name
910          */
911         xtInitRoot(tid, ip);
912
913         /*
914          * write source path name inline in on-disk inode (fast symbolic link)
915          */
916
917         if (ssize <= IDATASIZE) {
918                 ip->i_op = &jfs_symlink_inode_operations;
919
920                 i_fastsymlink = JFS_IP(ip)->i_inline;
921                 memcpy(i_fastsymlink, name, ssize);
922                 ip->i_size = ssize - 1;
923
924                 /*
925                  * if symlink is > 128 bytes, we don't have the space to
926                  * store inline extended attributes
927                  */
928                 if (ssize > sizeof (JFS_IP(ip)->i_inline))
929                         JFS_IP(ip)->mode2 &= ~INLINEEA;
930
931                 jfs_info("jfs_symlink: fast symlink added  ssize:%d name:%s ",
932                          ssize, name);
933         }
934         /*
935          * write source path name in a single extent
936          */
937         else {
938                 jfs_info("jfs_symlink: allocate extent ip:0x%p", ip);
939
940                 ip->i_op = &page_symlink_inode_operations;
941                 ip->i_mapping->a_ops = &jfs_aops;
942
943                 /*
944                  * even though the data of symlink object (source 
945                  * path name) is treated as non-journaled user data,
946                  * it is read/written thru buffer cache for performance.
947                  */
948                 sb = ip->i_sb;
949                 bmask = JFS_SBI(sb)->bsize - 1;
950                 xsize = (ssize + bmask) & ~bmask;
951                 xaddr = 0;
952                 xlen = xsize >> JFS_SBI(sb)->l2bsize;
953                 if ((rc = xtInsert(tid, ip, 0, 0, xlen, &xaddr, 0))) {
954                         txAbort(tid, 0);
955                         rc = -ENOSPC;
956                         goto out3;
957                 }
958                 extent = xaddr;
959                 ip->i_size = ssize - 1;
960                 while (ssize) {
961                         /* This is kind of silly since PATH_MAX == 4K */
962                         int copy_size = min(ssize, PSIZE);
963
964                         mp = get_metapage(ip, xaddr, PSIZE, 1);
965
966                         if (mp == NULL) {
967                                 dbFree(ip, extent, xlen);
968                                 rc = -EIO;
969                                 txAbort(tid, 0);
970                                 goto out3;
971                         }
972                         memcpy(mp->data, name, copy_size);
973                         flush_metapage(mp);
974                         ssize -= copy_size;
975                         name += copy_size;
976                         xaddr += JFS_SBI(sb)->nbperpage;
977                 }
978                 ip->i_blocks = LBLK2PBLK(sb, xlen);
979         }
980
981         /*
982          * create entry for symbolic link in parent directory
983          */
984         rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE);
985         if (rc == 0) {
986                 ino = ip->i_ino;
987                 rc = dtInsert(tid, dip, &dname, &ino, &btstack);
988         }
989         if (rc) {
990                 if (xlen)
991                         dbFree(ip, extent, xlen);
992                 txAbort(tid, 0);
993                 /* discard new inode */
994                 goto out3;
995         }
996
997         insert_inode_hash(ip);
998         mark_inode_dirty(ip);
999
1000         /*
1001          * commit update of parent directory and link object
1002          */
1003
1004         iplist[0] = dip;
1005         iplist[1] = ip;
1006         rc = txCommit(tid, 2, &iplist[0], 0);
1007
1008       out3:
1009         txEnd(tid);
1010         up(&JFS_IP(dip)->commit_sem);
1011         up(&JFS_IP(ip)->commit_sem);
1012         if (rc) {
1013                 ip->i_nlink = 0;
1014                 iput(ip);
1015         } else
1016                 d_instantiate(dentry, ip);
1017
1018       out2:
1019         free_UCSname(&dname);
1020
1021 #ifdef CONFIG_JFS_POSIX_ACL
1022         if (rc == 0)
1023                 jfs_init_acl(ip, dip);
1024 #endif
1025
1026       out1:
1027         jfs_info("jfs_symlink: rc:%d", rc);
1028         return rc;
1029 }
1030
1031
1032 /*
1033  * NAME:        jfs_rename
1034  *
1035  * FUNCTION:    rename a file or directory
1036  */
1037 static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
1038                struct inode *new_dir, struct dentry *new_dentry)
1039 {
1040         struct btstack btstack;
1041         ino_t ino;
1042         struct component_name new_dname;
1043         struct inode *new_ip;
1044         struct component_name old_dname;
1045         struct inode *old_ip;
1046         int rc;
1047         tid_t tid;
1048         struct tlock *tlck;
1049         struct dt_lock *dtlck;
1050         struct lv *lv;
1051         int ipcount;
1052         struct inode *iplist[4];
1053         struct tblock *tblk;
1054         s64 new_size = 0;
1055         int commit_flag;
1056
1057
1058         jfs_info("jfs_rename: %s %s", old_dentry->d_name.name,
1059                  new_dentry->d_name.name);
1060
1061         old_ip = old_dentry->d_inode;
1062         new_ip = new_dentry->d_inode;
1063
1064         if ((rc = get_UCSname(&old_dname, old_dentry)))
1065                 goto out1;
1066
1067         if ((rc = get_UCSname(&new_dname, new_dentry)))
1068                 goto out2;
1069
1070         /*
1071          * Make sure source inode number is what we think it is
1072          */
1073         rc = dtSearch(old_dir, &old_dname, &ino, &btstack, JFS_LOOKUP);
1074         if (rc || (ino != old_ip->i_ino)) {
1075                 rc = -ENOENT;
1076                 goto out3;
1077         }
1078
1079         /*
1080          * Make sure dest inode number (if any) is what we think it is
1081          */
1082         rc = dtSearch(new_dir, &new_dname, &ino, &btstack, JFS_LOOKUP);
1083         if (rc == 0) {
1084                 if ((new_ip == 0) || (ino != new_ip->i_ino)) {
1085                         rc = -ESTALE;
1086                         goto out3;
1087                 }
1088         } else if (rc != -ENOENT)
1089                 goto out3;
1090         else if (new_ip) {
1091                 /* no entry exists, but one was expected */
1092                 rc = -ESTALE;
1093                 goto out3;
1094         }
1095
1096         if (S_ISDIR(old_ip->i_mode)) {
1097                 if (new_ip) {
1098                         if (!dtEmpty(new_ip)) {
1099                                 rc = -ENOTEMPTY;
1100                                 goto out3;
1101                         }
1102                 } else if ((new_dir != old_dir) &&
1103                            (new_dir->i_nlink == JFS_LINK_MAX)) {
1104                         rc = -EMLINK;
1105                         goto out3;
1106                 }
1107         } else if (new_ip)
1108                 IWRITE_LOCK(new_ip);
1109
1110         /*
1111          * The real work starts here
1112          */
1113         tid = txBegin(new_dir->i_sb, 0);
1114
1115         down(&JFS_IP(new_dir)->commit_sem);
1116         down(&JFS_IP(old_ip)->commit_sem);
1117         if (old_dir != new_dir)
1118                 down(&JFS_IP(old_dir)->commit_sem);
1119
1120         if (new_ip) {
1121                 down(&JFS_IP(new_ip)->commit_sem);
1122                 /*
1123                  * Change existing directory entry to new inode number
1124                  */
1125                 ino = new_ip->i_ino;
1126                 rc = dtModify(tid, new_dir, &new_dname, &ino,
1127                               old_ip->i_ino, JFS_RENAME);
1128                 if (rc)
1129                         goto out4;
1130                 new_ip->i_nlink--;
1131                 if (S_ISDIR(new_ip->i_mode)) {
1132                         new_ip->i_nlink--;
1133                         if (new_ip->i_nlink) {
1134                                 up(&JFS_IP(new_dir)->commit_sem);
1135                                 up(&JFS_IP(old_ip)->commit_sem);
1136                                 if (old_dir != new_dir)
1137                                         up(&JFS_IP(old_dir)->commit_sem);
1138                                 if (!S_ISDIR(old_ip->i_mode) && new_ip)
1139                                         IWRITE_UNLOCK(new_ip);
1140                                 jfs_error(new_ip->i_sb,
1141                                           "jfs_rename: new_ip->i_nlink != 0");
1142                                 return -EIO;
1143                         }
1144                         tblk = tid_to_tblock(tid);
1145                         tblk->xflag |= COMMIT_DELETE;
1146                         tblk->u.ip = new_ip;
1147                 } else if (new_ip->i_nlink == 0) {
1148                         assert(!test_cflag(COMMIT_Nolink, new_ip));
1149                         /* free block resources */
1150                         if ((new_size = commitZeroLink(tid, new_ip)) < 0) {
1151                                 txAbort(tid, 1);        /* Marks FS Dirty */
1152                                 rc = new_size;          
1153                                 goto out4;
1154                         }
1155                         tblk = tid_to_tblock(tid);
1156                         tblk->xflag |= COMMIT_DELETE;
1157                         tblk->u.ip = new_ip;
1158                 } else {
1159                         new_ip->i_ctime = CURRENT_TIME;
1160                         mark_inode_dirty(new_ip);
1161                 }
1162         } else {
1163                 /*
1164                  * Add new directory entry
1165                  */
1166                 rc = dtSearch(new_dir, &new_dname, &ino, &btstack,
1167                               JFS_CREATE);
1168                 if (rc) {
1169                         jfs_err("jfs_rename didn't expect dtSearch to fail "
1170                                 "w/rc = %d", rc);
1171                         goto out4;
1172                 }
1173
1174                 ino = old_ip->i_ino;
1175                 rc = dtInsert(tid, new_dir, &new_dname, &ino, &btstack);
1176                 if (rc) {
1177                         jfs_err("jfs_rename: dtInsert failed w/rc = %d",
1178                                 rc);
1179                         goto out4;
1180                 }
1181                 if (S_ISDIR(old_ip->i_mode))
1182                         new_dir->i_nlink++;
1183         }
1184         /*
1185          * Remove old directory entry
1186          */
1187
1188         ino = old_ip->i_ino;
1189         rc = dtDelete(tid, old_dir, &old_dname, &ino, JFS_REMOVE);
1190         if (rc) {
1191                 jfs_err("jfs_rename did not expect dtDelete to return rc = %d",
1192                         rc);
1193                 txAbort(tid, 1);        /* Marks Filesystem dirty */
1194                 goto out4;
1195         }
1196         if (S_ISDIR(old_ip->i_mode)) {
1197                 old_dir->i_nlink--;
1198                 if (old_dir != new_dir) {
1199                         /*
1200                          * Change inode number of parent for moved directory
1201                          */
1202
1203                         JFS_IP(old_ip)->i_dtroot.header.idotdot =
1204                                 cpu_to_le32(new_dir->i_ino);
1205
1206                         /* Linelock header of dtree */
1207                         tlck = txLock(tid, old_ip,
1208                                     (struct metapage *) &JFS_IP(old_ip)->bxflag,
1209                                       tlckDTREE | tlckBTROOT | tlckRELINK);
1210                         dtlck = (struct dt_lock *) & tlck->lock;
1211                         ASSERT(dtlck->index == 0);
1212                         lv = & dtlck->lv[0];
1213                         lv->offset = 0;
1214                         lv->length = 1;
1215                         dtlck->index++;
1216                 }
1217         }
1218
1219         /*
1220          * Update ctime on changed/moved inodes & mark dirty
1221          */
1222         old_ip->i_ctime = CURRENT_TIME;
1223         mark_inode_dirty(old_ip);
1224
1225         new_dir->i_ctime = new_dir->i_mtime = CURRENT_TIME;
1226         mark_inode_dirty(new_dir);
1227
1228         /* Build list of inodes modified by this transaction */
1229         ipcount = 0;
1230         iplist[ipcount++] = old_ip;
1231         if (new_ip)
1232                 iplist[ipcount++] = new_ip;
1233         iplist[ipcount++] = old_dir;
1234
1235         if (old_dir != new_dir) {
1236                 iplist[ipcount++] = new_dir;
1237                 old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
1238                 mark_inode_dirty(old_dir);
1239         }
1240
1241         /*
1242          * Incomplete truncate of file data can
1243          * result in timing problems unless we synchronously commit the
1244          * transaction.
1245          */
1246         if (new_size)
1247                 commit_flag = COMMIT_SYNC;
1248         else
1249                 commit_flag = 0;
1250
1251         rc = txCommit(tid, ipcount, iplist, commit_flag);
1252
1253       out4:
1254         txEnd(tid);
1255
1256         up(&JFS_IP(new_dir)->commit_sem);
1257         up(&JFS_IP(old_ip)->commit_sem);
1258         if (old_dir != new_dir)
1259                 up(&JFS_IP(old_dir)->commit_sem);
1260         if (new_ip)
1261                 up(&JFS_IP(new_ip)->commit_sem);
1262
1263         while (new_size && (rc == 0)) {
1264                 tid = txBegin(new_ip->i_sb, 0);
1265                 down(&JFS_IP(new_ip)->commit_sem);
1266                 new_size = xtTruncate_pmap(tid, new_ip, new_size);
1267                 if (new_size < 0) {
1268                         txAbort(tid, 1);
1269                         rc = new_size;          
1270                 } else
1271                         rc = txCommit(tid, 1, &new_ip, COMMIT_SYNC);
1272                 txEnd(tid);
1273                 up(&JFS_IP(new_ip)->commit_sem);
1274         }
1275         if (new_ip && (new_ip->i_nlink == 0))
1276                 set_cflag(COMMIT_Nolink, new_ip);
1277       out3:
1278         free_UCSname(&new_dname);
1279       out2:
1280         free_UCSname(&old_dname);
1281       out1:
1282         if (new_ip && !S_ISDIR(new_ip->i_mode))
1283                 IWRITE_UNLOCK(new_ip);
1284         /*
1285          * Truncating the directory index table is not guaranteed.  It
1286          * may need to be done iteratively
1287          */
1288         if (test_cflag(COMMIT_Stale, old_dir)) {
1289                 if (old_dir->i_size > 1)
1290                         jfs_truncate_nolock(old_dir, 0);
1291
1292                 clear_cflag(COMMIT_Stale, old_dir);
1293         }
1294
1295         jfs_info("jfs_rename: returning %d", rc);
1296         return rc;
1297 }
1298
1299
1300 /*
1301  * NAME:        jfs_mknod
1302  *
1303  * FUNCTION:    Create a special file (device)
1304  */
1305 static int jfs_mknod(struct inode *dir, struct dentry *dentry,
1306                 int mode, dev_t rdev)
1307 {
1308         struct jfs_inode_info *jfs_ip;
1309         struct btstack btstack;
1310         struct component_name dname;
1311         ino_t ino;
1312         struct inode *ip;
1313         struct inode *iplist[2];
1314         int rc;
1315         tid_t tid;
1316         struct tblock *tblk;
1317
1318         if (!new_valid_dev(rdev))
1319                 return -EINVAL;
1320
1321         jfs_info("jfs_mknod: %s", dentry->d_name.name);
1322
1323         if ((rc = get_UCSname(&dname, dentry)))
1324                 goto out;
1325
1326         ip = ialloc(dir, mode);
1327         if (ip == NULL) {
1328                 rc = -ENOSPC;
1329                 goto out1;
1330         }
1331         jfs_ip = JFS_IP(ip);
1332
1333         tid = txBegin(dir->i_sb, 0);
1334
1335         down(&JFS_IP(dir)->commit_sem);
1336         down(&JFS_IP(ip)->commit_sem);
1337
1338         if ((rc = dtSearch(dir, &dname, &ino, &btstack, JFS_CREATE)))
1339                 goto out3;
1340
1341         tblk = tid_to_tblock(tid);
1342         tblk->xflag |= COMMIT_CREATE;
1343         tblk->ino = ip->i_ino;
1344         tblk->u.ixpxd = JFS_IP(ip)->ixpxd;
1345
1346         ino = ip->i_ino;
1347         if ((rc = dtInsert(tid, dir, &dname, &ino, &btstack)))
1348                 goto out3;
1349
1350         ip->i_op = &jfs_file_inode_operations;
1351         jfs_ip->dev = new_encode_dev(rdev);
1352         init_special_inode(ip, ip->i_mode, rdev);
1353
1354         insert_inode_hash(ip);
1355         mark_inode_dirty(ip);
1356
1357         dir->i_ctime = dir->i_mtime = CURRENT_TIME;
1358
1359         mark_inode_dirty(dir);
1360
1361         iplist[0] = dir;
1362         iplist[1] = ip;
1363         rc = txCommit(tid, 2, iplist, 0);
1364
1365       out3:
1366         txEnd(tid);
1367         up(&JFS_IP(ip)->commit_sem);
1368         up(&JFS_IP(dir)->commit_sem);
1369         if (rc) {
1370                 ip->i_nlink = 0;
1371                 iput(ip);
1372         } else
1373                 d_instantiate(dentry, ip);
1374
1375       out1:
1376         free_UCSname(&dname);
1377
1378 #ifdef CONFIG_JFS_POSIX_ACL
1379         if (rc == 0)
1380                 jfs_init_acl(ip, dir);
1381 #endif
1382
1383       out:
1384         jfs_info("jfs_mknod: returning %d", rc);
1385         return rc;
1386 }
1387
1388 static struct dentry *jfs_lookup(struct inode *dip, struct dentry *dentry, struct nameidata *nd)
1389 {
1390         struct btstack btstack;
1391         ino_t inum;
1392         struct inode *ip;
1393         struct component_name key;
1394         const char *name = dentry->d_name.name;
1395         int len = dentry->d_name.len;
1396         int rc;
1397
1398         jfs_info("jfs_lookup: name = %s", name);
1399
1400
1401         if ((name[0] == '.') && (len == 1))
1402                 inum = dip->i_ino;
1403         else if (strcmp(name, "..") == 0)
1404                 inum = PARENT(dip);
1405         else {
1406                 if ((rc = get_UCSname(&key, dentry)))
1407                         return ERR_PTR(rc);
1408                 rc = dtSearch(dip, &key, &inum, &btstack, JFS_LOOKUP);
1409                 free_UCSname(&key);
1410                 if (rc == -ENOENT) {
1411                         d_add(dentry, NULL);
1412                         return ERR_PTR(0);
1413                 } else if (rc) {
1414                         jfs_err("jfs_lookup: dtSearch returned %d", rc);
1415                         return ERR_PTR(rc);
1416                 }
1417         }
1418
1419         ip = iget(dip->i_sb, inum);
1420         if (ip == NULL || is_bad_inode(ip)) {
1421                 jfs_err("jfs_lookup: iget failed on inum %d", (uint) inum);
1422                 if (ip)
1423                         iput(ip);
1424                 return ERR_PTR(-EACCES);
1425         }
1426
1427         if (JFS_SBI(dip->i_sb)->mntflag & JFS_OS2)
1428                 dentry->d_op = &jfs_ci_dentry_operations;
1429
1430         dentry = d_splice_alias(ip, dentry);
1431
1432         if (dentry && (JFS_SBI(dip->i_sb)->mntflag & JFS_OS2))
1433                 dentry->d_op = &jfs_ci_dentry_operations;
1434
1435         return dentry;
1436 }
1437
1438 struct dentry *jfs_get_parent(struct dentry *dentry)
1439 {
1440         struct super_block *sb = dentry->d_inode->i_sb;
1441         struct dentry *parent = ERR_PTR(-ENOENT);
1442         struct inode *inode;
1443         unsigned long parent_ino;
1444
1445         parent_ino =
1446                 le32_to_cpu(JFS_IP(dentry->d_inode)->i_dtroot.header.idotdot);
1447         inode = iget(sb, parent_ino);
1448         if (inode) {
1449                 if (is_bad_inode(inode)) {
1450                         iput(inode);
1451                         parent = ERR_PTR(-EACCES);
1452                 } else {
1453                         parent = d_alloc_anon(inode);
1454                         if (!parent) {
1455                                 parent = ERR_PTR(-ENOMEM);
1456                                 iput(inode);
1457                         }
1458                 }
1459         }
1460
1461         return parent;
1462 }
1463
1464 struct inode_operations jfs_dir_inode_operations = {
1465         .create         = jfs_create,
1466         .lookup         = jfs_lookup,
1467         .link           = jfs_link,
1468         .unlink         = jfs_unlink,
1469         .symlink        = jfs_symlink,
1470         .mkdir          = jfs_mkdir,
1471         .rmdir          = jfs_rmdir,
1472         .mknod          = jfs_mknod,
1473         .rename         = jfs_rename,
1474         .setxattr       = jfs_setxattr,
1475         .getxattr       = jfs_getxattr,
1476         .listxattr      = jfs_listxattr,
1477         .removexattr    = jfs_removexattr,
1478 #ifdef CONFIG_JFS_POSIX_ACL
1479         .setattr        = jfs_setattr,
1480         .permission     = jfs_permission,
1481 #endif
1482 };
1483
1484 struct file_operations jfs_dir_operations = {
1485         .read           = generic_read_dir,
1486         .readdir        = jfs_readdir,
1487         .fsync          = jfs_fsync,
1488 };
1489
1490 static int jfs_ci_hash(struct dentry *dir, struct qstr *this)
1491 {
1492         unsigned long hash;
1493         int i;
1494
1495         hash = init_name_hash();
1496         for (i=0; i < this->len; i++)
1497                 hash = partial_name_hash(tolower(this->name[i]), hash);
1498         this->hash = end_name_hash(hash);
1499
1500         return 0;
1501 }
1502
1503 static int jfs_ci_compare(struct dentry *dir, struct qstr *a, struct qstr *b)
1504 {
1505         int i, result = 1;
1506
1507         if (a->len != b->len)
1508                 goto out;
1509         for (i=0; i < a->len; i++) {
1510                 if (tolower(a->name[i]) != tolower(b->name[i]))
1511                         goto out;
1512         }
1513         result = 0;
1514
1515         /*
1516          * We want creates to preserve case.  A negative dentry, a, that
1517          * has a different case than b may cause a new entry to be created
1518          * with the wrong case.  Since we can't tell if a comes from a negative
1519          * dentry, we blindly replace it with b.  This should be harmless if
1520          * a is not a negative dentry.
1521          */
1522         memcpy((unsigned char *)a->name, b->name, a->len);
1523 out:
1524         return result;
1525 }
1526
1527 struct dentry_operations jfs_ci_dentry_operations =
1528 {
1529         .d_hash = jfs_ci_hash,
1530         .d_compare = jfs_ci_compare,
1531 };