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