-/*
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
*
* This code is issued under the GNU General Public License.
* See the file COPYING in this distribution
* David S. Miller (davem@caip.rutgers.edu), 1995
* Directory entry file type support and forward compatibility hooks
* for B-tree directories by Theodore Ts'o (tytso@mit.edu), 1998
- *
+ *
* Changes for use in OBDFS
* Copyright (c) 1999, Seagate Technology Inc.
* Copyright (C) 2001, Cluster File Systems, Inc.
* Rewritten based on recent ext2 page cache use.
- *
+ *
*/
#include <linux/fs.h>
#include <linux/locks.h>
#include <linux/quotaops.h>
+
+#define DEBUG_SUBSYSTEM S_LLITE
+
#include <linux/obd_support.h>
-#include <linux/lustre_light.h>
+#include <linux/lustre_lite.h>
+#include <linux/lustre_dlm.h>
extern struct address_space_operations ll_aops;
/* from super.c */
/* from dir.c */
extern int ll_add_link (struct dentry *dentry, struct inode *inode);
-ino_t ll_inode_by_name(struct inode * dir, struct dentry *dentry, int *typ);
+obd_id ll_inode_by_name(struct inode * dir, struct dentry *dentry, int *typ);
int ext2_make_empty(struct inode *inode, struct inode *parent);
struct ext2_dir_entry_2 * ext2_find_entry (struct inode * dir,
- struct dentry *dentry, struct page ** res_page);
+ struct dentry *dentry, struct page ** res_page);
int ext2_delete_entry (struct ext2_dir_entry_2 * dir, struct page * page );
int ext2_empty_dir (struct inode * inode);
struct ext2_dir_entry_2 * ext2_dotdot (struct inode *dir, struct page **p);
void ext2_set_link(struct inode *dir, struct ext2_dir_entry_2 *de,
- struct page *page, struct inode *inode);
+ struct page *page, struct inode *inode);
/*
* Couple of helper functions - make the code slightly cleaner.
*/
static inline void ext2_inc_count(struct inode *inode)
{
- inode->i_nlink++;
+ inode->i_nlink++;
}
-/* postpone the disk update until the inode really goes away */
+/* postpone the disk update until the inode really goes away */
static inline void ext2_dec_count(struct inode *inode)
{
- inode->i_nlink--;
+ inode->i_nlink--;
}
static inline int ext2_add_nondir(struct dentry *dentry, struct inode *inode)
{
- int err;
- err = ll_add_link(dentry, inode);
- if (!err) {
- d_instantiate(dentry, inode);
- return 0;
- }
- ext2_dec_count(inode);
- iput(inode);
- return err;
+ int err;
+ err = ll_add_link(dentry, inode);
+ if (!err) {
+ d_instantiate(dentry, inode);
+ return 0;
+ }
+ ext2_dec_count(inode);
+ iput(inode);
+ return err;
}
/* methods */
-static struct dentry *ll_lookup(struct inode * dir, struct dentry *dentry)
+static int ll_find_inode(struct inode *inode, unsigned long ino, void *opaque)
{
- struct mds_rep *rep;
- struct ptlrep_hdr *hdr = NULL;
- struct inode * inode = NULL;
- int err;
- int type;
- ino_t ino;
-
- ENTRY;
- if (dentry->d_name.len > EXT2_NAME_LEN)
- return ERR_PTR(-ENAMETOOLONG);
+ struct mds_body *body = (struct mds_body *)opaque;
- ino = ll_inode_by_name(dir, dentry, &type);
- if (!ino)
- goto negative;
+ if (inode->i_generation != body->generation)
+ return 0;
- err = mdc_getattr(ino, type, OBD_MD_FLNOTOBD|OBD_MD_FLBLOCKS,
- &rep, &hdr);
- if ( err ) {
- printk(__FUNCTION__ ": obdo_fromid failed\n");
- EXIT;
- return ERR_PTR(-EACCES);
- }
+ return 1;
+}
+
+extern struct dentry_operations ll_d_ops;
- inode = iget4(dir->i_sb, ino, NULL, rep);
- kfree(hdr);
+int ll_lock(struct inode *dir, struct dentry *dentry,
+ struct lookup_intent *it, struct lustre_handle *lockh)
+{
+ struct ll_sb_info *sbi = ll_i2sbi(dir);
+ int err, lock_mode;
+
+ if ((it->it_op & (IT_CREAT | IT_MKDIR | IT_SYMLINK | IT_SETATTR |
+ IT_MKNOD)))
+ lock_mode = LCK_PW;
+ else if (it->it_op & (IT_READDIR | IT_GETATTR | IT_OPEN | IT_UNLINK |
+ IT_RMDIR | IT_RENAME | IT_RENAME2))
+ lock_mode = LCK_PR;
+ else if (it->it_op & IT_LOOKUP)
+ lock_mode = LCK_CR;
+ else {
+ LBUG();
+ RETURN(-1);
+ }
- if (!inode)
- return ERR_PTR(-EACCES);
+ err = mdc_enqueue(&sbi->ll_mdc_conn, LDLM_MDSINTENT, it, lock_mode, dir,
+ dentry, lockh, 0, NULL, 0, dir, sizeof(*dir));
- negative:
- d_add(dentry, inode);
- return NULL;
+ RETURN(err);
}
+int ll_unlock(__u32 mode, struct lustre_handle *lockh)
+{
+ ENTRY;
+
+ ldlm_lock_decref(lockh, mode);
-/*
- * NOTE! unlike strncmp, ext2_match returns 1 for success, 0 for failure.
- *
- * `len <= EXT2_NAME_LEN' is guaranteed by caller.
- * `de != NULL' is guaranteed by caller.
- */
-static inline int ext2_match (int len, const char * const name,
- struct ext2_dir_entry_2 * de)
+ RETURN(0);
+}
+
+static struct dentry *ll_lookup2(struct inode * dir, struct dentry *dentry,
+ struct lookup_intent *it)
{
- if (len != de->name_len)
- return 0;
- if (!de->inode)
- return 0;
- return !memcmp(name, de->name, len);
+ struct ptlrpc_request *request = NULL;
+ struct inode * inode = NULL;
+ struct ll_sb_info *sbi = ll_i2sbi(dir);
+ struct ll_inode_md md;
+ struct lustre_handle lockh;
+ int err, type, offset;
+ struct lookup_intent lookup_it = { IT_LOOKUP };
+ obd_id ino;
+
+ ENTRY;
+
+ if (it == NULL) {
+ it = &lookup_it;
+ dentry->d_it = it;
+ }
+
+ CDEBUG(D_INFO, "name: %*s, intent op: %d\n", dentry->d_name.len,
+ dentry->d_name.name, it->it_op);
+
+ if (dentry->d_name.len > EXT2_NAME_LEN)
+ RETURN(ERR_PTR(-ENAMETOOLONG));
+
+ err = ll_lock(dir, dentry, it, &lockh);
+ if (err < 0) {
+ /* FIXME: Mike LBUG() can disappear the moment that
+ * ll_lock has sane interrupt behavior
+ */
+ LBUG();
+ RETURN(ERR_PTR(err));
+ }
+ memcpy(it->it_lock_handle, &lockh, sizeof(lockh));
+
+ if ((it->it_op & (IT_CREAT | IT_MKDIR | IT_SYMLINK | IT_MKNOD)) &&
+ it->it_disposition && !it->it_status)
+ GOTO(negative, NULL);
+
+ if ((it->it_op & (IT_RENAME | IT_GETATTR | IT_UNLINK | IT_RMDIR |
+ IT_SETATTR | IT_LOOKUP)) &&
+ it->it_disposition && it->it_status)
+ GOTO(negative, NULL);
+
+ request = (struct ptlrpc_request *)it->it_data;
+ if (!it->it_disposition) {
+ struct ll_inode_info *lli = ll_i2info(dir);
+ memcpy(&lli->lli_intent_lock_handle, &lockh, sizeof(lockh));
+
+ ino = ll_inode_by_name(dir, dentry, &type);
+#warning FIXME: handle negative inode case (see old ll_lookup)
+
+ err = mdc_getattr(&sbi->ll_mdc_conn, ino, type,
+ OBD_MD_FLNOTOBD|OBD_MD_FLBLOCKS, 0, &request);
+ if (err) {
+ CERROR("failure %d inode %Ld\n", err, (long long)ino);
+ ptlrpc_free_req(request);
+ RETURN(ERR_PTR(-abs(err)));
+ }
+ offset = 0;
+ } else if (it->it_op == IT_RENAME2) {
+ inode = ((struct dentry *)(it->it_data))->d_inode;
+ GOTO(out_req, NULL);
+ } else {
+ offset = 1;
+ }
+
+ md.body = lustre_msg_buf(request->rq_repmsg, offset);
+ if (S_ISREG(md.body->mode)) {
+ if (request->rq_repmsg->bufcount < offset + 1)
+ LBUG();
+ md.md = lustre_msg_buf(request->rq_repmsg, offset + 1);
+ } else
+ md.md = NULL;
+
+ /* No rpc's happen during iget4, -ENOMEM's are possible */
+ inode = iget4(dir->i_sb, ino, ll_find_inode, &md);
+ if (it->it_op & IT_RENAME)
+ it->it_data = dentry;
+
+ out_req:
+ ptlrpc_free_req(request);
+ if (!inode || IS_ERR(inode)) {
+ ll_intent_release(dentry);
+ RETURN(ERR_PTR(-ENOMEM));
+ }
+ EXIT;
+ negative:
+ dentry->d_op = &ll_d_ops;
+ d_add(dentry, inode);
+ if (it->it_op == IT_LOOKUP)
+ ll_intent_release(dentry);
+
+ return NULL;
}
-static struct inode *ll_create_node(struct inode *dir, const char *name,
- int namelen, int mode, __u64 id)
+static struct inode *ll_create_node(struct inode *dir, const char *name,
+ int namelen, const char *tgt, int tgtlen,
+ int mode, __u64 extra,
+ struct lookup_intent *it,
+ struct lov_stripe_md *smd)
{
struct inode *inode;
- struct mds_rep *rep;
- struct ptlrep_hdr *hdr;
- int err;
+ struct ptlrpc_request *request = NULL;
+ struct mds_body *body;
+ int rc;
+ time_t time = CURRENT_TIME;
+ struct ll_sb_info *sbi = ll_i2sbi(dir);
+ int gid = current->fsgid;
+ struct ll_inode_md md;
ENTRY;
- err = mdc_create(dir, name, namelen, mode, id,
- current->uid, current->gid, CURRENT_TIME,
- &rep, &hdr);
- if (err) {
- EXIT;
- return ERR_PTR(err);
- }
- if ( hdr->status) {
- EXIT;
- return ERR_PTR(hdr->status);
- }
- rep->valid = OBD_MD_FLNOTOBD;
-
- rep->objid = id;
- rep->nlink = 1;
- rep->mode = mode;
- printk("-- new_inode: objid %lld, ino %d, mode %o\n",
- rep->objid, rep->ino, rep->mode);
-
- inode = iget4(dir->i_sb, rep->ino, NULL, rep);
+ if (dir->i_mode & S_ISGID) {
+ gid = dir->i_gid;
+ if (S_ISDIR(mode))
+ mode |= S_ISGID;
+ }
+
+ if (!it->it_disposition) {
+ rc = mdc_create(&sbi->ll_mdc_conn, dir, name, namelen, tgt,
+ tgtlen, mode, current->fsuid,
+ gid, time, extra, smd, &request);
+ if (rc) {
+ inode = ERR_PTR(rc);
+ GOTO(out, rc);
+ }
+ body = lustre_msg_buf(request->rq_repmsg, 0);
+ md.md = smd;
+ } else {
+ request = it->it_data;
+ body = lustre_msg_buf(request->rq_repmsg, 1);
+ md.md = NULL;
+ }
+
+ body->valid = OBD_MD_FLNOTOBD;
+
+ body->nlink = 1;
+ body->atime = body->ctime = body->mtime = time;
+ body->uid = current->fsuid;
+ body->gid = gid;
+ body->mode = mode;
+
+ md.body = body;
+
+ inode = iget4(dir->i_sb, body->ino, ll_find_inode, &md);
if (IS_ERR(inode)) {
- printk(__FUNCTION__ ": new_inode -fatal: %ld\n",
- PTR_ERR(inode));
- EXIT;
- return ERR_PTR(-EIO);
+ rc = PTR_ERR(inode);
+ CERROR("new_inode -fatal: rc %d\n", rc);
+ LBUG();
+ GOTO(out, rc);
}
if (!list_empty(&inode->i_dentry)) {
- printk("new_inode -fatal: aliases %d, ct %d lnk %d\n",
- rep->ino, atomic_read(&inode->i_count),
- inode->i_nlink);
+ CERROR("new_inode -fatal: inode %d, ct %d lnk %d\n",
+ body->ino, atomic_read(&inode->i_count),
+ inode->i_nlink);
iput(inode);
- EXIT;
- return ERR_PTR(-EIO);
+ LBUG();
+ inode = ERR_PTR(-EIO);
+ GOTO(out, -EIO);
}
EXIT;
+ out:
+ ptlrpc_free_req(request);
return inode;
-} /* ll_new_inode */
+}
+int ll_mdc_unlink(struct inode *dir, struct inode *child,
+ const char *name, int len)
+{
+ struct ptlrpc_request *request = NULL;
+ int err;
+ struct ll_sb_info *sbi = ll_i2sbi(dir);
+
+ ENTRY;
+
+ err = mdc_unlink(&sbi->ll_mdc_conn, dir, child,
+ name, len, &request);
+ ptlrpc_free_req(request);
+
+ RETURN(err);
+}
+
+int ll_mdc_link(struct dentry *src, struct inode *dir,
+ const char *name, int len)
+{
+ struct ptlrpc_request *request = NULL;
+ int err;
+ struct ll_sb_info *sbi = ll_i2sbi(dir);
+
+ ENTRY;
+
+ err = mdc_link(&sbi->ll_mdc_conn, src, dir, name,
+ len, &request);
+ ptlrpc_free_req(request);
+
+ RETURN(err);
+}
+
+int ll_mdc_rename(struct inode *src, struct inode *tgt,
+ struct dentry *old, struct dentry *new)
+{
+ struct ptlrpc_request *request = NULL;
+ struct ll_sb_info *sbi = ll_i2sbi(src);
+ int err;
+
+ ENTRY;
+
+ err = mdc_rename(&sbi->ll_mdc_conn, src, tgt,
+ old->d_name.name, old->d_name.len,
+ new->d_name.name, new->d_name.len, &request);
+ ptlrpc_free_req(request);
+
+ RETURN(err);
+}
/*
* By the time this is called, we already have created
* is so far negative - it has no inode.
*
* If the create succeeds, we fill in the inode information
- * with d_instantiate().
+ * with d_instantiate().
*/
-static int ll_create (struct inode * dir, struct dentry * dentry, int mode)
+
+static int ll_create(struct inode * dir, struct dentry * dentry, int mode)
{
- int err;
- struct obdo oa;
- struct inode * inode;
-
- err = obd_create(IID(dir), &oa);
- if (err) {
- EXIT;
- return err;
- }
-
- mode = mode | S_IFREG;
- printk("ll_create: name %s mode %o\n", dentry->d_name.name, mode);
- inode = ll_create_node(dir, dentry->d_name.name,
- dentry->d_name.len,
- mode, oa.o_id);
- err = PTR_ERR(inode);
- if (!IS_ERR(inode)) {
- // XXX clean up the object
- inode->i_op = &ll_file_inode_operations;
- inode->i_fop = &ll_file_operations;
- inode->i_mapping->a_ops = &ll_aops;
- err = ext2_add_nondir(dentry, inode);
- }
- EXIT;
- return err;
-} /* ll_create */
-
-
-static int ll_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev)
+ int err, rc = 0;
+ struct obdo oa;
+ struct inode *inode;
+ struct lov_stripe_md *smd;
+ struct ll_inode_info *ii;
+
+ if (dentry->d_it->it_disposition == 0) {
+ memset(&oa, 0, sizeof(oa));
+ oa.o_valid = OBD_MD_FLMODE;
+ oa.o_mode = S_IFREG | 0600;
+ rc = obd_create(ll_i2obdconn(dir), &oa, &smd);
+ if (rc)
+ RETURN(rc);
+ }
+
+ mode = mode | S_IFREG;
+ CDEBUG(D_DENTRY, "name %s mode %o o_id %lld\n",
+ dentry->d_name.name, mode, (unsigned long long)oa.o_id);
+ inode = ll_create_node(dir, dentry->d_name.name, dentry->d_name.len,
+ NULL, 0, mode, 0, dentry->d_it, smd);
+
+ if (IS_ERR(inode)) {
+ rc = PTR_ERR(inode);
+ CERROR("error creating MDS object for id %Ld: rc = %d\n",
+ (unsigned long long)oa.o_id, rc);
+ GOTO(out_destroy, rc);
+ }
+
+ if (dentry->d_it->it_disposition) {
+ struct ll_inode_info *ii = ll_i2info(inode);
+ ii->lli_flags |= OBD_FL_CREATEONOPEN;
+ memcpy(&ii->lli_intent_lock_handle,
+ dentry->d_it->it_lock_handle,
+ sizeof(struct lustre_handle));
+ }
+
+ /* no directory data updates when intents rule */
+ if (dentry->d_it->it_disposition == 0)
+ rc = ext2_add_nondir(dentry, inode);
+ else
+ d_instantiate(dentry, inode);
+ RETURN(rc);
+
+out_destroy:
+ oa.o_easize = ii->lli_smd->lmd_size;
+ err = obd_destroy(ll_i2obdconn(dir), &oa, ii->lli_smd);
+ if (err)
+ CERROR("error destroying object %Ld in error path: err = %d\n",
+ (unsigned long long)oa.o_id, err);
+ return rc;
+}
+
+static int ll_mknod(struct inode *dir, struct dentry *dentry, int mode,
+ int rdev)
{
- struct inode * inode = ll_create_node(dir, dentry->d_name.name,
- dentry->d_name.len, mode, 0);
- int err = PTR_ERR(inode);
- if (!IS_ERR(inode)) {
- init_special_inode(inode, mode, rdev);
- err = ext2_add_nondir(dentry, inode);
- }
- return err;
+ struct inode * inode = ll_create_node(dir, dentry->d_name.name,
+ dentry->d_name.len, NULL, 0,
+ mode, rdev, NULL, NULL);
+ int err = PTR_ERR(inode);
+ if (!IS_ERR(inode))
+ err = ext2_add_nondir(dentry, inode);
+ return err;
}
-static int ll_symlink (struct inode * dir, struct dentry * dentry,
- const char * symname)
+static int ll_symlink(struct inode *dir, struct dentry *dentry,
+ const char *symname)
{
- struct super_block * sb = dir->i_sb;
- int err = -ENAMETOOLONG;
- unsigned l = strlen(symname)+1;
- struct inode * inode;
+ int err = -ENAMETOOLONG;
+ unsigned l = strlen(symname);
+ struct inode * inode;
struct ll_inode_info *oinfo;
- if (l > sb->s_blocksize)
- goto out;
-
- inode = ll_create_node(dir, dentry->d_name.name,
- dentry->d_name.len,
- S_IFLNK | S_IRWXUGO, 0);
- err = PTR_ERR(inode);
- if (IS_ERR(inode))
- goto out;
+ inode = ll_create_node(dir, dentry->d_name.name,
+ dentry->d_name.len, symname, l,
+ S_IFLNK | S_IRWXUGO, 0, dentry->d_it, NULL);
+ err = PTR_ERR(inode);
+ if (IS_ERR(inode))
+ return err;
oinfo = ll_i2info(inode);
- if (l >= sizeof(oinfo->lli_inline)) {
- /* slow symlink */
- inode->i_op = &page_symlink_inode_operations;
- inode->i_mapping->a_ops = &ll_aops;
- err = block_symlink(inode, symname, l);
- if (err)
- goto out_fail;
- } else {
- /* fast symlink */
- inode->i_op = &ll_fast_symlink_inode_operations;
- memcpy(oinfo->lli_inline, symname, l);
- inode->i_size = l-1;
- }
-
- err = ext2_add_nondir(dentry, inode);
-out:
- return err;
-out_fail:
- ext2_dec_count(inode);
- iput (inode);
- goto out;
-}
+ OBD_ALLOC(oinfo->lli_symlink_name, l + 1);
+ memcpy(oinfo->lli_symlink_name, symname, l + 1);
+ inode->i_size = l;
+ err = ext2_add_nondir(dentry, inode);
+ if (err) {
+ ext2_dec_count(inode);
+ iput (inode);
+ }
+ return err;
+}
-static int ll_link (struct dentry * old_dentry, struct inode * dir,
- struct dentry *dentry)
+static int ll_link(struct dentry * old_dentry, struct inode * dir,
+ struct dentry *dentry)
{
- struct inode *inode = old_dentry->d_inode;
+ int err;
+ struct inode *inode = old_dentry->d_inode;
- if (S_ISDIR(inode->i_mode))
- return -EPERM;
+ if (S_ISDIR(inode->i_mode))
+ return -EPERM;
- if (inode->i_nlink >= EXT2_LINK_MAX)
- return -EMLINK;
+ if (inode->i_nlink >= EXT2_LINK_MAX)
+ return -EMLINK;
- inode->i_ctime = CURRENT_TIME;
- ext2_inc_count(inode);
- atomic_inc(&inode->i_count);
+ err = ll_mdc_link(old_dentry, dir,
+ dentry->d_name.name, dentry->d_name.len);
+ if (err) {
+ EXIT;
+ return err;
+ }
- return ext2_add_nondir(dentry, inode);
-}
+ inode->i_ctime = CURRENT_TIME;
+ ext2_inc_count(inode);
+ atomic_inc(&inode->i_count);
+ return ext2_add_nondir(dentry, inode);
+}
static int ll_mkdir(struct inode * dir, struct dentry * dentry, int mode)
{
- struct inode * inode;
- int err = -EMLINK;
- ENTRY;
-
- if (dir->i_nlink >= EXT2_LINK_MAX)
- goto out;
+ struct inode * inode;
+ int err = -EMLINK;
+ ENTRY;
- ext2_inc_count(dir);
+ if (dir->i_nlink >= EXT2_LINK_MAX)
+ goto out;
- inode = ll_create_node (dir, dentry->d_name.name,
- dentry->d_name.len,
- S_IFDIR | mode, 0);
- err = PTR_ERR(inode);
- if (IS_ERR(inode))
- goto out_dir;
+ ext2_inc_count(dir);
- inode->i_op = &ll_dir_inode_operations;
- inode->i_fop = &ll_dir_operations;
- inode->i_mapping->a_ops = &ll_aops;
+ inode = ll_create_node (dir, dentry->d_name.name,
+ dentry->d_name.len, NULL, 0,
+ S_IFDIR | mode, 0, dentry->d_it, NULL);
+ err = PTR_ERR(inode);
+ if (IS_ERR(inode))
+ goto out_dir;
- ext2_inc_count(inode);
+ inode->i_nlink = 1;
+ ext2_inc_count(inode);
- err = ext2_make_empty(inode, dir);
- if (err)
- goto out_fail;
+ err = ext2_make_empty(inode, dir);
+ if (err)
+ goto out_fail;
- err = ll_add_link(dentry, inode);
- if (err)
- goto out_fail;
+ /* no directory data updates when intents rule */
+ if (dentry->d_it->it_disposition == 0) {
+ err = ll_add_link(dentry, inode);
+ if (err)
+ goto out_fail;
+ }
- d_instantiate(dentry, inode);
+ d_instantiate(dentry, inode);
out:
- EXIT;
- return err;
+ EXIT;
+ return err;
out_fail:
- ext2_dec_count(inode);
- ext2_dec_count(inode);
- iput(inode);
- EXIT;
+ ext2_dec_count(inode);
+ ext2_dec_count(inode);
+ iput(inode);
+ EXIT;
out_dir:
- ext2_dec_count(dir);
- EXIT;
- goto out;
+ ext2_dec_count(dir);
+ EXIT;
+ goto out;
}
static int ll_unlink(struct inode * dir, struct dentry *dentry)
{
- struct inode * inode = dentry->d_inode;
- struct ext2_dir_entry_2 * de;
- struct page * page;
- int err = -ENOENT;
-
- de = ext2_find_entry (dir, dentry, &page);
- if (!de)
- goto out;
-
- err = ext2_delete_entry (de, page);
- if (err)
- goto out;
-
- inode->i_ctime = dir->i_ctime;
- ext2_dec_count(inode);
- err = 0;
+ struct inode * inode = dentry->d_inode;
+ struct ext2_dir_entry_2 * de;
+ struct page * page;
+ int err = -ENOENT;
+
+ if (dentry->d_it && dentry->d_it->it_disposition) {
+ inode->i_nlink = 0;
+ GOTO(out, err = dentry->d_it->it_status);
+ }
+
+ de = ext2_find_entry (dir, dentry, &page);
+ if (!de)
+ goto out;
+
+ err = ll_mdc_unlink(dir, dentry->d_inode,
+ dentry->d_name.name, dentry->d_name.len);
+ if (err)
+ goto out;
+
+ err = ext2_delete_entry (de, page);
+ if (err)
+ goto out;
+
+ inode->i_ctime = dir->i_ctime;
+ ext2_dec_count(inode);
out:
- return err;
+ return err;
}
-
-static int ll_rmdir (struct inode * dir, struct dentry *dentry)
+static int ll_rmdir(struct inode * dir, struct dentry *dentry)
{
- struct inode * inode = dentry->d_inode;
- int err = -ENOTEMPTY;
-
- if (ext2_empty_dir(inode)) {
- err = ll_unlink(dir, dentry);
- if (!err) {
- inode->i_size = 0;
- ext2_dec_count(inode);
- ext2_dec_count(dir);
- }
- }
- return err;
+ struct inode * inode = dentry->d_inode;
+ int err = 0;
+ int intent_did = dentry->d_it && dentry->d_it->it_disposition;
+
+ if (!intent_did) {
+ if (!ext2_empty_dir(inode))
+ LBUG();
+
+ err = ll_unlink(dir, dentry);
+ if (err)
+ RETURN(err);
+ } else
+ err = dentry->d_it->it_status;
+ inode->i_size = 0;
+ ext2_dec_count(inode);
+ ext2_dec_count(dir);
+ RETURN(err);
}
-static int ll_rename (struct inode * old_dir, struct dentry * old_dentry,
- struct inode * new_dir, struct dentry * new_dentry )
+static int ll_rename(struct inode * old_dir, struct dentry * old_dentry,
+ struct inode * new_dir, struct dentry * new_dentry)
{
- struct inode * old_inode = old_dentry->d_inode;
- struct inode * new_inode = new_dentry->d_inode;
- struct page * dir_page = NULL;
- struct ext2_dir_entry_2 * dir_de = NULL;
- struct page * old_page;
- struct ext2_dir_entry_2 * old_de;
- int err = -ENOENT;
-
- old_de = ext2_find_entry (old_dir, old_dentry, &old_page);
- if (!old_de)
- goto out;
-
- if (S_ISDIR(old_inode->i_mode)) {
- err = -EIO;
- dir_de = ext2_dotdot(old_inode, &dir_page);
- if (!dir_de)
- goto out_old;
- }
-
- if (new_inode) {
- struct page *new_page;
- struct ext2_dir_entry_2 *new_de;
-
- err = -ENOTEMPTY;
- if (dir_de && !ext2_empty_dir (new_inode))
- goto out_dir;
-
- err = -ENOENT;
- new_de = ext2_find_entry (new_dir, new_dentry, &new_page);
- if (!new_de)
- goto out_dir;
- ext2_inc_count(old_inode);
- ext2_set_link(new_dir, new_de, new_page, old_inode);
- new_inode->i_ctime = CURRENT_TIME;
- if (dir_de)
- new_inode->i_nlink--;
- ext2_dec_count(new_inode);
- } else {
- if (dir_de) {
- err = -EMLINK;
- if (new_dir->i_nlink >= EXT2_LINK_MAX)
- goto out_dir;
- }
- ext2_inc_count(old_inode);
- err = ll_add_link(new_dentry, old_inode);
- if (err) {
- ext2_dec_count(old_inode);
- goto out_dir;
- }
- if (dir_de)
- ext2_inc_count(new_dir);
- }
-
- ext2_delete_entry (old_de, old_page);
- ext2_dec_count(old_inode);
-
- if (dir_de) {
- ext2_set_link(old_inode, dir_de, dir_page, new_dir);
- ext2_dec_count(old_dir);
- }
- return 0;
+ struct inode * old_inode = old_dentry->d_inode;
+ struct inode * new_inode = new_dentry->d_inode;
+ struct page * dir_page = NULL;
+ struct ext2_dir_entry_2 * dir_de = NULL;
+ struct page * old_page;
+ struct ext2_dir_entry_2 * old_de;
+ int err = -ENOENT;
+
+ if (new_dentry->d_it && new_dentry->d_it->it_disposition)
+ GOTO(out, err = new_dentry->d_it->it_status);
+
+ err = ll_mdc_rename(old_dir, new_dir, old_dentry, new_dentry);
+ if (err)
+ goto out;
+
+ old_de = ext2_find_entry (old_dir, old_dentry, &old_page);
+ if (!old_de)
+ goto out;
+
+ if (S_ISDIR(old_inode->i_mode)) {
+ err = -EIO;
+ dir_de = ext2_dotdot(old_inode, &dir_page);
+ if (!dir_de)
+ goto out_old;
+ }
+
+ if (new_inode) {
+ struct page *new_page;
+ struct ext2_dir_entry_2 *new_de;
+
+ err = -ENOTEMPTY;
+ if (dir_de && !ext2_empty_dir (new_inode))
+ goto out_dir;
+
+ err = -ENOENT;
+ new_de = ext2_find_entry (new_dir, new_dentry, &new_page);
+ if (!new_de)
+ goto out_dir;
+ ext2_inc_count(old_inode);
+ ext2_set_link(new_dir, new_de, new_page, old_inode);
+ new_inode->i_ctime = CURRENT_TIME;
+ if (dir_de)
+ new_inode->i_nlink--;
+ ext2_dec_count(new_inode);
+ } else {
+ if (dir_de) {
+ err = -EMLINK;
+ if (new_dir->i_nlink >= EXT2_LINK_MAX)
+ goto out_dir;
+ }
+ ext2_inc_count(old_inode);
+ err = ll_add_link(new_dentry, old_inode);
+ if (err) {
+ ext2_dec_count(old_inode);
+ goto out_dir;
+ }
+ if (dir_de)
+ ext2_inc_count(new_dir);
+ }
+ ext2_delete_entry (old_de, old_page);
+ ext2_dec_count(old_inode);
+
+ if (dir_de) {
+ ext2_set_link(old_inode, dir_de, dir_page, new_dir);
+ ext2_dec_count(old_dir);
+ }
+ return 0;
out_dir:
- if (dir_de) {
- kunmap(dir_page);
- page_cache_release(dir_page);
- }
+ if (dir_de) {
+ kunmap(dir_page);
+ page_cache_release(dir_page);
+ }
out_old:
- kunmap(old_page);
- page_cache_release(old_page);
+ kunmap(old_page);
+ page_cache_release(old_page);
out:
- return err;
+ return err;
}
struct inode_operations ll_dir_inode_operations = {
- create: ll_create,
- lookup: ll_lookup,
- link: ll_link,
- unlink: ll_unlink,
- symlink: ll_symlink,
- mkdir: ll_mkdir,
- rmdir: ll_rmdir,
- mknod: ll_mknod,
- rename: ll_rename,
- setattr: ll_setattr
+ create: ll_create,
+ lookup2: ll_lookup2,
+ link: ll_link,
+ unlink: ll_unlink,
+ symlink: ll_symlink,
+ mkdir: ll_mkdir,
+ rmdir: ll_rmdir,
+ mknod: ll_mknod,
+ rename: ll_rename,
+ setattr: ll_setattr
};