11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * Copyright (C) International Business Machines Corp., 2000-2004
41da177e4SLinus Torvalds * Portions Copyright (C) Christoph Hellwig, 2001-2002
51da177e4SLinus Torvalds */
61da177e4SLinus Torvalds
71da177e4SLinus Torvalds #include <linux/fs.h>
82bc334dcSNick Piggin #include <linux/namei.h>
91da177e4SLinus Torvalds #include <linux/ctype.h>
101da177e4SLinus Torvalds #include <linux/quotaops.h>
11d425de70SChristoph Hellwig #include <linux/exportfs.h>
121da177e4SLinus Torvalds #include "jfs_incore.h"
131da177e4SLinus Torvalds #include "jfs_superblock.h"
141da177e4SLinus Torvalds #include "jfs_inode.h"
151da177e4SLinus Torvalds #include "jfs_dinode.h"
161da177e4SLinus Torvalds #include "jfs_dmap.h"
171da177e4SLinus Torvalds #include "jfs_unicode.h"
181da177e4SLinus Torvalds #include "jfs_metapage.h"
191da177e4SLinus Torvalds #include "jfs_xattr.h"
201da177e4SLinus Torvalds #include "jfs_acl.h"
211da177e4SLinus Torvalds #include "jfs_debug.h"
221da177e4SLinus Torvalds
231da177e4SLinus Torvalds /*
241da177e4SLinus Torvalds * forward references
251da177e4SLinus Torvalds */
26ad28b4efSAl Viro const struct dentry_operations jfs_ci_dentry_operations;
271da177e4SLinus Torvalds
281da177e4SLinus Torvalds static s64 commitZeroLink(tid_t, struct inode *);
291da177e4SLinus Torvalds
301da177e4SLinus Torvalds /*
314f4b401bSDave Kleikamp * NAME: free_ea_wmap(inode)
324f4b401bSDave Kleikamp *
334f4b401bSDave Kleikamp * FUNCTION: free uncommitted extended attributes from working map
344f4b401bSDave Kleikamp *
354f4b401bSDave Kleikamp */
free_ea_wmap(struct inode * inode)364f4b401bSDave Kleikamp static inline void free_ea_wmap(struct inode *inode)
374f4b401bSDave Kleikamp {
384f4b401bSDave Kleikamp dxd_t *ea = &JFS_IP(inode)->ea;
394f4b401bSDave Kleikamp
404f4b401bSDave Kleikamp if (ea->flag & DXD_EXTENT) {
414f4b401bSDave Kleikamp /* free EA pages from cache */
424f4b401bSDave Kleikamp invalidate_dxd_metapages(inode, *ea);
434f4b401bSDave Kleikamp dbFree(inode, addressDXD(ea), lengthDXD(ea));
444f4b401bSDave Kleikamp }
454f4b401bSDave Kleikamp ea->flag = 0;
464f4b401bSDave Kleikamp }
474f4b401bSDave Kleikamp
484f4b401bSDave Kleikamp /*
491da177e4SLinus Torvalds * NAME: jfs_create(dip, dentry, mode)
501da177e4SLinus Torvalds *
511da177e4SLinus Torvalds * FUNCTION: create a regular file in the parent directory <dip>
521da177e4SLinus Torvalds * with name = <from dentry> and mode = <mode>
531da177e4SLinus Torvalds *
541da177e4SLinus Torvalds * PARAMETER: dip - parent directory vnode
551da177e4SLinus Torvalds * dentry - dentry of new file
561da177e4SLinus Torvalds * mode - create mode (rwxrwxrwx).
571da177e4SLinus Torvalds * nd- nd struct
581da177e4SLinus Torvalds *
591da177e4SLinus Torvalds * RETURN: Errors from subroutines
601da177e4SLinus Torvalds *
611da177e4SLinus Torvalds */
jfs_create(struct mnt_idmap * idmap,struct inode * dip,struct dentry * dentry,umode_t mode,bool excl)626c960e68SChristian Brauner static int jfs_create(struct mnt_idmap *idmap, struct inode *dip,
63549c7297SChristian Brauner struct dentry *dentry, umode_t mode, bool excl)
641da177e4SLinus Torvalds {
651da177e4SLinus Torvalds int rc = 0;
661da177e4SLinus Torvalds tid_t tid; /* transaction id */
671da177e4SLinus Torvalds struct inode *ip = NULL; /* child directory inode */
681da177e4SLinus Torvalds ino_t ino;
691da177e4SLinus Torvalds struct component_name dname; /* child directory name */
701da177e4SLinus Torvalds struct btstack btstack;
711da177e4SLinus Torvalds struct inode *iplist[2];
721da177e4SLinus Torvalds struct tblock *tblk;
731da177e4SLinus Torvalds
74a455589fSAl Viro jfs_info("jfs_create: dip:0x%p name:%pd", dip, dentry);
751da177e4SLinus Torvalds
76acc84b05SDave Kleikamp rc = dquot_initialize(dip);
77acc84b05SDave Kleikamp if (rc)
78acc84b05SDave Kleikamp goto out1;
79907f4554SChristoph Hellwig
801da177e4SLinus Torvalds /*
811da177e4SLinus Torvalds * search parent directory for entry/freespace
821da177e4SLinus Torvalds * (dtSearch() returns parent directory page pinned)
831da177e4SLinus Torvalds */
841da177e4SLinus Torvalds if ((rc = get_UCSname(&dname, dentry)))
851da177e4SLinus Torvalds goto out1;
861da177e4SLinus Torvalds
871da177e4SLinus Torvalds /*
881da177e4SLinus Torvalds * Either iAlloc() or txBegin() may block. Deadlock can occur if we
891da177e4SLinus Torvalds * block there while holding dtree page, so we allocate the inode &
901da177e4SLinus Torvalds * begin the transaction before we search the directory.
911da177e4SLinus Torvalds */
921da177e4SLinus Torvalds ip = ialloc(dip, mode);
93087387f9SAkinobu Mita if (IS_ERR(ip)) {
94087387f9SAkinobu Mita rc = PTR_ERR(ip);
951da177e4SLinus Torvalds goto out2;
961da177e4SLinus Torvalds }
971da177e4SLinus Torvalds
981da177e4SLinus Torvalds tid = txBegin(dip->i_sb, 0);
991da177e4SLinus Torvalds
10082d5b9a7SDave Kleikamp mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);
10182d5b9a7SDave Kleikamp mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
1021da177e4SLinus Torvalds
1034f4b401bSDave Kleikamp rc = jfs_init_acl(tid, ip, dip);
1044f4b401bSDave Kleikamp if (rc)
1054f4b401bSDave Kleikamp goto out3;
1064f4b401bSDave Kleikamp
1072a7dba39SEric Paris rc = jfs_init_security(tid, ip, dip, &dentry->d_name);
1081d15b10fSDave Kleikamp if (rc) {
1091d15b10fSDave Kleikamp txAbort(tid, 0);
1101d15b10fSDave Kleikamp goto out3;
1111d15b10fSDave Kleikamp }
1121d15b10fSDave Kleikamp
1131da177e4SLinus Torvalds if ((rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE))) {
1141da177e4SLinus Torvalds jfs_err("jfs_create: dtSearch returned %d", rc);
1154f4b401bSDave Kleikamp txAbort(tid, 0);
1161da177e4SLinus Torvalds goto out3;
1171da177e4SLinus Torvalds }
1181da177e4SLinus Torvalds
1191da177e4SLinus Torvalds tblk = tid_to_tblock(tid);
1201da177e4SLinus Torvalds tblk->xflag |= COMMIT_CREATE;
1211da177e4SLinus Torvalds tblk->ino = ip->i_ino;
1221da177e4SLinus Torvalds tblk->u.ixpxd = JFS_IP(ip)->ixpxd;
1231da177e4SLinus Torvalds
1241da177e4SLinus Torvalds iplist[0] = dip;
1251da177e4SLinus Torvalds iplist[1] = ip;
1261da177e4SLinus Torvalds
1271da177e4SLinus Torvalds /*
1281da177e4SLinus Torvalds * initialize the child XAD tree root in-line in inode
1291da177e4SLinus Torvalds */
1301da177e4SLinus Torvalds xtInitRoot(tid, ip);
1311da177e4SLinus Torvalds
1321da177e4SLinus Torvalds /*
1331da177e4SLinus Torvalds * create entry in parent directory for child directory
1341da177e4SLinus Torvalds * (dtInsert() releases parent directory page)
1351da177e4SLinus Torvalds */
1361da177e4SLinus Torvalds ino = ip->i_ino;
1371da177e4SLinus Torvalds if ((rc = dtInsert(tid, dip, &dname, &ino, &btstack))) {
1381da177e4SLinus Torvalds if (rc == -EIO) {
1391da177e4SLinus Torvalds jfs_err("jfs_create: dtInsert returned -EIO");
1401da177e4SLinus Torvalds txAbort(tid, 1); /* Marks Filesystem dirty */
1411da177e4SLinus Torvalds } else
1421da177e4SLinus Torvalds txAbort(tid, 0); /* Filesystem full */
1431da177e4SLinus Torvalds goto out3;
1441da177e4SLinus Torvalds }
1451da177e4SLinus Torvalds
1461da177e4SLinus Torvalds ip->i_op = &jfs_file_inode_operations;
1471da177e4SLinus Torvalds ip->i_fop = &jfs_file_operations;
1481da177e4SLinus Torvalds ip->i_mapping->a_ops = &jfs_aops;
1491da177e4SLinus Torvalds
1501da177e4SLinus Torvalds mark_inode_dirty(ip);
1511da177e4SLinus Torvalds
152ad9dc5dfSJeff Layton dip->i_mtime = inode_set_ctime_current(dip);
1531da177e4SLinus Torvalds
1541da177e4SLinus Torvalds mark_inode_dirty(dip);
1551da177e4SLinus Torvalds
1561da177e4SLinus Torvalds rc = txCommit(tid, 2, &iplist[0], 0);
1571da177e4SLinus Torvalds
1581da177e4SLinus Torvalds out3:
1591da177e4SLinus Torvalds txEnd(tid);
1601de87444SIngo Molnar mutex_unlock(&JFS_IP(ip)->commit_mutex);
16148ce8b05SEvgeniy Dushistov mutex_unlock(&JFS_IP(dip)->commit_mutex);
1621da177e4SLinus Torvalds if (rc) {
1634f4b401bSDave Kleikamp free_ea_wmap(ip);
1646d6b77f1SMiklos Szeredi clear_nlink(ip);
165a6cbedfaSAl Viro discard_new_inode(ip);
1661f3403faSDave Kleikamp } else {
1671e2e547aSAl Viro d_instantiate_new(dentry, ip);
1681f3403faSDave Kleikamp }
1691da177e4SLinus Torvalds
1701da177e4SLinus Torvalds out2:
1711da177e4SLinus Torvalds free_UCSname(&dname);
1721da177e4SLinus Torvalds
1731da177e4SLinus Torvalds out1:
1741da177e4SLinus Torvalds
1751da177e4SLinus Torvalds jfs_info("jfs_create: rc:%d", rc);
1761da177e4SLinus Torvalds return rc;
1771da177e4SLinus Torvalds }
1781da177e4SLinus Torvalds
1791da177e4SLinus Torvalds
1801da177e4SLinus Torvalds /*
1811da177e4SLinus Torvalds * NAME: jfs_mkdir(dip, dentry, mode)
1821da177e4SLinus Torvalds *
1831da177e4SLinus Torvalds * FUNCTION: create a child directory in the parent directory <dip>
1841da177e4SLinus Torvalds * with name = <from dentry> and mode = <mode>
1851da177e4SLinus Torvalds *
1861da177e4SLinus Torvalds * PARAMETER: dip - parent directory vnode
1871da177e4SLinus Torvalds * dentry - dentry of child directory
1881da177e4SLinus Torvalds * mode - create mode (rwxrwxrwx).
1891da177e4SLinus Torvalds *
1901da177e4SLinus Torvalds * RETURN: Errors from subroutines
1911da177e4SLinus Torvalds *
1921da177e4SLinus Torvalds * note:
193a83722f4SColin Ian King * EACCES: user needs search+write permission on the parent directory
1941da177e4SLinus Torvalds */
jfs_mkdir(struct mnt_idmap * idmap,struct inode * dip,struct dentry * dentry,umode_t mode)195c54bd91eSChristian Brauner static int jfs_mkdir(struct mnt_idmap *idmap, struct inode *dip,
196549c7297SChristian Brauner struct dentry *dentry, umode_t mode)
1971da177e4SLinus Torvalds {
1981da177e4SLinus Torvalds int rc = 0;
1991da177e4SLinus Torvalds tid_t tid; /* transaction id */
2001da177e4SLinus Torvalds struct inode *ip = NULL; /* child directory inode */
2011da177e4SLinus Torvalds ino_t ino;
2021da177e4SLinus Torvalds struct component_name dname; /* child directory name */
2031da177e4SLinus Torvalds struct btstack btstack;
2041da177e4SLinus Torvalds struct inode *iplist[2];
2051da177e4SLinus Torvalds struct tblock *tblk;
2061da177e4SLinus Torvalds
207a455589fSAl Viro jfs_info("jfs_mkdir: dip:0x%p name:%pd", dip, dentry);
2081da177e4SLinus Torvalds
209acc84b05SDave Kleikamp rc = dquot_initialize(dip);
210acc84b05SDave Kleikamp if (rc)
211acc84b05SDave Kleikamp goto out1;
212907f4554SChristoph Hellwig
2131da177e4SLinus Torvalds /*
2141da177e4SLinus Torvalds * search parent directory for entry/freespace
2151da177e4SLinus Torvalds * (dtSearch() returns parent directory page pinned)
2161da177e4SLinus Torvalds */
2171da177e4SLinus Torvalds if ((rc = get_UCSname(&dname, dentry)))
2181da177e4SLinus Torvalds goto out1;
2191da177e4SLinus Torvalds
2201da177e4SLinus Torvalds /*
2211da177e4SLinus Torvalds * Either iAlloc() or txBegin() may block. Deadlock can occur if we
2221da177e4SLinus Torvalds * block there while holding dtree page, so we allocate the inode &
2231da177e4SLinus Torvalds * begin the transaction before we search the directory.
2241da177e4SLinus Torvalds */
2251da177e4SLinus Torvalds ip = ialloc(dip, S_IFDIR | mode);
226087387f9SAkinobu Mita if (IS_ERR(ip)) {
227087387f9SAkinobu Mita rc = PTR_ERR(ip);
2281da177e4SLinus Torvalds goto out2;
2291da177e4SLinus Torvalds }
2301da177e4SLinus Torvalds
2311da177e4SLinus Torvalds tid = txBegin(dip->i_sb, 0);
2321da177e4SLinus Torvalds
23382d5b9a7SDave Kleikamp mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);
23482d5b9a7SDave Kleikamp mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
2351da177e4SLinus Torvalds
2364f4b401bSDave Kleikamp rc = jfs_init_acl(tid, ip, dip);
2374f4b401bSDave Kleikamp if (rc)
2384f4b401bSDave Kleikamp goto out3;
2394f4b401bSDave Kleikamp
2402a7dba39SEric Paris rc = jfs_init_security(tid, ip, dip, &dentry->d_name);
2411d15b10fSDave Kleikamp if (rc) {
2421d15b10fSDave Kleikamp txAbort(tid, 0);
2431d15b10fSDave Kleikamp goto out3;
2441d15b10fSDave Kleikamp }
2451d15b10fSDave Kleikamp
2461da177e4SLinus Torvalds if ((rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE))) {
2471da177e4SLinus Torvalds jfs_err("jfs_mkdir: dtSearch returned %d", rc);
2484f4b401bSDave Kleikamp txAbort(tid, 0);
2491da177e4SLinus Torvalds goto out3;
2501da177e4SLinus Torvalds }
2511da177e4SLinus Torvalds
2521da177e4SLinus Torvalds tblk = tid_to_tblock(tid);
2531da177e4SLinus Torvalds tblk->xflag |= COMMIT_CREATE;
2541da177e4SLinus Torvalds tblk->ino = ip->i_ino;
2551da177e4SLinus Torvalds tblk->u.ixpxd = JFS_IP(ip)->ixpxd;
2561da177e4SLinus Torvalds
2571da177e4SLinus Torvalds iplist[0] = dip;
2581da177e4SLinus Torvalds iplist[1] = ip;
2591da177e4SLinus Torvalds
2601da177e4SLinus Torvalds /*
2611da177e4SLinus Torvalds * initialize the child directory in-line in inode
2621da177e4SLinus Torvalds */
2631da177e4SLinus Torvalds dtInitRoot(tid, ip, dip->i_ino);
2641da177e4SLinus Torvalds
2651da177e4SLinus Torvalds /*
2661da177e4SLinus Torvalds * create entry in parent directory for child directory
2671da177e4SLinus Torvalds * (dtInsert() releases parent directory page)
2681da177e4SLinus Torvalds */
2691da177e4SLinus Torvalds ino = ip->i_ino;
2701da177e4SLinus Torvalds if ((rc = dtInsert(tid, dip, &dname, &ino, &btstack))) {
2711da177e4SLinus Torvalds if (rc == -EIO) {
2721da177e4SLinus Torvalds jfs_err("jfs_mkdir: dtInsert returned -EIO");
2731da177e4SLinus Torvalds txAbort(tid, 1); /* Marks Filesystem dirty */
2741da177e4SLinus Torvalds } else
2751da177e4SLinus Torvalds txAbort(tid, 0); /* Filesystem full */
2761da177e4SLinus Torvalds goto out3;
2771da177e4SLinus Torvalds }
2781da177e4SLinus Torvalds
279bfe86848SMiklos Szeredi set_nlink(ip, 2); /* for '.' */
2801da177e4SLinus Torvalds ip->i_op = &jfs_dir_inode_operations;
2811da177e4SLinus Torvalds ip->i_fop = &jfs_dir_operations;
2821da177e4SLinus Torvalds
2831da177e4SLinus Torvalds mark_inode_dirty(ip);
2841da177e4SLinus Torvalds
2851da177e4SLinus Torvalds /* update parent directory inode */
286d8c76e6fSDave Hansen inc_nlink(dip); /* for '..' from child directory */
287ad9dc5dfSJeff Layton dip->i_mtime = inode_set_ctime_current(dip);
2881da177e4SLinus Torvalds mark_inode_dirty(dip);
2891da177e4SLinus Torvalds
2901da177e4SLinus Torvalds rc = txCommit(tid, 2, &iplist[0], 0);
2911da177e4SLinus Torvalds
2921da177e4SLinus Torvalds out3:
2931da177e4SLinus Torvalds txEnd(tid);
2941de87444SIngo Molnar mutex_unlock(&JFS_IP(ip)->commit_mutex);
29548ce8b05SEvgeniy Dushistov mutex_unlock(&JFS_IP(dip)->commit_mutex);
2961da177e4SLinus Torvalds if (rc) {
2974f4b401bSDave Kleikamp free_ea_wmap(ip);
2986d6b77f1SMiklos Szeredi clear_nlink(ip);
299a6cbedfaSAl Viro discard_new_inode(ip);
3001f3403faSDave Kleikamp } else {
3011e2e547aSAl Viro d_instantiate_new(dentry, ip);
3021f3403faSDave Kleikamp }
3031da177e4SLinus Torvalds
3041da177e4SLinus Torvalds out2:
3051da177e4SLinus Torvalds free_UCSname(&dname);
3061da177e4SLinus Torvalds
3071da177e4SLinus Torvalds
3081da177e4SLinus Torvalds out1:
3091da177e4SLinus Torvalds
3101da177e4SLinus Torvalds jfs_info("jfs_mkdir: rc:%d", rc);
3111da177e4SLinus Torvalds return rc;
3121da177e4SLinus Torvalds }
3131da177e4SLinus Torvalds
3141da177e4SLinus Torvalds /*
3151da177e4SLinus Torvalds * NAME: jfs_rmdir(dip, dentry)
3161da177e4SLinus Torvalds *
3171da177e4SLinus Torvalds * FUNCTION: remove a link to child directory
3181da177e4SLinus Torvalds *
3191da177e4SLinus Torvalds * PARAMETER: dip - parent inode
3201da177e4SLinus Torvalds * dentry - child directory dentry
3211da177e4SLinus Torvalds *
3221da177e4SLinus Torvalds * RETURN: -EINVAL - if name is . or ..
3231da177e4SLinus Torvalds * -EINVAL - if . or .. exist but are invalid.
3241da177e4SLinus Torvalds * errors from subroutines
3251da177e4SLinus Torvalds *
3261da177e4SLinus Torvalds * note:
3271da177e4SLinus Torvalds * if other threads have the directory open when the last link
3281da177e4SLinus Torvalds * is removed, the "." and ".." entries, if present, are removed before
3291da177e4SLinus Torvalds * rmdir() returns and no new entries may be created in the directory,
3301da177e4SLinus Torvalds * but the directory is not removed until the last reference to
3311da177e4SLinus Torvalds * the directory is released (cf.unlink() of regular file).
3321da177e4SLinus Torvalds */
jfs_rmdir(struct inode * dip,struct dentry * dentry)3331da177e4SLinus Torvalds static int jfs_rmdir(struct inode *dip, struct dentry *dentry)
3341da177e4SLinus Torvalds {
3351da177e4SLinus Torvalds int rc;
3361da177e4SLinus Torvalds tid_t tid; /* transaction id */
3372b0143b5SDavid Howells struct inode *ip = d_inode(dentry);
3381da177e4SLinus Torvalds ino_t ino;
3391da177e4SLinus Torvalds struct component_name dname;
3401da177e4SLinus Torvalds struct inode *iplist[2];
3411da177e4SLinus Torvalds struct tblock *tblk;
3421da177e4SLinus Torvalds
343a455589fSAl Viro jfs_info("jfs_rmdir: dip:0x%p name:%pd", dip, dentry);
3441da177e4SLinus Torvalds
3451da177e4SLinus Torvalds /* Init inode for quota operations. */
346acc84b05SDave Kleikamp rc = dquot_initialize(dip);
347acc84b05SDave Kleikamp if (rc)
348acc84b05SDave Kleikamp goto out;
349acc84b05SDave Kleikamp rc = dquot_initialize(ip);
350acc84b05SDave Kleikamp if (rc)
351acc84b05SDave Kleikamp goto out;
3521da177e4SLinus Torvalds
3531da177e4SLinus Torvalds /* directory must be empty to be removed */
3541da177e4SLinus Torvalds if (!dtEmpty(ip)) {
3551da177e4SLinus Torvalds rc = -ENOTEMPTY;
3561da177e4SLinus Torvalds goto out;
3571da177e4SLinus Torvalds }
3581da177e4SLinus Torvalds
3591da177e4SLinus Torvalds if ((rc = get_UCSname(&dname, dentry))) {
3601da177e4SLinus Torvalds goto out;
3611da177e4SLinus Torvalds }
3621da177e4SLinus Torvalds
3631da177e4SLinus Torvalds tid = txBegin(dip->i_sb, 0);
3641da177e4SLinus Torvalds
36582d5b9a7SDave Kleikamp mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);
36682d5b9a7SDave Kleikamp mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
3671da177e4SLinus Torvalds
3681da177e4SLinus Torvalds iplist[0] = dip;
3691da177e4SLinus Torvalds iplist[1] = ip;
3701da177e4SLinus Torvalds
3711da177e4SLinus Torvalds tblk = tid_to_tblock(tid);
3721da177e4SLinus Torvalds tblk->xflag |= COMMIT_DELETE;
3731da177e4SLinus Torvalds tblk->u.ip = ip;
3741da177e4SLinus Torvalds
3751da177e4SLinus Torvalds /*
3761da177e4SLinus Torvalds * delete the entry of target directory from parent directory
3771da177e4SLinus Torvalds */
3781da177e4SLinus Torvalds ino = ip->i_ino;
3791da177e4SLinus Torvalds if ((rc = dtDelete(tid, dip, &dname, &ino, JFS_REMOVE))) {
3801da177e4SLinus Torvalds jfs_err("jfs_rmdir: dtDelete returned %d", rc);
3811da177e4SLinus Torvalds if (rc == -EIO)
3821da177e4SLinus Torvalds txAbort(tid, 1);
3831da177e4SLinus Torvalds txEnd(tid);
3841de87444SIngo Molnar mutex_unlock(&JFS_IP(ip)->commit_mutex);
38548ce8b05SEvgeniy Dushistov mutex_unlock(&JFS_IP(dip)->commit_mutex);
3861da177e4SLinus Torvalds
3871da177e4SLinus Torvalds goto out2;
3881da177e4SLinus Torvalds }
3891da177e4SLinus Torvalds
3901da177e4SLinus Torvalds /* update parent directory's link count corresponding
3911da177e4SLinus Torvalds * to ".." entry of the target directory deleted
3921da177e4SLinus Torvalds */
393ad9dc5dfSJeff Layton dip->i_mtime = inode_set_ctime_current(dip);
3949a53c3a7SDave Hansen inode_dec_link_count(dip);
3951da177e4SLinus Torvalds
3961da177e4SLinus Torvalds /*
3971da177e4SLinus Torvalds * OS/2 could have created EA and/or ACL
3981da177e4SLinus Torvalds */
3991da177e4SLinus Torvalds /* free EA from both persistent and working map */
4001da177e4SLinus Torvalds if (JFS_IP(ip)->ea.flag & DXD_EXTENT) {
4011da177e4SLinus Torvalds /* free EA pages */
4021da177e4SLinus Torvalds txEA(tid, ip, &JFS_IP(ip)->ea, NULL);
4031da177e4SLinus Torvalds }
4041da177e4SLinus Torvalds JFS_IP(ip)->ea.flag = 0;
4051da177e4SLinus Torvalds
4061da177e4SLinus Torvalds /* free ACL from both persistent and working map */
4071da177e4SLinus Torvalds if (JFS_IP(ip)->acl.flag & DXD_EXTENT) {
4081da177e4SLinus Torvalds /* free ACL pages */
4091da177e4SLinus Torvalds txEA(tid, ip, &JFS_IP(ip)->acl, NULL);
4101da177e4SLinus Torvalds }
4111da177e4SLinus Torvalds JFS_IP(ip)->acl.flag = 0;
4121da177e4SLinus Torvalds
4131da177e4SLinus Torvalds /* mark the target directory as deleted */
414ce71ec36SDave Hansen clear_nlink(ip);
4151da177e4SLinus Torvalds mark_inode_dirty(ip);
4161da177e4SLinus Torvalds
4171da177e4SLinus Torvalds rc = txCommit(tid, 2, &iplist[0], 0);
4181da177e4SLinus Torvalds
4191da177e4SLinus Torvalds txEnd(tid);
4201da177e4SLinus Torvalds
4211de87444SIngo Molnar mutex_unlock(&JFS_IP(ip)->commit_mutex);
42248ce8b05SEvgeniy Dushistov mutex_unlock(&JFS_IP(dip)->commit_mutex);
4231da177e4SLinus Torvalds
4241da177e4SLinus Torvalds /*
4251da177e4SLinus Torvalds * Truncating the directory index table is not guaranteed. It
4261da177e4SLinus Torvalds * may need to be done iteratively
4271da177e4SLinus Torvalds */
4281da177e4SLinus Torvalds if (test_cflag(COMMIT_Stale, dip)) {
4291da177e4SLinus Torvalds if (dip->i_size > 1)
4301da177e4SLinus Torvalds jfs_truncate_nolock(dip, 0);
4311da177e4SLinus Torvalds
4321da177e4SLinus Torvalds clear_cflag(COMMIT_Stale, dip);
4331da177e4SLinus Torvalds }
4341da177e4SLinus Torvalds
4351da177e4SLinus Torvalds out2:
4361da177e4SLinus Torvalds free_UCSname(&dname);
4371da177e4SLinus Torvalds
4381da177e4SLinus Torvalds out:
4391da177e4SLinus Torvalds jfs_info("jfs_rmdir: rc:%d", rc);
4401da177e4SLinus Torvalds return rc;
4411da177e4SLinus Torvalds }
4421da177e4SLinus Torvalds
4431da177e4SLinus Torvalds /*
4441da177e4SLinus Torvalds * NAME: jfs_unlink(dip, dentry)
4451da177e4SLinus Torvalds *
4461da177e4SLinus Torvalds * FUNCTION: remove a link to object <vp> named by <name>
4471da177e4SLinus Torvalds * from parent directory <dvp>
4481da177e4SLinus Torvalds *
4491da177e4SLinus Torvalds * PARAMETER: dip - inode of parent directory
4501da177e4SLinus Torvalds * dentry - dentry of object to be removed
4511da177e4SLinus Torvalds *
4521da177e4SLinus Torvalds * RETURN: errors from subroutines
4531da177e4SLinus Torvalds *
4541da177e4SLinus Torvalds * note:
4551da177e4SLinus Torvalds * temporary file: if one or more processes have the file open
4561da177e4SLinus Torvalds * when the last link is removed, the link will be removed before
4571da177e4SLinus Torvalds * unlink() returns, but the removal of the file contents will be
4581da177e4SLinus Torvalds * postponed until all references to the files are closed.
4591da177e4SLinus Torvalds *
4601da177e4SLinus Torvalds * JFS does NOT support unlink() on directories.
4611da177e4SLinus Torvalds *
4621da177e4SLinus Torvalds */
jfs_unlink(struct inode * dip,struct dentry * dentry)4631da177e4SLinus Torvalds static int jfs_unlink(struct inode *dip, struct dentry *dentry)
4641da177e4SLinus Torvalds {
4651da177e4SLinus Torvalds int rc;
4661da177e4SLinus Torvalds tid_t tid; /* transaction id */
4672b0143b5SDavid Howells struct inode *ip = d_inode(dentry);
4681da177e4SLinus Torvalds ino_t ino;
4691da177e4SLinus Torvalds struct component_name dname; /* object name */
4701da177e4SLinus Torvalds struct inode *iplist[2];
4711da177e4SLinus Torvalds struct tblock *tblk;
4721da177e4SLinus Torvalds s64 new_size = 0;
4731da177e4SLinus Torvalds int commit_flag;
4741da177e4SLinus Torvalds
475a455589fSAl Viro jfs_info("jfs_unlink: dip:0x%p name:%pd", dip, dentry);
4761da177e4SLinus Torvalds
4771da177e4SLinus Torvalds /* Init inode for quota operations. */
478acc84b05SDave Kleikamp rc = dquot_initialize(dip);
479acc84b05SDave Kleikamp if (rc)
480acc84b05SDave Kleikamp goto out;
481acc84b05SDave Kleikamp rc = dquot_initialize(ip);
482acc84b05SDave Kleikamp if (rc)
483acc84b05SDave Kleikamp goto out;
4841da177e4SLinus Torvalds
4851da177e4SLinus Torvalds if ((rc = get_UCSname(&dname, dentry)))
4861da177e4SLinus Torvalds goto out;
4871da177e4SLinus Torvalds
48882d5b9a7SDave Kleikamp IWRITE_LOCK(ip, RDWRLOCK_NORMAL);
4891da177e4SLinus Torvalds
4901da177e4SLinus Torvalds tid = txBegin(dip->i_sb, 0);
4911da177e4SLinus Torvalds
49282d5b9a7SDave Kleikamp mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);
49382d5b9a7SDave Kleikamp mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
4941da177e4SLinus Torvalds
4951da177e4SLinus Torvalds iplist[0] = dip;
4961da177e4SLinus Torvalds iplist[1] = ip;
4971da177e4SLinus Torvalds
4981da177e4SLinus Torvalds /*
4991da177e4SLinus Torvalds * delete the entry of target file from parent directory
5001da177e4SLinus Torvalds */
5011da177e4SLinus Torvalds ino = ip->i_ino;
5021da177e4SLinus Torvalds if ((rc = dtDelete(tid, dip, &dname, &ino, JFS_REMOVE))) {
5031da177e4SLinus Torvalds jfs_err("jfs_unlink: dtDelete returned %d", rc);
5041da177e4SLinus Torvalds if (rc == -EIO)
5051da177e4SLinus Torvalds txAbort(tid, 1); /* Marks FS Dirty */
5061da177e4SLinus Torvalds txEnd(tid);
5071de87444SIngo Molnar mutex_unlock(&JFS_IP(ip)->commit_mutex);
50848ce8b05SEvgeniy Dushistov mutex_unlock(&JFS_IP(dip)->commit_mutex);
5091da177e4SLinus Torvalds IWRITE_UNLOCK(ip);
5101da177e4SLinus Torvalds goto out1;
5111da177e4SLinus Torvalds }
5121da177e4SLinus Torvalds
5131da177e4SLinus Torvalds ASSERT(ip->i_nlink);
5141da177e4SLinus Torvalds
515ad9dc5dfSJeff Layton dip->i_mtime = inode_set_ctime_to_ts(dip, inode_set_ctime_current(ip));
5161da177e4SLinus Torvalds mark_inode_dirty(dip);
5171da177e4SLinus Torvalds
5181da177e4SLinus Torvalds /* update target's inode */
5199a53c3a7SDave Hansen inode_dec_link_count(ip);
5201da177e4SLinus Torvalds
5211da177e4SLinus Torvalds /*
5221da177e4SLinus Torvalds * commit zero link count object
5231da177e4SLinus Torvalds */
5241da177e4SLinus Torvalds if (ip->i_nlink == 0) {
5251da177e4SLinus Torvalds assert(!test_cflag(COMMIT_Nolink, ip));
5261da177e4SLinus Torvalds /* free block resources */
5271da177e4SLinus Torvalds if ((new_size = commitZeroLink(tid, ip)) < 0) {
5281da177e4SLinus Torvalds txAbort(tid, 1); /* Marks FS Dirty */
5291da177e4SLinus Torvalds txEnd(tid);
5301de87444SIngo Molnar mutex_unlock(&JFS_IP(ip)->commit_mutex);
53148ce8b05SEvgeniy Dushistov mutex_unlock(&JFS_IP(dip)->commit_mutex);
5321da177e4SLinus Torvalds IWRITE_UNLOCK(ip);
5331da177e4SLinus Torvalds rc = new_size;
5341da177e4SLinus Torvalds goto out1;
5351da177e4SLinus Torvalds }
5361da177e4SLinus Torvalds tblk = tid_to_tblock(tid);
5371da177e4SLinus Torvalds tblk->xflag |= COMMIT_DELETE;
5381da177e4SLinus Torvalds tblk->u.ip = ip;
5391da177e4SLinus Torvalds }
5401da177e4SLinus Torvalds
5411da177e4SLinus Torvalds /*
5421da177e4SLinus Torvalds * Incomplete truncate of file data can
5431da177e4SLinus Torvalds * result in timing problems unless we synchronously commit the
5441da177e4SLinus Torvalds * transaction.
5451da177e4SLinus Torvalds */
5461da177e4SLinus Torvalds if (new_size)
5471da177e4SLinus Torvalds commit_flag = COMMIT_SYNC;
5481da177e4SLinus Torvalds else
5491da177e4SLinus Torvalds commit_flag = 0;
5501da177e4SLinus Torvalds
5511da177e4SLinus Torvalds /*
5521da177e4SLinus Torvalds * If xtTruncate was incomplete, commit synchronously to avoid
5531da177e4SLinus Torvalds * timing complications
5541da177e4SLinus Torvalds */
5551da177e4SLinus Torvalds rc = txCommit(tid, 2, &iplist[0], commit_flag);
5561da177e4SLinus Torvalds
5571da177e4SLinus Torvalds txEnd(tid);
5581da177e4SLinus Torvalds
5591de87444SIngo Molnar mutex_unlock(&JFS_IP(ip)->commit_mutex);
56048ce8b05SEvgeniy Dushistov mutex_unlock(&JFS_IP(dip)->commit_mutex);
5611da177e4SLinus Torvalds
5621da177e4SLinus Torvalds while (new_size && (rc == 0)) {
5631da177e4SLinus Torvalds tid = txBegin(dip->i_sb, 0);
5641de87444SIngo Molnar mutex_lock(&JFS_IP(ip)->commit_mutex);
5651da177e4SLinus Torvalds new_size = xtTruncate_pmap(tid, ip, new_size);
5661da177e4SLinus Torvalds if (new_size < 0) {
5671da177e4SLinus Torvalds txAbort(tid, 1); /* Marks FS Dirty */
5681da177e4SLinus Torvalds rc = new_size;
5691da177e4SLinus Torvalds } else
5701da177e4SLinus Torvalds rc = txCommit(tid, 2, &iplist[0], COMMIT_SYNC);
5711da177e4SLinus Torvalds txEnd(tid);
5721de87444SIngo Molnar mutex_unlock(&JFS_IP(ip)->commit_mutex);
5731da177e4SLinus Torvalds }
5741da177e4SLinus Torvalds
5751da177e4SLinus Torvalds if (ip->i_nlink == 0)
5761da177e4SLinus Torvalds set_cflag(COMMIT_Nolink, ip);
5771da177e4SLinus Torvalds
5781da177e4SLinus Torvalds IWRITE_UNLOCK(ip);
5791da177e4SLinus Torvalds
5801da177e4SLinus Torvalds /*
5811da177e4SLinus Torvalds * Truncating the directory index table is not guaranteed. It
5821da177e4SLinus Torvalds * may need to be done iteratively
5831da177e4SLinus Torvalds */
5841da177e4SLinus Torvalds if (test_cflag(COMMIT_Stale, dip)) {
5851da177e4SLinus Torvalds if (dip->i_size > 1)
5861da177e4SLinus Torvalds jfs_truncate_nolock(dip, 0);
5871da177e4SLinus Torvalds
5881da177e4SLinus Torvalds clear_cflag(COMMIT_Stale, dip);
5891da177e4SLinus Torvalds }
5901da177e4SLinus Torvalds
5911da177e4SLinus Torvalds out1:
5921da177e4SLinus Torvalds free_UCSname(&dname);
5931da177e4SLinus Torvalds out:
5941da177e4SLinus Torvalds jfs_info("jfs_unlink: rc:%d", rc);
5951da177e4SLinus Torvalds return rc;
5961da177e4SLinus Torvalds }
5971da177e4SLinus Torvalds
5981da177e4SLinus Torvalds /*
5991da177e4SLinus Torvalds * NAME: commitZeroLink()
6001da177e4SLinus Torvalds *
6011da177e4SLinus Torvalds * FUNCTION: for non-directory, called by jfs_remove(),
6021da177e4SLinus Torvalds * truncate a regular file, directory or symbolic
6031da177e4SLinus Torvalds * link to zero length. return 0 if type is not
6041da177e4SLinus Torvalds * one of these.
6051da177e4SLinus Torvalds *
6061da177e4SLinus Torvalds * if the file is currently associated with a VM segment
6071da177e4SLinus Torvalds * only permanent disk and inode map resources are freed,
6081da177e4SLinus Torvalds * and neither the inode nor indirect blocks are modified
6091da177e4SLinus Torvalds * so that the resources can be later freed in the work
6101da177e4SLinus Torvalds * map by ctrunc1.
6111da177e4SLinus Torvalds * if there is no VM segment on entry, the resources are
6121da177e4SLinus Torvalds * freed in both work and permanent map.
6131da177e4SLinus Torvalds * (? for temporary file - memory object is cached even
6141da177e4SLinus Torvalds * after no reference:
6151da177e4SLinus Torvalds * reference count > 0 - )
6161da177e4SLinus Torvalds *
6171da177e4SLinus Torvalds * PARAMETERS: cd - pointer to commit data structure.
6181da177e4SLinus Torvalds * current inode is the one to truncate.
6191da177e4SLinus Torvalds *
6201da177e4SLinus Torvalds * RETURN: Errors from subroutines
6211da177e4SLinus Torvalds */
commitZeroLink(tid_t tid,struct inode * ip)6221da177e4SLinus Torvalds static s64 commitZeroLink(tid_t tid, struct inode *ip)
6231da177e4SLinus Torvalds {
6241da177e4SLinus Torvalds int filetype;
6251da177e4SLinus Torvalds struct tblock *tblk;
6261da177e4SLinus Torvalds
6271da177e4SLinus Torvalds jfs_info("commitZeroLink: tid = %d, ip = 0x%p", tid, ip);
6281da177e4SLinus Torvalds
6291da177e4SLinus Torvalds filetype = ip->i_mode & S_IFMT;
6301da177e4SLinus Torvalds switch (filetype) {
6311da177e4SLinus Torvalds case S_IFREG:
6321da177e4SLinus Torvalds break;
6331da177e4SLinus Torvalds case S_IFLNK:
6341da177e4SLinus Torvalds /* fast symbolic link */
6351da177e4SLinus Torvalds if (ip->i_size < IDATASIZE) {
6361da177e4SLinus Torvalds ip->i_size = 0;
6371da177e4SLinus Torvalds return 0;
6381da177e4SLinus Torvalds }
6391da177e4SLinus Torvalds break;
6401da177e4SLinus Torvalds default:
6411da177e4SLinus Torvalds assert(filetype != S_IFDIR);
6421da177e4SLinus Torvalds return 0;
6431da177e4SLinus Torvalds }
6441da177e4SLinus Torvalds
6451da177e4SLinus Torvalds set_cflag(COMMIT_Freewmap, ip);
6461da177e4SLinus Torvalds
6471da177e4SLinus Torvalds /* mark transaction of block map update type */
6481da177e4SLinus Torvalds tblk = tid_to_tblock(tid);
6491da177e4SLinus Torvalds tblk->xflag |= COMMIT_PMAP;
6501da177e4SLinus Torvalds
6511da177e4SLinus Torvalds /*
6521da177e4SLinus Torvalds * free EA
6531da177e4SLinus Torvalds */
6541da177e4SLinus Torvalds if (JFS_IP(ip)->ea.flag & DXD_EXTENT)
6551da177e4SLinus Torvalds /* acquire maplock on EA to be freed from block map */
6561da177e4SLinus Torvalds txEA(tid, ip, &JFS_IP(ip)->ea, NULL);
6571da177e4SLinus Torvalds
6581da177e4SLinus Torvalds /*
6591da177e4SLinus Torvalds * free ACL
6601da177e4SLinus Torvalds */
6611da177e4SLinus Torvalds if (JFS_IP(ip)->acl.flag & DXD_EXTENT)
6621da177e4SLinus Torvalds /* acquire maplock on EA to be freed from block map */
6631da177e4SLinus Torvalds txEA(tid, ip, &JFS_IP(ip)->acl, NULL);
6641da177e4SLinus Torvalds
6651da177e4SLinus Torvalds /*
6661da177e4SLinus Torvalds * free xtree/data (truncate to zero length):
6671da177e4SLinus Torvalds * free xtree/data pages from cache if COMMIT_PWMAP,
6681da177e4SLinus Torvalds * free xtree/data blocks from persistent block map, and
6691da177e4SLinus Torvalds * free xtree/data blocks from working block map if COMMIT_PWMAP;
6701da177e4SLinus Torvalds */
6711da177e4SLinus Torvalds if (ip->i_size)
6721da177e4SLinus Torvalds return xtTruncate_pmap(tid, ip, 0);
6731da177e4SLinus Torvalds
6741da177e4SLinus Torvalds return 0;
6751da177e4SLinus Torvalds }
6761da177e4SLinus Torvalds
6771da177e4SLinus Torvalds
6781da177e4SLinus Torvalds /*
6791868f4aaSDave Kleikamp * NAME: jfs_free_zero_link()
6801da177e4SLinus Torvalds *
6811da177e4SLinus Torvalds * FUNCTION: for non-directory, called by iClose(),
6821da177e4SLinus Torvalds * free resources of a file from cache and WORKING map
6831da177e4SLinus Torvalds * for a file previously committed with zero link count
6841da177e4SLinus Torvalds * while associated with a pager object,
6851da177e4SLinus Torvalds *
6861da177e4SLinus Torvalds * PARAMETER: ip - pointer to inode of file.
6871da177e4SLinus Torvalds */
jfs_free_zero_link(struct inode * ip)6881868f4aaSDave Kleikamp void jfs_free_zero_link(struct inode *ip)
6891da177e4SLinus Torvalds {
6901da177e4SLinus Torvalds int type;
6911da177e4SLinus Torvalds
6921868f4aaSDave Kleikamp jfs_info("jfs_free_zero_link: ip = 0x%p", ip);
6931da177e4SLinus Torvalds
6941da177e4SLinus Torvalds /* return if not reg or symbolic link or if size is
6951da177e4SLinus Torvalds * already ok.
6961da177e4SLinus Torvalds */
6971da177e4SLinus Torvalds type = ip->i_mode & S_IFMT;
6981da177e4SLinus Torvalds
6991da177e4SLinus Torvalds switch (type) {
7001da177e4SLinus Torvalds case S_IFREG:
7011da177e4SLinus Torvalds break;
7021da177e4SLinus Torvalds case S_IFLNK:
7031da177e4SLinus Torvalds /* if its contained in inode nothing to do */
7041da177e4SLinus Torvalds if (ip->i_size < IDATASIZE)
7051868f4aaSDave Kleikamp return;
7061da177e4SLinus Torvalds break;
7071da177e4SLinus Torvalds default:
7081868f4aaSDave Kleikamp return;
7091da177e4SLinus Torvalds }
7101da177e4SLinus Torvalds
7111da177e4SLinus Torvalds /*
7121da177e4SLinus Torvalds * free EA
7131da177e4SLinus Torvalds */
7141da177e4SLinus Torvalds if (JFS_IP(ip)->ea.flag & DXD_EXTENT) {
7151da177e4SLinus Torvalds s64 xaddr = addressDXD(&JFS_IP(ip)->ea);
7161da177e4SLinus Torvalds int xlen = lengthDXD(&JFS_IP(ip)->ea);
7171da177e4SLinus Torvalds struct maplock maplock; /* maplock for COMMIT_WMAP */
7181da177e4SLinus Torvalds struct pxd_lock *pxdlock; /* maplock for COMMIT_WMAP */
7191da177e4SLinus Torvalds
7201da177e4SLinus Torvalds /* free EA pages from cache */
7211da177e4SLinus Torvalds invalidate_dxd_metapages(ip, JFS_IP(ip)->ea);
7221da177e4SLinus Torvalds
7231da177e4SLinus Torvalds /* free EA extent from working block map */
7241da177e4SLinus Torvalds maplock.index = 1;
7251da177e4SLinus Torvalds pxdlock = (struct pxd_lock *) & maplock;
7261da177e4SLinus Torvalds pxdlock->flag = mlckFREEPXD;
7271da177e4SLinus Torvalds PXDaddress(&pxdlock->pxd, xaddr);
7281da177e4SLinus Torvalds PXDlength(&pxdlock->pxd, xlen);
7291da177e4SLinus Torvalds txFreeMap(ip, pxdlock, NULL, COMMIT_WMAP);
7301da177e4SLinus Torvalds }
7311da177e4SLinus Torvalds
7321da177e4SLinus Torvalds /*
7331da177e4SLinus Torvalds * free ACL
7341da177e4SLinus Torvalds */
7351da177e4SLinus Torvalds if (JFS_IP(ip)->acl.flag & DXD_EXTENT) {
7361da177e4SLinus Torvalds s64 xaddr = addressDXD(&JFS_IP(ip)->acl);
7371da177e4SLinus Torvalds int xlen = lengthDXD(&JFS_IP(ip)->acl);
7381da177e4SLinus Torvalds struct maplock maplock; /* maplock for COMMIT_WMAP */
7391da177e4SLinus Torvalds struct pxd_lock *pxdlock; /* maplock for COMMIT_WMAP */
7401da177e4SLinus Torvalds
7411da177e4SLinus Torvalds invalidate_dxd_metapages(ip, JFS_IP(ip)->acl);
7421da177e4SLinus Torvalds
7431da177e4SLinus Torvalds /* free ACL extent from working block map */
7441da177e4SLinus Torvalds maplock.index = 1;
7451da177e4SLinus Torvalds pxdlock = (struct pxd_lock *) & maplock;
7461da177e4SLinus Torvalds pxdlock->flag = mlckFREEPXD;
7471da177e4SLinus Torvalds PXDaddress(&pxdlock->pxd, xaddr);
7481da177e4SLinus Torvalds PXDlength(&pxdlock->pxd, xlen);
7491da177e4SLinus Torvalds txFreeMap(ip, pxdlock, NULL, COMMIT_WMAP);
7501da177e4SLinus Torvalds }
7511da177e4SLinus Torvalds
7521da177e4SLinus Torvalds /*
7531da177e4SLinus Torvalds * free xtree/data (truncate to zero length):
7541da177e4SLinus Torvalds * free xtree/data pages from cache, and
7551da177e4SLinus Torvalds * free xtree/data blocks from working block map;
7561da177e4SLinus Torvalds */
7571da177e4SLinus Torvalds if (ip->i_size)
7581868f4aaSDave Kleikamp xtTruncate(0, ip, 0, COMMIT_WMAP);
7591da177e4SLinus Torvalds }
7601da177e4SLinus Torvalds
7611da177e4SLinus Torvalds /*
7621da177e4SLinus Torvalds * NAME: jfs_link(vp, dvp, name, crp)
7631da177e4SLinus Torvalds *
7641da177e4SLinus Torvalds * FUNCTION: create a link to <vp> by the name = <name>
7651da177e4SLinus Torvalds * in the parent directory <dvp>
7661da177e4SLinus Torvalds *
7671da177e4SLinus Torvalds * PARAMETER: vp - target object
7681da177e4SLinus Torvalds * dvp - parent directory of new link
7691da177e4SLinus Torvalds * name - name of new link to target object
7701da177e4SLinus Torvalds * crp - credential
7711da177e4SLinus Torvalds *
7721da177e4SLinus Torvalds * RETURN: Errors from subroutines
7731da177e4SLinus Torvalds *
7741da177e4SLinus Torvalds * note:
7751da177e4SLinus Torvalds * JFS does NOT support link() on directories (to prevent circular
7761da177e4SLinus Torvalds * path in the directory hierarchy);
7771da177e4SLinus Torvalds * EPERM: the target object is a directory, and either the caller
7781da177e4SLinus Torvalds * does not have appropriate privileges or the implementation prohibits
7791da177e4SLinus Torvalds * using link() on directories [XPG4.2].
7801da177e4SLinus Torvalds *
7811da177e4SLinus Torvalds * JFS does NOT support links between file systems:
7821da177e4SLinus Torvalds * EXDEV: target object and new link are on different file systems and
7831da177e4SLinus Torvalds * implementation does not support links between file systems [XPG4.2].
7841da177e4SLinus Torvalds */
jfs_link(struct dentry * old_dentry,struct inode * dir,struct dentry * dentry)7851da177e4SLinus Torvalds static int jfs_link(struct dentry *old_dentry,
7861da177e4SLinus Torvalds struct inode *dir, struct dentry *dentry)
7871da177e4SLinus Torvalds {
7881da177e4SLinus Torvalds int rc;
7891da177e4SLinus Torvalds tid_t tid;
7902b0143b5SDavid Howells struct inode *ip = d_inode(old_dentry);
7911da177e4SLinus Torvalds ino_t ino;
7921da177e4SLinus Torvalds struct component_name dname;
7931da177e4SLinus Torvalds struct btstack btstack;
7941da177e4SLinus Torvalds struct inode *iplist[2];
7951da177e4SLinus Torvalds
796a455589fSAl Viro jfs_info("jfs_link: %pd %pd", old_dentry, dentry);
7971da177e4SLinus Torvalds
798acc84b05SDave Kleikamp rc = dquot_initialize(dir);
799acc84b05SDave Kleikamp if (rc)
800acc84b05SDave Kleikamp goto out;
801907f4554SChristoph Hellwig
80247cfdc33SImmad Mir if (isReadOnly(ip)) {
80347cfdc33SImmad Mir jfs_error(ip->i_sb, "read-only filesystem\n");
80447cfdc33SImmad Mir return -EROFS;
80547cfdc33SImmad Mir }
80647cfdc33SImmad Mir
8071da177e4SLinus Torvalds tid = txBegin(ip->i_sb, 0);
8081da177e4SLinus Torvalds
80982d5b9a7SDave Kleikamp mutex_lock_nested(&JFS_IP(dir)->commit_mutex, COMMIT_MUTEX_PARENT);
81082d5b9a7SDave Kleikamp mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
8111da177e4SLinus Torvalds
8121da177e4SLinus Torvalds /*
8131da177e4SLinus Torvalds * scan parent directory for entry/freespace
8141da177e4SLinus Torvalds */
8151da177e4SLinus Torvalds if ((rc = get_UCSname(&dname, dentry)))
816acc84b05SDave Kleikamp goto out_tx;
8171da177e4SLinus Torvalds
8181da177e4SLinus Torvalds if ((rc = dtSearch(dir, &dname, &ino, &btstack, JFS_CREATE)))
8191da177e4SLinus Torvalds goto free_dname;
8201da177e4SLinus Torvalds
8211da177e4SLinus Torvalds /*
8221da177e4SLinus Torvalds * create entry for new link in parent directory
8231da177e4SLinus Torvalds */
8241da177e4SLinus Torvalds ino = ip->i_ino;
8251da177e4SLinus Torvalds if ((rc = dtInsert(tid, dir, &dname, &ino, &btstack)))
8261da177e4SLinus Torvalds goto free_dname;
8271da177e4SLinus Torvalds
8281da177e4SLinus Torvalds /* update object inode */
829d8c76e6fSDave Hansen inc_nlink(ip); /* for new link */
830ad9dc5dfSJeff Layton inode_set_ctime_current(ip);
831ad9dc5dfSJeff Layton dir->i_mtime = inode_set_ctime_current(dir);
8321da177e4SLinus Torvalds mark_inode_dirty(dir);
8337de9c6eeSAl Viro ihold(ip);
8341da177e4SLinus Torvalds
8351da177e4SLinus Torvalds iplist[0] = ip;
8361da177e4SLinus Torvalds iplist[1] = dir;
8371da177e4SLinus Torvalds rc = txCommit(tid, 2, &iplist[0], 0);
8381da177e4SLinus Torvalds
8391da177e4SLinus Torvalds if (rc) {
8406d6b77f1SMiklos Szeredi drop_nlink(ip); /* never instantiated */
8411da177e4SLinus Torvalds iput(ip);
8421da177e4SLinus Torvalds } else
8431da177e4SLinus Torvalds d_instantiate(dentry, ip);
8441da177e4SLinus Torvalds
8451da177e4SLinus Torvalds free_dname:
8461da177e4SLinus Torvalds free_UCSname(&dname);
8471da177e4SLinus Torvalds
848acc84b05SDave Kleikamp out_tx:
8491da177e4SLinus Torvalds txEnd(tid);
8501da177e4SLinus Torvalds
8511de87444SIngo Molnar mutex_unlock(&JFS_IP(ip)->commit_mutex);
85248ce8b05SEvgeniy Dushistov mutex_unlock(&JFS_IP(dir)->commit_mutex);
8531da177e4SLinus Torvalds
854acc84b05SDave Kleikamp out:
8551da177e4SLinus Torvalds jfs_info("jfs_link: rc:%d", rc);
8561da177e4SLinus Torvalds return rc;
8571da177e4SLinus Torvalds }
8581da177e4SLinus Torvalds
8591da177e4SLinus Torvalds /*
8601da177e4SLinus Torvalds * NAME: jfs_symlink(dip, dentry, name)
8611da177e4SLinus Torvalds *
8621da177e4SLinus Torvalds * FUNCTION: creates a symbolic link to <symlink> by name <name>
8631da177e4SLinus Torvalds * in directory <dip>
8641da177e4SLinus Torvalds *
8651da177e4SLinus Torvalds * PARAMETER: dip - parent directory vnode
8661da177e4SLinus Torvalds * dentry - dentry of symbolic link
8671da177e4SLinus Torvalds * name - the path name of the existing object
8681da177e4SLinus Torvalds * that will be the source of the link
8691da177e4SLinus Torvalds *
8701da177e4SLinus Torvalds * RETURN: errors from subroutines
8711da177e4SLinus Torvalds *
8721da177e4SLinus Torvalds * note:
8731da177e4SLinus Torvalds * ENAMETOOLONG: pathname resolution of a symbolic link produced
8741da177e4SLinus Torvalds * an intermediate result whose length exceeds PATH_MAX [XPG4.2]
8751da177e4SLinus Torvalds */
8761da177e4SLinus Torvalds
jfs_symlink(struct mnt_idmap * idmap,struct inode * dip,struct dentry * dentry,const char * name)8777a77db95SChristian Brauner static int jfs_symlink(struct mnt_idmap *idmap, struct inode *dip,
878549c7297SChristian Brauner struct dentry *dentry, const char *name)
8791da177e4SLinus Torvalds {
8801da177e4SLinus Torvalds int rc;
8811da177e4SLinus Torvalds tid_t tid;
8821da177e4SLinus Torvalds ino_t ino = 0;
8831da177e4SLinus Torvalds struct component_name dname;
884820eb59dSKees Cook u32 ssize; /* source pathname size */
8851da177e4SLinus Torvalds struct btstack btstack;
886*87098a0dSColin Ian King struct inode *ip;
8871da177e4SLinus Torvalds s64 xlen = 0;
8881da177e4SLinus Torvalds int bmask = 0, xsize;
8893c2c2262SDave Kleikamp s64 xaddr;
8901da177e4SLinus Torvalds struct metapage *mp;
8911da177e4SLinus Torvalds struct super_block *sb;
8921da177e4SLinus Torvalds struct tblock *tblk;
8931da177e4SLinus Torvalds
8941da177e4SLinus Torvalds struct inode *iplist[2];
8951da177e4SLinus Torvalds
8961da177e4SLinus Torvalds jfs_info("jfs_symlink: dip:0x%p name:%s", dip, name);
8971da177e4SLinus Torvalds
898acc84b05SDave Kleikamp rc = dquot_initialize(dip);
899acc84b05SDave Kleikamp if (rc)
900acc84b05SDave Kleikamp goto out1;
901907f4554SChristoph Hellwig
9021da177e4SLinus Torvalds ssize = strlen(name) + 1;
9031da177e4SLinus Torvalds
9041da177e4SLinus Torvalds /*
9051da177e4SLinus Torvalds * search parent directory for entry/freespace
9061da177e4SLinus Torvalds * (dtSearch() returns parent directory page pinned)
9071da177e4SLinus Torvalds */
9081da177e4SLinus Torvalds
9091da177e4SLinus Torvalds if ((rc = get_UCSname(&dname, dentry)))
9101da177e4SLinus Torvalds goto out1;
9111da177e4SLinus Torvalds
9121da177e4SLinus Torvalds /*
9131da177e4SLinus Torvalds * allocate on-disk/in-memory inode for symbolic link:
9141da177e4SLinus Torvalds * (iAlloc() returns new, locked inode)
9151da177e4SLinus Torvalds */
9161da177e4SLinus Torvalds ip = ialloc(dip, S_IFLNK | 0777);
917087387f9SAkinobu Mita if (IS_ERR(ip)) {
918087387f9SAkinobu Mita rc = PTR_ERR(ip);
9191da177e4SLinus Torvalds goto out2;
9201da177e4SLinus Torvalds }
9211da177e4SLinus Torvalds
9221da177e4SLinus Torvalds tid = txBegin(dip->i_sb, 0);
9231da177e4SLinus Torvalds
92482d5b9a7SDave Kleikamp mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);
92582d5b9a7SDave Kleikamp mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
9261da177e4SLinus Torvalds
9272a7dba39SEric Paris rc = jfs_init_security(tid, ip, dip, &dentry->d_name);
9281d15b10fSDave Kleikamp if (rc)
9291d15b10fSDave Kleikamp goto out3;
9301d15b10fSDave Kleikamp
9311da177e4SLinus Torvalds tblk = tid_to_tblock(tid);
9321da177e4SLinus Torvalds tblk->xflag |= COMMIT_CREATE;
9331da177e4SLinus Torvalds tblk->ino = ip->i_ino;
9341da177e4SLinus Torvalds tblk->u.ixpxd = JFS_IP(ip)->ixpxd;
9351da177e4SLinus Torvalds
9361da177e4SLinus Torvalds /* fix symlink access permission
9371da177e4SLinus Torvalds * (dir_create() ANDs in the u.u_cmask,
9381da177e4SLinus Torvalds * but symlinks really need to be 777 access)
9391da177e4SLinus Torvalds */
9401da177e4SLinus Torvalds ip->i_mode |= 0777;
9411da177e4SLinus Torvalds
9421da177e4SLinus Torvalds /*
9431da177e4SLinus Torvalds * write symbolic link target path name
9441da177e4SLinus Torvalds */
9451da177e4SLinus Torvalds xtInitRoot(tid, ip);
9461da177e4SLinus Torvalds
9471da177e4SLinus Torvalds /*
9481da177e4SLinus Torvalds * write source path name inline in on-disk inode (fast symbolic link)
9491da177e4SLinus Torvalds */
9501da177e4SLinus Torvalds
9511da177e4SLinus Torvalds if (ssize <= IDATASIZE) {
952c7f2e1f0SDmitry Monakhov ip->i_op = &jfs_fast_symlink_inode_operations;
9531da177e4SLinus Torvalds
954ebe06036SDr. David Alan Gilbert ip->i_link = JFS_IP(ip)->i_inline_all;
955ad476fedSAl Viro memcpy(ip->i_link, name, ssize);
9561da177e4SLinus Torvalds ip->i_size = ssize - 1;
9571da177e4SLinus Torvalds
9581da177e4SLinus Torvalds /*
9591da177e4SLinus Torvalds * if symlink is > 128 bytes, we don't have the space to
9601da177e4SLinus Torvalds * store inline extended attributes
9611da177e4SLinus Torvalds */
9621da177e4SLinus Torvalds if (ssize > sizeof (JFS_IP(ip)->i_inline))
9631da177e4SLinus Torvalds JFS_IP(ip)->mode2 &= ~INLINEEA;
9641da177e4SLinus Torvalds
965820eb59dSKees Cook jfs_info("jfs_symlink: fast symlink added ssize:%u name:%s ",
9661da177e4SLinus Torvalds ssize, name);
9671da177e4SLinus Torvalds }
9681da177e4SLinus Torvalds /*
9691da177e4SLinus Torvalds * write source path name in a single extent
9701da177e4SLinus Torvalds */
9711da177e4SLinus Torvalds else {
9721da177e4SLinus Torvalds jfs_info("jfs_symlink: allocate extent ip:0x%p", ip);
9731da177e4SLinus Torvalds
974c7f2e1f0SDmitry Monakhov ip->i_op = &jfs_symlink_inode_operations;
97521fc61c7SAl Viro inode_nohighmem(ip);
9761da177e4SLinus Torvalds ip->i_mapping->a_ops = &jfs_aops;
9771da177e4SLinus Torvalds
9781da177e4SLinus Torvalds /*
9791da177e4SLinus Torvalds * even though the data of symlink object (source
9801da177e4SLinus Torvalds * path name) is treated as non-journaled user data,
9811da177e4SLinus Torvalds * it is read/written thru buffer cache for performance.
9821da177e4SLinus Torvalds */
9831da177e4SLinus Torvalds sb = ip->i_sb;
9841da177e4SLinus Torvalds bmask = JFS_SBI(sb)->bsize - 1;
9851da177e4SLinus Torvalds xsize = (ssize + bmask) & ~bmask;
9861da177e4SLinus Torvalds xaddr = 0;
9871da177e4SLinus Torvalds xlen = xsize >> JFS_SBI(sb)->l2bsize;
9881da177e4SLinus Torvalds if ((rc = xtInsert(tid, ip, 0, 0, xlen, &xaddr, 0))) {
9891da177e4SLinus Torvalds txAbort(tid, 0);
9901da177e4SLinus Torvalds goto out3;
9911da177e4SLinus Torvalds }
9921da177e4SLinus Torvalds ip->i_size = ssize - 1;
9931da177e4SLinus Torvalds while (ssize) {
9941da177e4SLinus Torvalds /* This is kind of silly since PATH_MAX == 4K */
995820eb59dSKees Cook u32 copy_size = min_t(u32, ssize, PSIZE);
9961da177e4SLinus Torvalds
9971da177e4SLinus Torvalds mp = get_metapage(ip, xaddr, PSIZE, 1);
9981da177e4SLinus Torvalds
9991da177e4SLinus Torvalds if (mp == NULL) {
10001da177e4SLinus Torvalds xtTruncate(tid, ip, 0, COMMIT_PWMAP);
10011da177e4SLinus Torvalds rc = -EIO;
10021da177e4SLinus Torvalds txAbort(tid, 0);
10031da177e4SLinus Torvalds goto out3;
10041da177e4SLinus Torvalds }
10051da177e4SLinus Torvalds memcpy(mp->data, name, copy_size);
10061da177e4SLinus Torvalds flush_metapage(mp);
10071da177e4SLinus Torvalds ssize -= copy_size;
10081da177e4SLinus Torvalds name += copy_size;
10091da177e4SLinus Torvalds xaddr += JFS_SBI(sb)->nbperpage;
10101da177e4SLinus Torvalds }
10111da177e4SLinus Torvalds }
10121da177e4SLinus Torvalds
10131da177e4SLinus Torvalds /*
10141da177e4SLinus Torvalds * create entry for symbolic link in parent directory
10151da177e4SLinus Torvalds */
10161da177e4SLinus Torvalds rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE);
10171da177e4SLinus Torvalds if (rc == 0) {
10181da177e4SLinus Torvalds ino = ip->i_ino;
10191da177e4SLinus Torvalds rc = dtInsert(tid, dip, &dname, &ino, &btstack);
10201da177e4SLinus Torvalds }
10211da177e4SLinus Torvalds if (rc) {
10221da177e4SLinus Torvalds if (xlen)
10231da177e4SLinus Torvalds xtTruncate(tid, ip, 0, COMMIT_PWMAP);
10241da177e4SLinus Torvalds txAbort(tid, 0);
10251da177e4SLinus Torvalds /* discard new inode */
10261da177e4SLinus Torvalds goto out3;
10271da177e4SLinus Torvalds }
10281da177e4SLinus Torvalds
10291da177e4SLinus Torvalds mark_inode_dirty(ip);
10301da177e4SLinus Torvalds
1031ad9dc5dfSJeff Layton dip->i_mtime = inode_set_ctime_current(dip);
1032988a6490SDave Kleikamp mark_inode_dirty(dip);
10331da177e4SLinus Torvalds /*
10341da177e4SLinus Torvalds * commit update of parent directory and link object
10351da177e4SLinus Torvalds */
10361da177e4SLinus Torvalds
10371da177e4SLinus Torvalds iplist[0] = dip;
10381da177e4SLinus Torvalds iplist[1] = ip;
10391da177e4SLinus Torvalds rc = txCommit(tid, 2, &iplist[0], 0);
10401da177e4SLinus Torvalds
10411da177e4SLinus Torvalds out3:
10421da177e4SLinus Torvalds txEnd(tid);
10431de87444SIngo Molnar mutex_unlock(&JFS_IP(ip)->commit_mutex);
104448ce8b05SEvgeniy Dushistov mutex_unlock(&JFS_IP(dip)->commit_mutex);
10451da177e4SLinus Torvalds if (rc) {
10464f4b401bSDave Kleikamp free_ea_wmap(ip);
10476d6b77f1SMiklos Szeredi clear_nlink(ip);
1048a6cbedfaSAl Viro discard_new_inode(ip);
10491f3403faSDave Kleikamp } else {
10501e2e547aSAl Viro d_instantiate_new(dentry, ip);
10511f3403faSDave Kleikamp }
10521da177e4SLinus Torvalds
10531da177e4SLinus Torvalds out2:
10541da177e4SLinus Torvalds free_UCSname(&dname);
10551da177e4SLinus Torvalds
10561da177e4SLinus Torvalds out1:
10571da177e4SLinus Torvalds jfs_info("jfs_symlink: rc:%d", rc);
10581da177e4SLinus Torvalds return rc;
10591da177e4SLinus Torvalds }
10601da177e4SLinus Torvalds
10611da177e4SLinus Torvalds
10621da177e4SLinus Torvalds /*
10631da177e4SLinus Torvalds * NAME: jfs_rename
10641da177e4SLinus Torvalds *
10651da177e4SLinus Torvalds * FUNCTION: rename a file or directory
10661da177e4SLinus Torvalds */
jfs_rename(struct mnt_idmap * idmap,struct inode * old_dir,struct dentry * old_dentry,struct inode * new_dir,struct dentry * new_dentry,unsigned int flags)1067e18275aeSChristian Brauner static int jfs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
1068549c7297SChristian Brauner struct dentry *old_dentry, struct inode *new_dir,
1069549c7297SChristian Brauner struct dentry *new_dentry, unsigned int flags)
10701da177e4SLinus Torvalds {
10711da177e4SLinus Torvalds struct btstack btstack;
10721da177e4SLinus Torvalds ino_t ino;
10731da177e4SLinus Torvalds struct component_name new_dname;
10741da177e4SLinus Torvalds struct inode *new_ip;
10751da177e4SLinus Torvalds struct component_name old_dname;
10761da177e4SLinus Torvalds struct inode *old_ip;
10771da177e4SLinus Torvalds int rc;
10781da177e4SLinus Torvalds tid_t tid;
10791da177e4SLinus Torvalds struct tlock *tlck;
10801da177e4SLinus Torvalds struct dt_lock *dtlck;
10811da177e4SLinus Torvalds struct lv *lv;
10821da177e4SLinus Torvalds int ipcount;
10831da177e4SLinus Torvalds struct inode *iplist[4];
10841da177e4SLinus Torvalds struct tblock *tblk;
10851da177e4SLinus Torvalds s64 new_size = 0;
10861da177e4SLinus Torvalds int commit_flag;
10871da177e4SLinus Torvalds
1088f03b8ad8SMiklos Szeredi if (flags & ~RENAME_NOREPLACE)
1089f03b8ad8SMiklos Szeredi return -EINVAL;
10901da177e4SLinus Torvalds
1091a455589fSAl Viro jfs_info("jfs_rename: %pd %pd", old_dentry, new_dentry);
10921da177e4SLinus Torvalds
1093acc84b05SDave Kleikamp rc = dquot_initialize(old_dir);
1094acc84b05SDave Kleikamp if (rc)
1095acc84b05SDave Kleikamp goto out1;
1096acc84b05SDave Kleikamp rc = dquot_initialize(new_dir);
1097acc84b05SDave Kleikamp if (rc)
1098acc84b05SDave Kleikamp goto out1;
1099907f4554SChristoph Hellwig
11002b0143b5SDavid Howells old_ip = d_inode(old_dentry);
11012b0143b5SDavid Howells new_ip = d_inode(new_dentry);
11021da177e4SLinus Torvalds
11031da177e4SLinus Torvalds if ((rc = get_UCSname(&old_dname, old_dentry)))
11041da177e4SLinus Torvalds goto out1;
11051da177e4SLinus Torvalds
11061da177e4SLinus Torvalds if ((rc = get_UCSname(&new_dname, new_dentry)))
11071da177e4SLinus Torvalds goto out2;
11081da177e4SLinus Torvalds
11091da177e4SLinus Torvalds /*
11101da177e4SLinus Torvalds * Make sure source inode number is what we think it is
11111da177e4SLinus Torvalds */
11121da177e4SLinus Torvalds rc = dtSearch(old_dir, &old_dname, &ino, &btstack, JFS_LOOKUP);
11131da177e4SLinus Torvalds if (rc || (ino != old_ip->i_ino)) {
11141da177e4SLinus Torvalds rc = -ENOENT;
11151da177e4SLinus Torvalds goto out3;
11161da177e4SLinus Torvalds }
11171da177e4SLinus Torvalds
11181da177e4SLinus Torvalds /*
11191da177e4SLinus Torvalds * Make sure dest inode number (if any) is what we think it is
11201da177e4SLinus Torvalds */
11211da177e4SLinus Torvalds rc = dtSearch(new_dir, &new_dname, &ino, &btstack, JFS_LOOKUP);
112209aaa749SJoe Perches if (!rc) {
1123da8a41d1SDave Kleikamp if ((!new_ip) || (ino != new_ip->i_ino)) {
11241da177e4SLinus Torvalds rc = -ESTALE;
11251da177e4SLinus Torvalds goto out3;
11261da177e4SLinus Torvalds }
11271da177e4SLinus Torvalds } else if (rc != -ENOENT)
11281da177e4SLinus Torvalds goto out3;
11291da177e4SLinus Torvalds else if (new_ip) {
11301da177e4SLinus Torvalds /* no entry exists, but one was expected */
11311da177e4SLinus Torvalds rc = -ESTALE;
11321da177e4SLinus Torvalds goto out3;
11331da177e4SLinus Torvalds }
11341da177e4SLinus Torvalds
11351da177e4SLinus Torvalds if (S_ISDIR(old_ip->i_mode)) {
11361da177e4SLinus Torvalds if (new_ip) {
11371da177e4SLinus Torvalds if (!dtEmpty(new_ip)) {
11381da177e4SLinus Torvalds rc = -ENOTEMPTY;
11391da177e4SLinus Torvalds goto out3;
11401da177e4SLinus Torvalds }
11411da177e4SLinus Torvalds }
11421da177e4SLinus Torvalds } else if (new_ip) {
114382d5b9a7SDave Kleikamp IWRITE_LOCK(new_ip, RDWRLOCK_NORMAL);
11441da177e4SLinus Torvalds /* Init inode for quota operations. */
1145acc84b05SDave Kleikamp rc = dquot_initialize(new_ip);
1146acc84b05SDave Kleikamp if (rc)
1147acc84b05SDave Kleikamp goto out_unlock;
11481da177e4SLinus Torvalds }
11491da177e4SLinus Torvalds
11501da177e4SLinus Torvalds /*
11511da177e4SLinus Torvalds * The real work starts here
11521da177e4SLinus Torvalds */
11531da177e4SLinus Torvalds tid = txBegin(new_dir->i_sb, 0);
11541da177e4SLinus Torvalds
115582d5b9a7SDave Kleikamp /*
115682d5b9a7SDave Kleikamp * How do we know the locking is safe from deadlocks?
115782d5b9a7SDave Kleikamp * The vfs does the hard part for us. Any time we are taking nested
115882d5b9a7SDave Kleikamp * commit_mutexes, the vfs already has i_mutex held on the parent.
115982d5b9a7SDave Kleikamp * Here, the vfs has already taken i_mutex on both old_dir and new_dir.
116082d5b9a7SDave Kleikamp */
116182d5b9a7SDave Kleikamp mutex_lock_nested(&JFS_IP(new_dir)->commit_mutex, COMMIT_MUTEX_PARENT);
116282d5b9a7SDave Kleikamp mutex_lock_nested(&JFS_IP(old_ip)->commit_mutex, COMMIT_MUTEX_CHILD);
11631da177e4SLinus Torvalds if (old_dir != new_dir)
116482d5b9a7SDave Kleikamp mutex_lock_nested(&JFS_IP(old_dir)->commit_mutex,
116582d5b9a7SDave Kleikamp COMMIT_MUTEX_SECOND_PARENT);
11661da177e4SLinus Torvalds
11671da177e4SLinus Torvalds if (new_ip) {
116882d5b9a7SDave Kleikamp mutex_lock_nested(&JFS_IP(new_ip)->commit_mutex,
116982d5b9a7SDave Kleikamp COMMIT_MUTEX_VICTIM);
11701da177e4SLinus Torvalds /*
11711da177e4SLinus Torvalds * Change existing directory entry to new inode number
11721da177e4SLinus Torvalds */
11731da177e4SLinus Torvalds ino = new_ip->i_ino;
11741da177e4SLinus Torvalds rc = dtModify(tid, new_dir, &new_dname, &ino,
11751da177e4SLinus Torvalds old_ip->i_ino, JFS_RENAME);
11761da177e4SLinus Torvalds if (rc)
117726456955SDave Kleikamp goto out_tx;
11789a53c3a7SDave Hansen drop_nlink(new_ip);
11791da177e4SLinus Torvalds if (S_ISDIR(new_ip->i_mode)) {
11809a53c3a7SDave Hansen drop_nlink(new_ip);
11811da177e4SLinus Torvalds if (new_ip->i_nlink) {
118248ce8b05SEvgeniy Dushistov mutex_unlock(&JFS_IP(new_ip)->commit_mutex);
11831da177e4SLinus Torvalds if (old_dir != new_dir)
11841de87444SIngo Molnar mutex_unlock(&JFS_IP(old_dir)->commit_mutex);
118548ce8b05SEvgeniy Dushistov mutex_unlock(&JFS_IP(old_ip)->commit_mutex);
118648ce8b05SEvgeniy Dushistov mutex_unlock(&JFS_IP(new_dir)->commit_mutex);
11871da177e4SLinus Torvalds if (!S_ISDIR(old_ip->i_mode) && new_ip)
11881da177e4SLinus Torvalds IWRITE_UNLOCK(new_ip);
11891da177e4SLinus Torvalds jfs_error(new_ip->i_sb,
1190eb8630d7SJoe Perches "new_ip->i_nlink != 0\n");
11911da177e4SLinus Torvalds return -EIO;
11921da177e4SLinus Torvalds }
11931da177e4SLinus Torvalds tblk = tid_to_tblock(tid);
11941da177e4SLinus Torvalds tblk->xflag |= COMMIT_DELETE;
11951da177e4SLinus Torvalds tblk->u.ip = new_ip;
11961da177e4SLinus Torvalds } else if (new_ip->i_nlink == 0) {
11971da177e4SLinus Torvalds assert(!test_cflag(COMMIT_Nolink, new_ip));
11981da177e4SLinus Torvalds /* free block resources */
11991da177e4SLinus Torvalds if ((new_size = commitZeroLink(tid, new_ip)) < 0) {
12001da177e4SLinus Torvalds txAbort(tid, 1); /* Marks FS Dirty */
12011da177e4SLinus Torvalds rc = new_size;
120226456955SDave Kleikamp goto out_tx;
12031da177e4SLinus Torvalds }
12041da177e4SLinus Torvalds tblk = tid_to_tblock(tid);
12051da177e4SLinus Torvalds tblk->xflag |= COMMIT_DELETE;
12061da177e4SLinus Torvalds tblk->u.ip = new_ip;
12071da177e4SLinus Torvalds } else {
1208ad9dc5dfSJeff Layton inode_set_ctime_current(new_ip);
12091da177e4SLinus Torvalds mark_inode_dirty(new_ip);
12101da177e4SLinus Torvalds }
12111da177e4SLinus Torvalds } else {
12121da177e4SLinus Torvalds /*
12131da177e4SLinus Torvalds * Add new directory entry
12141da177e4SLinus Torvalds */
12151da177e4SLinus Torvalds rc = dtSearch(new_dir, &new_dname, &ino, &btstack,
12161da177e4SLinus Torvalds JFS_CREATE);
12171da177e4SLinus Torvalds if (rc) {
12186ed71e98SJoe Perches jfs_err("jfs_rename didn't expect dtSearch to fail w/rc = %d",
12196ed71e98SJoe Perches rc);
122026456955SDave Kleikamp goto out_tx;
12211da177e4SLinus Torvalds }
12221da177e4SLinus Torvalds
12231da177e4SLinus Torvalds ino = old_ip->i_ino;
12241da177e4SLinus Torvalds rc = dtInsert(tid, new_dir, &new_dname, &ino, &btstack);
12251da177e4SLinus Torvalds if (rc) {
12261da177e4SLinus Torvalds if (rc == -EIO)
12271da177e4SLinus Torvalds jfs_err("jfs_rename: dtInsert returned -EIO");
122826456955SDave Kleikamp goto out_tx;
12291da177e4SLinus Torvalds }
12301da177e4SLinus Torvalds if (S_ISDIR(old_ip->i_mode))
1231d8c76e6fSDave Hansen inc_nlink(new_dir);
12321da177e4SLinus Torvalds }
12331da177e4SLinus Torvalds /*
12341da177e4SLinus Torvalds * Remove old directory entry
12351da177e4SLinus Torvalds */
12361da177e4SLinus Torvalds
12371da177e4SLinus Torvalds ino = old_ip->i_ino;
12381da177e4SLinus Torvalds rc = dtDelete(tid, old_dir, &old_dname, &ino, JFS_REMOVE);
12391da177e4SLinus Torvalds if (rc) {
12401da177e4SLinus Torvalds jfs_err("jfs_rename did not expect dtDelete to return rc = %d",
12411da177e4SLinus Torvalds rc);
12421da177e4SLinus Torvalds txAbort(tid, 1); /* Marks Filesystem dirty */
124326456955SDave Kleikamp goto out_tx;
12441da177e4SLinus Torvalds }
12451da177e4SLinus Torvalds if (S_ISDIR(old_ip->i_mode)) {
12469a53c3a7SDave Hansen drop_nlink(old_dir);
12471da177e4SLinus Torvalds if (old_dir != new_dir) {
12481da177e4SLinus Torvalds /*
12491da177e4SLinus Torvalds * Change inode number of parent for moved directory
12501da177e4SLinus Torvalds */
12511da177e4SLinus Torvalds
12521da177e4SLinus Torvalds JFS_IP(old_ip)->i_dtroot.header.idotdot =
12531da177e4SLinus Torvalds cpu_to_le32(new_dir->i_ino);
12541da177e4SLinus Torvalds
12551da177e4SLinus Torvalds /* Linelock header of dtree */
12561da177e4SLinus Torvalds tlck = txLock(tid, old_ip,
12571da177e4SLinus Torvalds (struct metapage *) &JFS_IP(old_ip)->bxflag,
12581da177e4SLinus Torvalds tlckDTREE | tlckBTROOT | tlckRELINK);
12591da177e4SLinus Torvalds dtlck = (struct dt_lock *) & tlck->lock;
12601da177e4SLinus Torvalds ASSERT(dtlck->index == 0);
12611da177e4SLinus Torvalds lv = & dtlck->lv[0];
12621da177e4SLinus Torvalds lv->offset = 0;
12631da177e4SLinus Torvalds lv->length = 1;
12641da177e4SLinus Torvalds dtlck->index++;
12651da177e4SLinus Torvalds }
12661da177e4SLinus Torvalds }
12671da177e4SLinus Torvalds
12681da177e4SLinus Torvalds /*
12691da177e4SLinus Torvalds * Update ctime on changed/moved inodes & mark dirty
12701da177e4SLinus Torvalds */
1271ad9dc5dfSJeff Layton inode_set_ctime_current(old_ip);
12721da177e4SLinus Torvalds mark_inode_dirty(old_ip);
12731da177e4SLinus Torvalds
1274ad9dc5dfSJeff Layton new_dir->i_mtime = inode_set_ctime_current(new_dir);
12751da177e4SLinus Torvalds mark_inode_dirty(new_dir);
12761da177e4SLinus Torvalds
12771da177e4SLinus Torvalds /* Build list of inodes modified by this transaction */
12781da177e4SLinus Torvalds ipcount = 0;
12791da177e4SLinus Torvalds iplist[ipcount++] = old_ip;
12801da177e4SLinus Torvalds if (new_ip)
12811da177e4SLinus Torvalds iplist[ipcount++] = new_ip;
12821da177e4SLinus Torvalds iplist[ipcount++] = old_dir;
12831da177e4SLinus Torvalds
12841da177e4SLinus Torvalds if (old_dir != new_dir) {
12851da177e4SLinus Torvalds iplist[ipcount++] = new_dir;
1286ad9dc5dfSJeff Layton old_dir->i_mtime = inode_set_ctime_current(old_dir);
12871da177e4SLinus Torvalds mark_inode_dirty(old_dir);
12881da177e4SLinus Torvalds }
12891da177e4SLinus Torvalds
12901da177e4SLinus Torvalds /*
12911da177e4SLinus Torvalds * Incomplete truncate of file data can
12921da177e4SLinus Torvalds * result in timing problems unless we synchronously commit the
12931da177e4SLinus Torvalds * transaction.
12941da177e4SLinus Torvalds */
12951da177e4SLinus Torvalds if (new_size)
12961da177e4SLinus Torvalds commit_flag = COMMIT_SYNC;
12971da177e4SLinus Torvalds else
12981da177e4SLinus Torvalds commit_flag = 0;
12991da177e4SLinus Torvalds
13001da177e4SLinus Torvalds rc = txCommit(tid, ipcount, iplist, commit_flag);
13011da177e4SLinus Torvalds
130226456955SDave Kleikamp out_tx:
13031da177e4SLinus Torvalds txEnd(tid);
13041da177e4SLinus Torvalds if (new_ip)
13051de87444SIngo Molnar mutex_unlock(&JFS_IP(new_ip)->commit_mutex);
130648ce8b05SEvgeniy Dushistov if (old_dir != new_dir)
130748ce8b05SEvgeniy Dushistov mutex_unlock(&JFS_IP(old_dir)->commit_mutex);
130848ce8b05SEvgeniy Dushistov mutex_unlock(&JFS_IP(old_ip)->commit_mutex);
130948ce8b05SEvgeniy Dushistov mutex_unlock(&JFS_IP(new_dir)->commit_mutex);
13101da177e4SLinus Torvalds
13111da177e4SLinus Torvalds while (new_size && (rc == 0)) {
13121da177e4SLinus Torvalds tid = txBegin(new_ip->i_sb, 0);
13131de87444SIngo Molnar mutex_lock(&JFS_IP(new_ip)->commit_mutex);
13141da177e4SLinus Torvalds new_size = xtTruncate_pmap(tid, new_ip, new_size);
13151da177e4SLinus Torvalds if (new_size < 0) {
13161da177e4SLinus Torvalds txAbort(tid, 1);
13171da177e4SLinus Torvalds rc = new_size;
13181da177e4SLinus Torvalds } else
13191da177e4SLinus Torvalds rc = txCommit(tid, 1, &new_ip, COMMIT_SYNC);
13201da177e4SLinus Torvalds txEnd(tid);
13211de87444SIngo Molnar mutex_unlock(&JFS_IP(new_ip)->commit_mutex);
13221da177e4SLinus Torvalds }
13231da177e4SLinus Torvalds if (new_ip && (new_ip->i_nlink == 0))
13241da177e4SLinus Torvalds set_cflag(COMMIT_Nolink, new_ip);
13251da177e4SLinus Torvalds /*
13261da177e4SLinus Torvalds * Truncating the directory index table is not guaranteed. It
13271da177e4SLinus Torvalds * may need to be done iteratively
13281da177e4SLinus Torvalds */
13291da177e4SLinus Torvalds if (test_cflag(COMMIT_Stale, old_dir)) {
13301da177e4SLinus Torvalds if (old_dir->i_size > 1)
13311da177e4SLinus Torvalds jfs_truncate_nolock(old_dir, 0);
13321da177e4SLinus Torvalds
13331da177e4SLinus Torvalds clear_cflag(COMMIT_Stale, old_dir);
13341da177e4SLinus Torvalds }
1335acc84b05SDave Kleikamp out_unlock:
133626456955SDave Kleikamp if (new_ip && !S_ISDIR(new_ip->i_mode))
133726456955SDave Kleikamp IWRITE_UNLOCK(new_ip);
133826456955SDave Kleikamp out3:
133926456955SDave Kleikamp free_UCSname(&new_dname);
134026456955SDave Kleikamp out2:
134126456955SDave Kleikamp free_UCSname(&old_dname);
134226456955SDave Kleikamp out1:
13431da177e4SLinus Torvalds jfs_info("jfs_rename: returning %d", rc);
13441da177e4SLinus Torvalds return rc;
13451da177e4SLinus Torvalds }
13461da177e4SLinus Torvalds
13471da177e4SLinus Torvalds
13481da177e4SLinus Torvalds /*
13491da177e4SLinus Torvalds * NAME: jfs_mknod
13501da177e4SLinus Torvalds *
13511da177e4SLinus Torvalds * FUNCTION: Create a special file (device)
13521da177e4SLinus Torvalds */
jfs_mknod(struct mnt_idmap * idmap,struct inode * dir,struct dentry * dentry,umode_t mode,dev_t rdev)13535ebb29beSChristian Brauner static int jfs_mknod(struct mnt_idmap *idmap, struct inode *dir,
1354549c7297SChristian Brauner struct dentry *dentry, umode_t mode, dev_t rdev)
13551da177e4SLinus Torvalds {
13561da177e4SLinus Torvalds struct jfs_inode_info *jfs_ip;
13571da177e4SLinus Torvalds struct btstack btstack;
13581da177e4SLinus Torvalds struct component_name dname;
13591da177e4SLinus Torvalds ino_t ino;
13601da177e4SLinus Torvalds struct inode *ip;
13611da177e4SLinus Torvalds struct inode *iplist[2];
13621da177e4SLinus Torvalds int rc;
13631da177e4SLinus Torvalds tid_t tid;
13641da177e4SLinus Torvalds struct tblock *tblk;
13651da177e4SLinus Torvalds
1366a455589fSAl Viro jfs_info("jfs_mknod: %pd", dentry);
13671da177e4SLinus Torvalds
1368acc84b05SDave Kleikamp rc = dquot_initialize(dir);
1369acc84b05SDave Kleikamp if (rc)
1370acc84b05SDave Kleikamp goto out;
1371907f4554SChristoph Hellwig
13721da177e4SLinus Torvalds if ((rc = get_UCSname(&dname, dentry)))
13731da177e4SLinus Torvalds goto out;
13741da177e4SLinus Torvalds
13751da177e4SLinus Torvalds ip = ialloc(dir, mode);
1376087387f9SAkinobu Mita if (IS_ERR(ip)) {
1377087387f9SAkinobu Mita rc = PTR_ERR(ip);
13781da177e4SLinus Torvalds goto out1;
13791da177e4SLinus Torvalds }
13801da177e4SLinus Torvalds jfs_ip = JFS_IP(ip);
13811da177e4SLinus Torvalds
13821da177e4SLinus Torvalds tid = txBegin(dir->i_sb, 0);
13831da177e4SLinus Torvalds
138482d5b9a7SDave Kleikamp mutex_lock_nested(&JFS_IP(dir)->commit_mutex, COMMIT_MUTEX_PARENT);
138582d5b9a7SDave Kleikamp mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
13861da177e4SLinus Torvalds
13874f4b401bSDave Kleikamp rc = jfs_init_acl(tid, ip, dir);
13884f4b401bSDave Kleikamp if (rc)
13891da177e4SLinus Torvalds goto out3;
13901da177e4SLinus Torvalds
13912a7dba39SEric Paris rc = jfs_init_security(tid, ip, dir, &dentry->d_name);
13921d15b10fSDave Kleikamp if (rc) {
13931d15b10fSDave Kleikamp txAbort(tid, 0);
13941d15b10fSDave Kleikamp goto out3;
13951d15b10fSDave Kleikamp }
13961d15b10fSDave Kleikamp
13974f4b401bSDave Kleikamp if ((rc = dtSearch(dir, &dname, &ino, &btstack, JFS_CREATE))) {
13984f4b401bSDave Kleikamp txAbort(tid, 0);
13994f4b401bSDave Kleikamp goto out3;
14004f4b401bSDave Kleikamp }
14014f4b401bSDave Kleikamp
14021da177e4SLinus Torvalds tblk = tid_to_tblock(tid);
14031da177e4SLinus Torvalds tblk->xflag |= COMMIT_CREATE;
14041da177e4SLinus Torvalds tblk->ino = ip->i_ino;
14051da177e4SLinus Torvalds tblk->u.ixpxd = JFS_IP(ip)->ixpxd;
14061da177e4SLinus Torvalds
14071da177e4SLinus Torvalds ino = ip->i_ino;
14084f4b401bSDave Kleikamp if ((rc = dtInsert(tid, dir, &dname, &ino, &btstack))) {
14094f4b401bSDave Kleikamp txAbort(tid, 0);
14101da177e4SLinus Torvalds goto out3;
14114f4b401bSDave Kleikamp }
14121da177e4SLinus Torvalds
14131da177e4SLinus Torvalds ip->i_op = &jfs_file_inode_operations;
14141da177e4SLinus Torvalds jfs_ip->dev = new_encode_dev(rdev);
14151da177e4SLinus Torvalds init_special_inode(ip, ip->i_mode, rdev);
14161da177e4SLinus Torvalds
14171da177e4SLinus Torvalds mark_inode_dirty(ip);
14181da177e4SLinus Torvalds
1419ad9dc5dfSJeff Layton dir->i_mtime = inode_set_ctime_current(dir);
14201da177e4SLinus Torvalds
14211da177e4SLinus Torvalds mark_inode_dirty(dir);
14221da177e4SLinus Torvalds
14231da177e4SLinus Torvalds iplist[0] = dir;
14241da177e4SLinus Torvalds iplist[1] = ip;
14251da177e4SLinus Torvalds rc = txCommit(tid, 2, iplist, 0);
14261da177e4SLinus Torvalds
14271da177e4SLinus Torvalds out3:
14281da177e4SLinus Torvalds txEnd(tid);
14291de87444SIngo Molnar mutex_unlock(&JFS_IP(ip)->commit_mutex);
14301de87444SIngo Molnar mutex_unlock(&JFS_IP(dir)->commit_mutex);
14311da177e4SLinus Torvalds if (rc) {
14324f4b401bSDave Kleikamp free_ea_wmap(ip);
14336d6b77f1SMiklos Szeredi clear_nlink(ip);
1434a6cbedfaSAl Viro discard_new_inode(ip);
14351f3403faSDave Kleikamp } else {
14361e2e547aSAl Viro d_instantiate_new(dentry, ip);
14371f3403faSDave Kleikamp }
14381da177e4SLinus Torvalds
14391da177e4SLinus Torvalds out1:
14401da177e4SLinus Torvalds free_UCSname(&dname);
14411da177e4SLinus Torvalds
14421da177e4SLinus Torvalds out:
14431da177e4SLinus Torvalds jfs_info("jfs_mknod: returning %d", rc);
14441da177e4SLinus Torvalds return rc;
14451da177e4SLinus Torvalds }
14461da177e4SLinus Torvalds
jfs_lookup(struct inode * dip,struct dentry * dentry,unsigned int flags)144700cd8dd3SAl Viro static struct dentry *jfs_lookup(struct inode *dip, struct dentry *dentry, unsigned int flags)
14481da177e4SLinus Torvalds {
14491da177e4SLinus Torvalds struct btstack btstack;
14501da177e4SLinus Torvalds ino_t inum;
14511da177e4SLinus Torvalds struct inode *ip;
14521da177e4SLinus Torvalds struct component_name key;
14531da177e4SLinus Torvalds int rc;
14541da177e4SLinus Torvalds
1455a455589fSAl Viro jfs_info("jfs_lookup: name = %pd", dentry);
14561da177e4SLinus Torvalds
14571da177e4SLinus Torvalds if ((rc = get_UCSname(&key, dentry)))
14581da177e4SLinus Torvalds return ERR_PTR(rc);
14591da177e4SLinus Torvalds rc = dtSearch(dip, &key, &inum, &btstack, JFS_LOOKUP);
14601da177e4SLinus Torvalds free_UCSname(&key);
14611da177e4SLinus Torvalds if (rc == -ENOENT) {
146279ac5a46SAl Viro ip = NULL;
14631da177e4SLinus Torvalds } else if (rc) {
14641da177e4SLinus Torvalds jfs_err("jfs_lookup: dtSearch returned %d", rc);
146579ac5a46SAl Viro ip = ERR_PTR(rc);
146679ac5a46SAl Viro } else {
1467eab1df71SDavid Howells ip = jfs_iget(dip->i_sb, inum);
1468a9049376SAl Viro if (IS_ERR(ip))
14691da177e4SLinus Torvalds jfs_err("jfs_lookup: iget failed on inum %d", (uint)inum);
147079ac5a46SAl Viro }
14711da177e4SLinus Torvalds
147294b77bd8SAl Viro return d_splice_alias(ip, dentry);
14731da177e4SLinus Torvalds }
14741da177e4SLinus Torvalds
jfs_nfs_get_inode(struct super_block * sb,u64 ino,u32 generation)1475d425de70SChristoph Hellwig static struct inode *jfs_nfs_get_inode(struct super_block *sb,
1476d425de70SChristoph Hellwig u64 ino, u32 generation)
14775ca29607SChristoph Hellwig {
14785ca29607SChristoph Hellwig struct inode *inode;
14795ca29607SChristoph Hellwig
14805ca29607SChristoph Hellwig if (ino == 0)
14815ca29607SChristoph Hellwig return ERR_PTR(-ESTALE);
1482eab1df71SDavid Howells inode = jfs_iget(sb, ino);
1483eab1df71SDavid Howells if (IS_ERR(inode))
1484eab1df71SDavid Howells return ERR_CAST(inode);
14855ca29607SChristoph Hellwig
1486eab1df71SDavid Howells if (generation && inode->i_generation != generation) {
14875ca29607SChristoph Hellwig iput(inode);
1488d425de70SChristoph Hellwig return ERR_PTR(-ESTALE);
1489d425de70SChristoph Hellwig }
1490d425de70SChristoph Hellwig
1491d425de70SChristoph Hellwig return inode;
1492d425de70SChristoph Hellwig }
1493d425de70SChristoph Hellwig
jfs_fh_to_dentry(struct super_block * sb,struct fid * fid,int fh_len,int fh_type)1494d425de70SChristoph Hellwig struct dentry *jfs_fh_to_dentry(struct super_block *sb, struct fid *fid,
1495d425de70SChristoph Hellwig int fh_len, int fh_type)
1496d425de70SChristoph Hellwig {
1497d425de70SChristoph Hellwig return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
1498d425de70SChristoph Hellwig jfs_nfs_get_inode);
1499d425de70SChristoph Hellwig }
1500d425de70SChristoph Hellwig
jfs_fh_to_parent(struct super_block * sb,struct fid * fid,int fh_len,int fh_type)1501d425de70SChristoph Hellwig struct dentry *jfs_fh_to_parent(struct super_block *sb, struct fid *fid,
1502d425de70SChristoph Hellwig int fh_len, int fh_type)
1503d425de70SChristoph Hellwig {
1504d425de70SChristoph Hellwig return generic_fh_to_parent(sb, fid, fh_len, fh_type,
1505d425de70SChristoph Hellwig jfs_nfs_get_inode);
15065ca29607SChristoph Hellwig }
15075ca29607SChristoph Hellwig
jfs_get_parent(struct dentry * dentry)15081da177e4SLinus Torvalds struct dentry *jfs_get_parent(struct dentry *dentry)
15091da177e4SLinus Torvalds {
15101da177e4SLinus Torvalds unsigned long parent_ino;
15111da177e4SLinus Torvalds
15121da177e4SLinus Torvalds parent_ino =
15132b0143b5SDavid Howells le32_to_cpu(JFS_IP(d_inode(dentry))->i_dtroot.header.idotdot);
15141da177e4SLinus Torvalds
1515fc64005cSAl Viro return d_obtain_alias(jfs_iget(dentry->d_sb, parent_ino));
15161da177e4SLinus Torvalds }
15171da177e4SLinus Torvalds
151892e1d5beSArjan van de Ven const struct inode_operations jfs_dir_inode_operations = {
15191da177e4SLinus Torvalds .create = jfs_create,
15201da177e4SLinus Torvalds .lookup = jfs_lookup,
15211da177e4SLinus Torvalds .link = jfs_link,
15221da177e4SLinus Torvalds .unlink = jfs_unlink,
15231da177e4SLinus Torvalds .symlink = jfs_symlink,
15241da177e4SLinus Torvalds .mkdir = jfs_mkdir,
15251da177e4SLinus Torvalds .rmdir = jfs_rmdir,
15261da177e4SLinus Torvalds .mknod = jfs_mknod,
15271da177e4SLinus Torvalds .rename = jfs_rename,
15281da177e4SLinus Torvalds .listxattr = jfs_listxattr,
15291da177e4SLinus Torvalds .setattr = jfs_setattr,
15302ca58e30SMiklos Szeredi .fileattr_get = jfs_fileattr_get,
15312ca58e30SMiklos Szeredi .fileattr_set = jfs_fileattr_set,
1532759bfee6SChristoph Hellwig #ifdef CONFIG_JFS_POSIX_ACL
1533cac2f8b8SChristian Brauner .get_inode_acl = jfs_get_acl,
15342cc6a5a0SChristoph Hellwig .set_acl = jfs_set_acl,
15351da177e4SLinus Torvalds #endif
15361da177e4SLinus Torvalds };
15371da177e4SLinus Torvalds
15383e327154SLinus Torvalds WRAP_DIR_ITER(jfs_readdir) // FIXME!
15394b6f5d20SArjan van de Ven const struct file_operations jfs_dir_operations = {
15401da177e4SLinus Torvalds .read = generic_read_dir,
15413e327154SLinus Torvalds .iterate_shared = shared_jfs_readdir,
15421da177e4SLinus Torvalds .fsync = jfs_fsync,
1543baab81faSAndi Kleen .unlocked_ioctl = jfs_ioctl,
15442ca58e30SMiklos Szeredi .compat_ioctl = compat_ptr_ioctl,
15453222a3e5SChristoph Hellwig .llseek = generic_file_llseek,
15461da177e4SLinus Torvalds };
15471da177e4SLinus Torvalds
jfs_ci_hash(const struct dentry * dir,struct qstr * this)1548da53be12SLinus Torvalds static int jfs_ci_hash(const struct dentry *dir, struct qstr *this)
15491da177e4SLinus Torvalds {
15501da177e4SLinus Torvalds unsigned long hash;
15511da177e4SLinus Torvalds int i;
15521da177e4SLinus Torvalds
15538387ff25SLinus Torvalds hash = init_name_hash(dir);
15541da177e4SLinus Torvalds for (i=0; i < this->len; i++)
15551da177e4SLinus Torvalds hash = partial_name_hash(tolower(this->name[i]), hash);
15561da177e4SLinus Torvalds this->hash = end_name_hash(hash);
15571da177e4SLinus Torvalds
15581da177e4SLinus Torvalds return 0;
15591da177e4SLinus Torvalds }
15601da177e4SLinus Torvalds
jfs_ci_compare(const struct dentry * dentry,unsigned int len,const char * str,const struct qstr * name)15616fa67e70SAl Viro static int jfs_ci_compare(const struct dentry *dentry,
1562621e155aSNick Piggin unsigned int len, const char *str, const struct qstr *name)
15631da177e4SLinus Torvalds {
15641da177e4SLinus Torvalds int i, result = 1;
15651da177e4SLinus Torvalds
1566621e155aSNick Piggin if (len != name->len)
15671da177e4SLinus Torvalds goto out;
1568621e155aSNick Piggin for (i=0; i < len; i++) {
1569621e155aSNick Piggin if (tolower(str[i]) != tolower(name->name[i]))
15701da177e4SLinus Torvalds goto out;
15711da177e4SLinus Torvalds }
15721da177e4SLinus Torvalds result = 0;
15731da177e4SLinus Torvalds out:
15741da177e4SLinus Torvalds return result;
15751da177e4SLinus Torvalds }
15761da177e4SLinus Torvalds
jfs_ci_revalidate(struct dentry * dentry,unsigned int flags)15770b728e19SAl Viro static int jfs_ci_revalidate(struct dentry *dentry, unsigned int flags)
15782bc334dcSNick Piggin {
15792bc334dcSNick Piggin /*
15802bc334dcSNick Piggin * This is not negative dentry. Always valid.
15812bc334dcSNick Piggin *
15822bc334dcSNick Piggin * Note, rename() to existing directory entry will have ->d_inode,
15832bc334dcSNick Piggin * and will use existing name which isn't specified name by user.
15842bc334dcSNick Piggin *
15852bc334dcSNick Piggin * We may be able to drop this positive dentry here. But dropping
15862bc334dcSNick Piggin * positive dentry isn't good idea. So it's unsupported like
15872bc334dcSNick Piggin * rename("filename", "FILENAME") for now.
15882bc334dcSNick Piggin */
15892b0143b5SDavid Howells if (d_really_is_positive(dentry))
15902bc334dcSNick Piggin return 1;
15912bc334dcSNick Piggin
15922bc334dcSNick Piggin /*
15932bc334dcSNick Piggin * This may be nfsd (or something), anyway, we can't see the
15942bc334dcSNick Piggin * intent of this. So, since this can be for creation, drop it.
15952bc334dcSNick Piggin */
15960b728e19SAl Viro if (!flags)
15972bc334dcSNick Piggin return 0;
15982bc334dcSNick Piggin
15992bc334dcSNick Piggin /*
16002bc334dcSNick Piggin * Drop the negative dentry, in order to make sure to use the
16012bc334dcSNick Piggin * case sensitive name which is specified by user if this is
16022bc334dcSNick Piggin * for creation.
16032bc334dcSNick Piggin */
16040b728e19SAl Viro if (flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET))
16052bc334dcSNick Piggin return 0;
16062bc334dcSNick Piggin return 1;
16072bc334dcSNick Piggin }
16082bc334dcSNick Piggin
1609ad28b4efSAl Viro const struct dentry_operations jfs_ci_dentry_operations =
16101da177e4SLinus Torvalds {
16111da177e4SLinus Torvalds .d_hash = jfs_ci_hash,
16121da177e4SLinus Torvalds .d_compare = jfs_ci_compare,
16132bc334dcSNick Piggin .d_revalidate = jfs_ci_revalidate,
16141da177e4SLinus Torvalds };
1615