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