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