X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lustre%2Fllite%2Fnamei.c;h=61cf15b6ca697db84739a2ee7577e3c4ac80943b;hb=40e5945377e1b71dbd6afeaa10ea17f2b876db86;hp=c6bc754cacc4876a85de327c2ebe3829871dd578;hpb=baf1a0763f7713c1c356a5691b2bc0bfbf23e2b7;p=fs%2Flustre-release.git diff --git a/lustre/llite/namei.c b/lustre/llite/namei.c index c6bc754..61cf15b 100644 --- a/lustre/llite/namei.c +++ b/lustre/llite/namei.c @@ -1,17 +1,24 @@ /* -*- 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 + * Copyright (c) 2002, 2003 Cluster File Systems, Inc. * - * Copyright (C) 1992, 1993, 1994, 1995 - * Remy Card (card@masi.ibp.fr) - * Laboratoire MASI - Institut Blaise Pascal - * Universite Pierre et Marie Curie (Paris VI) + * This file is part of Lustre, http://www.lustre.org. * - * from + * Lustre is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. * - * linux/fs/ext2/namei.c + * Lustre is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Lustre; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * derived in small part from linux/fs/ext2/namei.c * * Copyright (C) 1991, 1992 Linus Torvalds * @@ -19,12 +26,6 @@ * 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 @@ -40,102 +41,60 @@ #include #include #include -#include - -extern struct address_space_operations ll_aops; - -/* from super.c */ -extern void ll_change_inode(struct inode *inode); -extern int ll_setattr(struct dentry *de, struct iattr *attr); - -/* from dir.c */ -extern int ll_add_link (struct dentry *dentry, struct inode *inode); -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); -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); +#include +#include "llite_internal.h" -/* - * Couple of helper functions - make the code slightly cleaner. - */ -static inline void ext2_inc_count(struct inode *inode) -{ - inode->i_nlink++; -} +/* methods */ -/* postpone the disk update until the inode really goes away */ -static inline void ext2_dec_count(struct inode *inode) +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) +static int ll_test_inode(struct inode *inode, unsigned long ino, void *opaque) +#else +static int ll_test_inode(struct inode *inode, void *opaque) +#endif { - inode->i_nlink--; -} + static int last_ino, last_gen, last_count; + struct lustre_md *md = opaque; -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); + if (!(md->body->valid & (OBD_MD_FLGENER | OBD_MD_FLID))) { + CERROR("MDS body missing inum or generation\n"); return 0; } - ext2_dec_count(inode); - iput(inode); - return err; -} -/* methods */ -static int ll_test_inode(struct inode *inode, void *opaque) -{ - struct ll_read_inode2_cookie *lic = opaque; - struct mds_body *body = lic->lic_body; + if (last_ino == md->body->ino && last_gen == md->body->generation && + last_count < 500) { + last_count++; + } else { + if (last_count > 1) + CDEBUG(D_VFSTRACE, "compared %u/%u %u times\n", + last_ino, last_gen, last_count); + last_count = 0; + last_ino = md->body->ino; + last_gen = md->body->generation; + CDEBUG(D_VFSTRACE, + "comparing inode %p ino %lu/%u/%u to body %u/%u/%u\n", + inode, inode->i_ino, inode->i_generation, + ll_i2info(inode)->lli_mds, + md->body->ino, md->body->generation, + md->body->mds); + } + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) + if (inode->i_ino != md->body->ino) + return 0; +#endif + if (inode->i_generation != md->body->generation) + return 0; - if (inode->i_generation != lic->lic_body->generation) + if (ll_i2info(inode)->lli_mds != md->body->mds) return 0; /* Apply the attributes in 'opaque' to this inode */ - ll_update_inode(inode, body); - + ll_update_inode(inode, md); return 1; } extern struct dentry_operations ll_d_ops; -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); - char *tgt = NULL; - int tgtlen = 0; - int err, lock_mode; - - /* CREAT needs to be tested before open (both could be set) */ - if ((it->it_op & (IT_CREAT | IT_MKDIR | 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 | IT_READLINK| - IT_LINK | IT_LINK2 | IT_LOOKUP)) { - /* XXXphil PW for LINK2/RENAME2? */ - lock_mode = LCK_PR; - } else if (it->it_op & IT_SYMLINK) { - lock_mode = LCK_PW; - tgt = it->it_data; - tgtlen = strlen(tgt); - it->it_data = NULL; - } else { - LBUG(); - RETURN(-EINVAL); - } - - err = mdc_enqueue(&sbi->ll_mdc_conn, LDLM_MDSINTENT, it, lock_mode, - dir, dentry, lockh, tgt, tgtlen, dir, sizeof(*dir)); - - RETURN(err); -} - int ll_unlock(__u32 mode, struct lustre_handle *lockh) { ENTRY; @@ -145,708 +104,726 @@ int ll_unlock(__u32 mode, struct lustre_handle *lockh) RETURN(0); } +/* Get an inode by inode number (already instantiated by the intent lookup). + * Returns inode or NULL + */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) -extern int ll_read_inode2(struct inode *inode, void *opaque); -struct inode *ll_iget(struct super_block *sb, ino_t hash, - struct ll_read_inode2_cookie *lic) +int ll_set_inode(struct inode *inode, void *opaque) { - struct inode *inode; + ll_read_inode2(inode, opaque); + return 0; +} - inode = iget5_locked(sb, hash, ll_test_inode, ll_read_inode2, lic); +struct inode *ll_iget(struct super_block *sb, ino_t hash, + struct lustre_md *md) +{ + struct inode *inode; - if (!inode) - return ERR_PTR(-ENOMEM); + LASSERT(hash != 0); + inode = iget5_locked(sb, hash, ll_test_inode, ll_set_inode, md); - if (inode->i_state & I_NEW) { - - unlock_new_inode(inode); - } + if (inode) { + if (inode->i_state & I_NEW) + unlock_new_inode(inode); + CDEBUG(D_VFSTRACE, "inode: %lu/%u(%p)\n", inode->i_ino, + inode->i_generation, inode); + } - // XXX Coda always fills inodes, should Lustre? return inode; } #else -struct inode *ll_iget(struct super_block *sb, inot_t hash, - struct ll_read_inode2_cookie *lic) +struct inode *ll_iget(struct super_block *sb, ino_t hash, + struct lustre_md *md) { struct inode *inode; - inode = iget4(sb, hash, ll_find_inode, lic); + LASSERT(hash != 0); + inode = iget4(sb, hash, ll_test_inode, md); + if (inode) + CDEBUG(D_VFSTRACE, "inode: %lu/%u(%p)\n", inode->i_ino, + inode->i_generation, inode); return inode; } #endif -static struct dentry *ll_lookup2(struct inode *dir, struct dentry *dentry, - struct lookup_intent *it) +int ll_mdc_blocking_ast(struct ldlm_lock *lock, struct ldlm_lock_desc *desc, + void *data, int flag) { - struct ptlrpc_request *request = NULL; - struct inode * inode = NULL; - struct ll_sb_info *sbi = ll_i2sbi(dir); - struct ll_read_inode2_cookie lic; + int rc; struct lustre_handle lockh; - struct lookup_intent lookup_it = { IT_LOOKUP }; - int rc, offset; - obd_id ino = 0; - ENTRY; - /* CHECK_MOUNT_EPOCH(dir); */ - if (ll_i2info(dir)->lli_mount_epoch != ll_i2sbi(dir)->ll_mount_epoch) { - make_bad_inode(dir); - RETURN(ERR_PTR(-EIO)); - } + switch (flag) { + case LDLM_CB_BLOCKING: + ldlm_lock2handle(lock, &lockh); + rc = ldlm_cli_cancel(&lockh); + if (rc < 0) { + CDEBUG(D_INODE, "ldlm_cli_cancel: %d\n", rc); + RETURN(rc); + } + break; + case LDLM_CB_CANCELING: { + struct inode *inode = ll_inode_from_lock(lock); + __u64 bits = lock->l_policy_data.l_inodebits.bits; - if (it == NULL) - it = &lookup_it; + /* For lookup locks: Invalidate all dentries associated with + this inode, for UPDATE locks - invalidate directory pages */ + if (inode == NULL) + break; - CDEBUG(D_INFO, "name: %*s, intent: %s\n", dentry->d_name.len, - dentry->d_name.name, ldlm_it2str(it->it_op)); + if (bits & MDS_INODELOCK_UPDATE) + clear_bit(LLI_F_HAVE_MDS_SIZE_LOCK, + &(ll_i2info(inode)->lli_flags)); - if (dentry->d_name.len > EXT2_NAME_LEN) - RETURN(ERR_PTR(-ENAMETOOLONG)); - rc = ll_lock(dir, dentry, it, &lockh); - if (rc < 0) - RETURN(ERR_PTR(rc)); - memcpy(it->it_lock_handle, &lockh, sizeof(lockh)); - - request = (struct ptlrpc_request *)it->it_data; - if (it->it_disposition) { - int mode, symlen = 0; - obd_flag valid; - - offset = 1; - lic.lic_body = lustre_msg_buf(request->rq_repmsg, offset); - ino = lic.lic_body->fid1.id; - mode = lic.lic_body->mode; - if (it->it_op & (IT_CREAT | IT_MKDIR | IT_SYMLINK | IT_MKNOD)) { - /* For create ops, we want the lookup to be negative, - * unless the create failed in a way that indicates - * that the file is already there */ - if (it->it_status != -EEXIST) - GOTO(negative, NULL); - } else if (it->it_op & (IT_GETATTR | IT_SETATTR | IT_LOOKUP | - IT_READLINK)) { - /* For check ops, we want the lookup to succeed */ - it->it_data = NULL; - if (it->it_status) - GOTO(neg_req, NULL); - } else if (it->it_op & (IT_RENAME | IT_LINK)) { - /* For rename, we want the source lookup to succeed */ - if (it->it_status) { - it->it_data = NULL; - GOTO(drop_req, rc = it->it_status); - } - it->it_data = dentry; - } else if (it->it_op & (IT_UNLINK | IT_RMDIR)) { - /* For remove ops, we want the lookup to succeed unless - * the file truly doesn't exist */ - it->it_data = NULL; - if (it->it_status == -ENOENT) - GOTO(neg_req, NULL); - goto iget; - } else if (it->it_op == IT_OPEN) { - it->it_data = NULL; - if (it->it_status && it->it_status != -EEXIST) - GOTO(neg_req, NULL); - } else if (it->it_op & (IT_RENAME2 | IT_LINK2)) { - struct mds_body *body = - lustre_msg_buf(request->rq_repmsg, offset); - it->it_data = NULL; - /* This means the target lookup is negative */ - if (body->valid == 0) - GOTO(neg_req, NULL); - goto iget; + if (lock->l_resource->lr_name.name[0] != inode->i_ino || + lock->l_resource->lr_name.name[1] != inode->i_generation) { + LDLM_ERROR(lock, "data mismatch with ino %lu/%u", + inode->i_ino, inode->i_generation); } - /* Do a getattr now that we have the lock */ - valid = OBD_MD_FLNOTOBD | OBD_MD_FLEASIZE; - if (it->it_op == IT_READLINK) { - valid |= OBD_MD_LINKNAME; - symlen = lic.lic_body->size; - } - ptlrpc_req_finished(request); - request = NULL; - rc = mdc_getattr(&sbi->ll_mdc_conn, ino, mode, - valid, symlen, &request); - if (rc) { - CERROR("failure %d inode "LPX64"\n", rc, ino); - GOTO(drop_req, rc = -abs(rc)); + /* If lookup lock is cancelled, we just drop the dentry and + this will cause us to reget data from MDS when we'd want to + access this dentry/inode again. If this is lock on + other parts of inode that is cancelled, we do not need to do + much (but need to discard data from readdir, if any), since + abscence of lock will cause ll_revalidate_it (called from + stat() and similar functions) to renew the data anyway */ + if (S_ISDIR(inode->i_mode) && + (bits & MDS_INODELOCK_UPDATE)) { + CDEBUG(D_INODE, "invalidating inode %lu\n", + inode->i_ino); + + truncate_inode_pages(inode->i_mapping, 0); } - offset = 0; - } else { - struct ll_inode_info *lli = ll_i2info(dir); - int mode; - memcpy(&lli->lli_intent_lock_handle, &lockh, sizeof(lockh)); - offset = 0; + if (inode->i_sb->s_root && + inode != inode->i_sb->s_root->d_inode && + (bits & MDS_INODELOCK_LOOKUP)) + ll_unhash_aliases(inode); + iput(inode); + break; + } + default: + LBUG(); + } - ino = ll_inode_by_name(dir, dentry, &mode); - if (!ino) { - CERROR("inode %*s not found by name\n", - dentry->d_name.len, dentry->d_name.name); - GOTO(drop_lock, rc = -ENOENT); - } + RETURN(0); +} + +int ll_mdc_cancel_unused(struct lustre_handle *conn, struct inode *inode, + int flags, void *opaque) +{ + struct ldlm_res_id res_id = + { .name = {inode->i_ino, inode->i_generation} }; + struct obd_device *obddev = class_conn2obd(conn); + ENTRY; + + RETURN(ldlm_cli_cancel_unused(obddev->obd_namespace, &res_id, flags, + opaque)); +} + +/* Search "inode"'s alias list for a dentry that has the same name and parent as + * de. If found, return it. If not found, return de. */ +struct dentry *ll_find_alias(struct inode *inode, struct dentry *de) +{ + struct list_head *tmp; - rc = mdc_getattr(&sbi->ll_mdc_conn, ino, mode, - OBD_MD_FLNOTOBD|OBD_MD_FLEASIZE, 0, &request); - if (rc) { - CERROR("failure %d inode "LPX64"\n", rc, ino); - GOTO(drop_req, rc = -abs(rc)); + spin_lock(&dcache_lock); + list_for_each(tmp, &inode->i_dentry) { + struct dentry *dentry = list_entry(tmp, struct dentry, d_alias); + + /* We are called here with 'de' already on the aliases list. */ + if (dentry == de) { + CERROR("whoops\n"); + continue; } - } - iget: - lic.lic_body = lustre_msg_buf(request->rq_repmsg, offset); - if (S_ISREG(lic.lic_body->mode) && - lic.lic_body->valid & OBD_MD_FLEASIZE) { - LASSERT(request->rq_repmsg->bufcount > offset); - lic.lic_lmm = lustre_msg_buf(request->rq_repmsg, offset + 1); - } else - lic.lic_lmm = NULL; - - /* No rpc's happen during iget4, -ENOMEM's are possible */ - LASSERT(ino != 0); - inode = ll_iget(dir->i_sb, ino, &lic); - if (!inode) { - ptlrpc_free_req(request); - ll_intent_release(dentry, it); - RETURN(ERR_PTR(-ENOMEM)); - } + if (dentry->d_parent != de->d_parent) + continue; - EXIT; - neg_req: - ptlrpc_req_finished(request); - negative: - dentry->d_op = &ll_d_ops; - if (ll_d2d(dentry) == NULL) { - ll_set_dd(dentry); - } else - CERROR("NOT allocating fsdata - already set\n"); + if (dentry->d_name.len != de->d_name.len) + continue; - d_add(dentry, inode); + if (memcmp(dentry->d_name.name, de->d_name.name, + de->d_name.len) != 0) + continue; - if (it->it_status == 0) { - LL_SAVE_INTENT(dentry, it); - } - else { - dentry->d_it = NULL; - CDEBUG(D_DENTRY, - "D_IT dentry %p fsdata %p intent: %s status %d\n", - dentry, ll_d2d(dentry), ldlm_it2str(it->it_op), - it->it_status); - } + if (!list_empty(&dentry->d_lru)) + list_del_init(&dentry->d_lru); - if (it->it_op == IT_LOOKUP) - ll_intent_release(dentry, it); + hlist_del_init(&dentry->d_hash); + __d_rehash(dentry, 0); /* avoid taking dcache_lock inside */ + spin_unlock(&dcache_lock); + atomic_inc(&dentry->d_count); + iput(inode); + dentry->d_flags &= ~DCACHE_LUSTRE_INVALID; + CDEBUG(D_DENTRY, "alias dentry %*s (%p) parent %p inode %p " + "refc %d\n", de->d_name.len, de->d_name.name, de, + de->d_parent, de->d_inode, atomic_read(&de->d_count)); + return dentry; + } - return NULL; + spin_unlock(&dcache_lock); - drop_req: - ptlrpc_free_req(request); - drop_lock: -#warning FIXME: must release lock here - return ERR_PTR(rc); + return de; } -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 *lsm) +static int lookup_it_finish(struct ptlrpc_request *request, int offset, + struct lookup_intent *it, void *data) { - struct inode *inode; - struct ptlrpc_request *request = NULL; - struct mds_body *body; - time_t time = CURRENT_TIME; - struct ll_sb_info *sbi = ll_i2sbi(dir); - struct ll_read_inode2_cookie lic; - struct lov_mds_md *lmm = NULL; - ENTRY; + struct it_cb_data *icbd = data; + struct dentry **de = icbd->icbd_childp; + struct inode *parent = icbd->icbd_parent; + struct ll_sb_info *sbi = ll_i2sbi(parent); + struct dentry *dentry = *de, *saved = *de; + struct inode *inode = NULL; + int rc; - if (it && it->it_disposition) { - int rc = it->it_status; - if (rc) { - CERROR("error creating MDS inode for %*s: rc = %d\n", - namelen, name, rc); - RETURN(ERR_PTR(rc)); - } - invalidate_inode_pages(dir); - request = it->it_data; - body = lustre_msg_buf(request->rq_repmsg, 1); - lic.lic_lmm = NULL; - } else { - int gid = current->fsgid; - int rc; - - if (lsm) { - OBD_ALLOC(lmm, lsm->lsm_mds_easize); - if (!lmm) - RETURN(ERR_PTR(-ENOMEM)); - lov_packmd(lmm, lsm); - lic.lic_lmm = lmm; - } else - lic.lic_lmm = NULL; - - if (dir->i_mode & S_ISGID) { - gid = dir->i_gid; - if (S_ISDIR(mode)) - mode |= S_ISGID; - } + /* NB 1 request reference will be taken away by ll_intent_lock() + * when I return */ + if (!it_disposition(it, DISP_LOOKUP_NEG)) { + ENTRY; + + rc = ll_prep_inode(sbi->ll_osc_exp, sbi->ll_mdc_exp, + &inode, request, offset, dentry->d_sb); + if (rc) + RETURN(rc); - rc = mdc_create(&sbi->ll_mdc_conn, dir, name, namelen, tgt, - tgtlen, mode, current->fsuid, gid, - time, extra, lsm, &request); - if (rc) { - inode = ERR_PTR(rc); - GOTO(out, rc); + CDEBUG(D_DLMTRACE, "setting l_data to inode %p (%lu/%u)\n", + inode, inode->i_ino, inode->i_generation); + mdc_set_lock_data(NULL, &it->d.lustre.it_lock_handle, inode); + + /* If this is a stat, get the authoritative file size */ + if (it->it_op == IT_GETATTR && S_ISREG(inode->i_mode) && + ll_i2info(inode)->lli_smd != NULL) { + struct lov_stripe_md *lsm = ll_i2info(inode)->lli_smd; + struct ost_lvb lvb; + ldlm_error_t rc; + + LASSERT(lsm->lsm_object_id != 0); + + /* bug 2334: drop MDS lock before acquiring OST lock */ + ll_intent_drop_lock(it); + + rc = ll_glimpse_size(inode, &lvb); + if (rc) { + iput(inode); + RETURN(rc); + } + inode->i_size = lvb.lvb_size; } - body = lustre_msg_buf(request->rq_repmsg, 0); + + dentry = *de = ll_find_alias(inode, dentry); + } else { + ENTRY; } - lic.lic_body = body; + dentry->d_op = &ll_d_ops; + ll_set_dd(dentry); - LASSERT(body->ino != 0); - inode = ll_iget(dir->i_sb, body->ino, &lic); - if (IS_ERR(inode)) { - int rc = PTR_ERR(inode); - CERROR("new_inode -fatal: rc %d\n", rc); - LBUG(); - GOTO(out, rc); + if (dentry == saved) { + d_add(dentry, inode); } - if (!list_empty(&inode->i_dentry)) { - CERROR("new_inode -fatal: inode %d, ct %d lnk %d\n", - body->ino, atomic_read(&inode->i_count), - inode->i_nlink); - iput(inode); - LBUG(); - inode = ERR_PTR(-EIO); - GOTO(out, -EIO); + RETURN(0); +} + + +static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry, + struct nameidata *nd, + struct lookup_intent *it, int flags) +{ + struct dentry *save = dentry, *retval; + struct ll_fid pfid; + struct ll_uctxt ctxt; + struct it_cb_data icbd; + struct ptlrpc_request *req = NULL; + struct lookup_intent lookup_it = { .it_op = IT_LOOKUP }; + int rc; + ENTRY; + + if (dentry->d_name.len > EXT3_NAME_LEN) + RETURN(ERR_PTR(-ENAMETOOLONG)); + + CDEBUG(D_VFSTRACE, "VFS Op:name=%s,dir=%lu/%u(%p),intent=%s\n", + dentry->d_name.name, parent->i_ino, parent->i_generation, + parent, LL_IT2STR(it)); + + if (d_mountpoint(dentry)) + CERROR("Tell Peter, lookup on mtpt, it %s\n", LL_IT2STR(it)); + + if (nd != NULL) + nd->mnt->mnt_last_used = jiffies; + + ll_frob_intent(&it, &lookup_it); + + icbd.icbd_childp = &dentry; + icbd.icbd_parent = parent; + ll_inode2fid(&pfid, parent); + ll_i2uctxt(&ctxt, parent, NULL); + + rc = md_intent_lock(ll_i2mdcexp(parent), &ctxt, &pfid, + dentry->d_name.name, dentry->d_name.len, NULL, 0, + NULL, it, flags, &req, ll_mdc_blocking_ast); + if (rc < 0) + GOTO(out, retval = ERR_PTR(rc)); + + rc = lookup_it_finish(req, 1, it, &icbd); + if (rc != 0) { + ll_intent_release(it); + GOTO(out, retval = ERR_PTR(rc)); } - EXIT; + ll_lookup_finish_locks(it, dentry); + + if (nd && + dentry->d_inode != NULL && dentry->d_inode->i_mode & S_ISUID && + S_ISDIR(dentry->d_inode->i_mode) && + (flags & LOOKUP_CONTINUE || (it->it_op & (IT_CHDIR | IT_OPEN)))) + ll_dir_process_mount_object(dentry, nd->mnt); + + if (dentry == save) + GOTO(out, retval = NULL); + else + GOTO(out, retval = dentry); out: - if (lsm && lmm) - OBD_FREE(lmm, lsm->lsm_mds_easize); - ptlrpc_req_finished(request); - return inode; + if (req) + ptlrpc_req_finished(req); + if (dentry->d_inode) + CDEBUG(D_INODE, "lookup 0x%p in %lu/%lu: %*s -> %lu/%lu\n", + dentry, + (unsigned long) parent->i_ino, + (unsigned long) parent->i_generation, + dentry->d_name.len, dentry->d_name.name, + (unsigned long) dentry->d_inode->i_ino, + (unsigned long) dentry->d_inode->i_generation); + else + CDEBUG(D_INODE, "lookup 0x%p in %lu/%lu: %*s -> ??\n", + dentry, + (unsigned long) parent->i_ino, + (unsigned long) parent->i_generation, + dentry->d_name.len, dentry->d_name.name); + return retval; } -static int ll_mdc_unlink(struct inode *dir, struct inode *child, __u32 mode, - const char *name, int len) +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) +static struct dentry *ll_lookup_nd(struct inode *parent, struct dentry *dentry, + struct nameidata *nd) { - struct ptlrpc_request *request = NULL; - struct ll_sb_info *sbi = ll_i2sbi(dir); - int err; - + struct dentry *de; ENTRY; - err = mdc_unlink(&sbi->ll_mdc_conn, dir, child, mode, name, len, - &request); - ptlrpc_req_finished(request); + if (nd && nd->flags & LOOKUP_LAST && !(nd->flags & LOOKUP_LINK_NOTLAST)) + de = ll_lookup_it(parent, dentry, nd, &nd->intent, nd->flags); + else + de = ll_lookup_it(parent, dentry, nd, NULL, 0); - RETURN(err); + RETURN(de); } +#endif -int ll_mdc_link(struct dentry *src, struct inode *dir, - const char *name, int len) +/* We depend on "mode" being set with the proper file type/umask by now */ +static struct inode *ll_create_node(struct inode *dir, const char *name, + int namelen, const void *data, int datalen, + int mode, __u64 extra, + struct lookup_intent *it) { + struct inode *inode = NULL; struct ptlrpc_request *request = NULL; - int err; struct ll_sb_info *sbi = ll_i2sbi(dir); - + int rc; ENTRY; - err = mdc_link(&sbi->ll_mdc_conn, src, dir, name, len, &request); - ptlrpc_req_finished(request); + LASSERT(it && it->d.lustre.it_disposition); - 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; + request = it->d.lustre.it_data; + rc = ll_prep_inode(sbi->ll_osc_exp, sbi->ll_mdc_exp, + &inode, request, 1, dir->i_sb); + if (rc) + GOTO(out, inode = ERR_PTR(rc)); - ENTRY; + LASSERT(list_empty(&inode->i_dentry)); - 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); + /* We asked for a lock on the directory, but were granted a + * lock on the inode. Since we finally have an inode pointer, + * stuff it in the lock. */ + CDEBUG(D_DLMTRACE, "setting l_ast_data to inode %p (%lu/%u)\n", + inode, inode->i_ino, inode->i_generation); + mdc_set_lock_data(NULL, &it->d.lustre.it_lock_handle, inode); + EXIT; + out: ptlrpc_req_finished(request); - - RETURN(err); + return inode; } /* * By the time this is called, we already have created the directory cache * entry for the new file, but it is so far negative - it has no inode. + * * We defer creating the OBD object(s) until open, to keep the intent and * non-intent code paths similar, and also because we do not have the MDS * inode number before calling ll_create_node() (which is needed for LOV), * so we would need to do yet another RPC to the MDS to store the LOV EA - * data on the MDS. + * data on the MDS. If needed, we would pass the PACKED lmm as data and + * lmm_size in datalen (the MDS still has code which will handle that). * * If the create succeeds, we fill in the inode information * with d_instantiate(). */ -static int ll_create(struct inode *dir, struct dentry *dentry, int mode) +static int ll_create_it(struct inode *dir, struct dentry *dentry, int mode, + struct lookup_intent *it) { - struct lookup_intent *it; struct inode *inode; + struct ptlrpc_request *request = it->d.lustre.it_data; + struct obd_export *mdc_exp = ll_i2mdcexp(dir); int rc = 0; ENTRY; - CHECK_MOUNT_EPOCH(dir); + CDEBUG(D_VFSTRACE, "VFS Op:name=%s,dir=%lu/%u(%p),intent=%s\n", + dentry->d_name.name, dir->i_ino, dir->i_generation, dir, + LL_IT2STR(it)); - LL_GET_INTENT(dentry, it); + rc = it_open_error(DISP_OPEN_CREATE, it); + if (rc) + RETURN(rc); + mdc_store_inode_generation(mdc_exp, request, 2, 1); inode = ll_create_node(dir, dentry->d_name.name, dentry->d_name.len, - NULL, 0, mode, 0, it, NULL); - - if (IS_ERR(inode)) + NULL, 0, mode, 0, it); + if (IS_ERR(inode)) { RETURN(PTR_ERR(inode)); - - if (it->it_disposition) { - struct ll_inode_info *lli = ll_i2info(inode); - memcpy(&lli->lli_intent_lock_handle, it->it_lock_handle, - sizeof(lli->lli_intent_lock_handle)); - d_instantiate(dentry, inode); - } else { - /* no directory data updates when intents rule */ - rc = ext2_add_nondir(dentry, inode); } - RETURN(rc); + d_instantiate(dentry, inode); + RETURN(0); } -static int ll_mknod(struct inode *dir, struct dentry *dentry, int mode, - int rdev) +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) +static int ll_create_nd(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd) { - struct lookup_intent *it; - struct inode *inode; - int rc = 0; - - LL_GET_INTENT(dentry, it); - - inode = ll_create_node(dir, dentry->d_name.name, dentry->d_name.len, - NULL, 0, mode, rdev, it, NULL); - - if (IS_ERR(inode)) - RETURN(PTR_ERR(inode)); - - /* no directory data updates when intents rule */ - if (it && it->it_disposition) - d_instantiate(dentry, inode); - else - rc = ext2_add_nondir(dentry, inode); - - return rc; + return ll_create_it(dir, dentry, mode, &nd->intent); } +#endif -static int ll_symlink(struct inode *dir, struct dentry *dentry, - const char *symname) +static int ll_mknod_raw(struct nameidata *nd, int mode, dev_t rdev) { - struct lookup_intent *it; - unsigned l = strlen(symname); - struct inode *inode; - struct ll_inode_info *lli; - int err = 0; + struct ptlrpc_request *request = NULL; + struct inode *dir = nd->dentry->d_inode; + const char *name = nd->last.name; + int len = nd->last.len; + struct ll_sb_info *sbi = ll_i2sbi(dir); + struct mdc_op_data op_data; + int err = -EMLINK; ENTRY; - CHECK_MOUNT_EPOCH(dir); + CDEBUG(D_VFSTRACE, "VFS Op:name=%s,dir=%lu/%u(%p)\n", + name, dir->i_ino, dir->i_generation, dir); + + if (dir->i_nlink >= EXT3_LINK_MAX) + RETURN(err); + + mode &= ~current->fs->umask; + + switch (mode & S_IFMT) { + case 0: + case S_IFREG: + mode |= S_IFREG; /* for mode = 0 case, fallthrough */ + case S_IFCHR: + case S_IFBLK: + case S_IFIFO: + case S_IFSOCK: + ll_prepare_mdc_op_data(&op_data, dir, NULL, name, len, 0); + err = md_create(sbi->ll_mdc_exp, &op_data, NULL, 0, mode, + current->fsuid, current->fsgid, rdev, &request); + ptlrpc_req_finished(request); + break; + case S_IFDIR: + err = -EPERM; + break; + default: + err = -EINVAL; + } + RETURN(err); +} - LL_GET_INTENT(dentry, it); +static int ll_mknod(struct inode *dir, struct dentry *child, int mode, + ll_dev_t rdev) +{ + struct ptlrpc_request *request = NULL; + struct inode *inode = NULL; + const char *name = child->d_name.name; + int len = child->d_name.len; + struct ll_sb_info *sbi = ll_i2sbi(dir); + struct mdc_op_data op_data; + int err = -EMLINK; + ENTRY; - inode = ll_create_node(dir, dentry->d_name.name, dentry->d_name.len, - symname, l, S_IFLNK | S_IRWXUGO, 0, it, NULL); - if (IS_ERR(inode)) - RETURN(PTR_ERR(inode)); + CDEBUG(D_VFSTRACE, "VFS Op:name=%s,dir=%lu/%u(%p)\n", + name, dir->i_ino, dir->i_generation, dir); + + if (dir->i_nlink >= EXT3_LINK_MAX) + RETURN(err); + + mode &= ~current->fs->umask; + + switch (mode & S_IFMT) { + case 0: + case S_IFREG: + mode |= S_IFREG; /* for mode = 0 case, fallthrough */ + case S_IFCHR: + case S_IFBLK: + case S_IFIFO: + case S_IFSOCK: + ll_prepare_mdc_op_data(&op_data, dir, NULL, name, len, 0); + err = md_create(sbi->ll_mdc_exp, &op_data, NULL, 0, mode, + current->fsuid, current->fsgid, rdev, &request); + err = ll_prep_inode(sbi->ll_osc_exp, sbi->ll_mdc_exp, + &inode, request, 0, child->d_sb); + if (err) + GOTO(out_err, err); + break; + case S_IFDIR: + RETURN(-EPERM); + break; + default: + RETURN(-EINVAL); + } - lli = ll_i2info(inode); + d_instantiate(child, inode); + out_err: + ptlrpc_req_finished(request); + RETURN(err); +} - OBD_ALLOC(lli->lli_symlink_name, l + 1); - /* this _could_ be a non-fatal error, since the symlink is already - * stored on the MDS by this point, and we can re-get it in readlink. - */ - if (!lli->lli_symlink_name) - RETURN(-ENOMEM); +static int ll_symlink_raw(struct nameidata *nd, const char *tgt) +{ + struct inode *dir = nd->dentry->d_inode; + const char *name = nd->last.name; + int len = nd->last.len; + struct ptlrpc_request *request = NULL; + struct ll_sb_info *sbi = ll_i2sbi(dir); + struct mdc_op_data op_data; + int err = -EMLINK; + ENTRY; - memcpy(lli->lli_symlink_name, symname, l + 1); - inode->i_size = l; + CDEBUG(D_VFSTRACE, "VFS Op:name=%s,dir=%lu/%u(%p),target=%s\n", + name, dir->i_ino, dir->i_generation, dir, tgt); - /* no directory data updates when intents rule */ - if (it && it->it_disposition) - d_instantiate(dentry, inode); - else - err = ext2_add_nondir(dentry, inode); + if (dir->i_nlink >= EXT3_LINK_MAX) + RETURN(err); + ll_prepare_mdc_op_data(&op_data, dir, NULL, name, len, 0); + err = md_create(sbi->ll_mdc_exp, &op_data, + tgt, strlen(tgt) + 1, S_IFLNK | S_IRWXUGO, + current->fsuid, current->fsgid, 0, &request); + ptlrpc_req_finished(request); RETURN(err); } -static int ll_link(struct dentry *old_dentry, struct inode * dir, - struct dentry *dentry) +static int ll_link_raw(struct nameidata *srcnd, struct nameidata *tgtnd) { - struct lookup_intent *it; - struct inode *inode = old_dentry->d_inode; - int rc; - - LL_GET_INTENT(dentry, it); - - if (it && it->it_disposition) { - if (it->it_status) - RETURN(it->it_status); - inode->i_ctime = CURRENT_TIME; - ext2_inc_count(inode); - atomic_inc(&inode->i_count); - d_instantiate(dentry, inode); - invalidate_inode_pages(dir); - RETURN(0); - } - - if (S_ISDIR(inode->i_mode)) - return -EPERM; - - if (inode->i_nlink >= EXT2_LINK_MAX) - return -EMLINK; + struct inode *src = srcnd->dentry->d_inode; + struct inode *dir = tgtnd->dentry->d_inode; + const char *name = tgtnd->last.name; + int len = tgtnd->last.len; + struct ptlrpc_request *request = NULL; + struct mdc_op_data op_data; + int err; + struct ll_sb_info *sbi = ll_i2sbi(dir); - rc = ll_mdc_link(old_dentry, dir, - dentry->d_name.name, dentry->d_name.len); - if (rc) - RETURN(rc); + ENTRY; + CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p),dir=%lu/%u(%p),target=%s\n", + src->i_ino, src->i_generation, src, + dir->i_ino, dir->i_generation, dir, name); - inode->i_ctime = CURRENT_TIME; - ext2_inc_count(inode); - atomic_inc(&inode->i_count); + ll_prepare_mdc_op_data(&op_data, src, dir, name, len, 0); + err = md_link(sbi->ll_mdc_exp, &op_data, &request); + ptlrpc_req_finished(request); - return ext2_add_nondir(dentry, inode); + RETURN(err); } -static int ll_mkdir(struct inode *dir, struct dentry *dentry, int mode) + +static int ll_mkdir_raw(struct nameidata *nd, int mode) { - struct lookup_intent *it; - struct inode * inode; + struct inode *dir = nd->dentry->d_inode; + const char *name = nd->last.name; + int len = nd->last.len; + struct ptlrpc_request *request = NULL; + struct ll_sb_info *sbi = ll_i2sbi(dir); + struct mdc_op_data op_data; int err = -EMLINK; ENTRY; + CDEBUG(D_VFSTRACE, "VFS Op:name=%s,dir=%lu/%u(%p)\n", + name, dir->i_ino, dir->i_generation, dir); - LL_GET_INTENT(dentry, it); - - if (dir->i_nlink >= EXT2_LINK_MAX) - goto out; - - ext2_inc_count(dir); - inode = ll_create_node(dir, dentry->d_name.name, dentry->d_name.len, - NULL, 0, S_IFDIR | mode, 0, it, NULL); - err = PTR_ERR(inode); - if (IS_ERR(inode)) - goto out_dir; + mode = (mode & (S_IRWXUGO|S_ISVTX) & ~current->fs->umask) | S_IFDIR; + ll_prepare_mdc_op_data(&op_data, dir, NULL, name, len, 0); + err = md_create(sbi->ll_mdc_exp, &op_data, NULL, 0, mode, + current->fsuid, current->fsgid, 0, &request); + ptlrpc_req_finished(request); + RETURN(err); +} - ext2_inc_count(inode); +static int ll_rmdir_raw(struct nameidata *nd) +{ + struct inode *dir = nd->dentry->d_inode; + const char *name = nd->last.name; + int len = nd->last.len; + struct ptlrpc_request *request = NULL; + struct mdc_op_data op_data; + int rc; + ENTRY; + CDEBUG(D_VFSTRACE, "VFS Op:name=%s,dir=%lu/%u(%p)\n", + name, dir->i_ino, dir->i_generation, dir); - err = ext2_make_empty(inode, dir); - if (err) - goto out_fail; + ll_prepare_mdc_op_data(&op_data, dir, NULL, name, len, S_IFDIR); + rc = md_unlink(ll_i2sbi(dir)->ll_mdc_exp, &op_data, &request); + ptlrpc_req_finished(request); + RETURN(rc); +} - /* no directory data updates when intents rule */ - if (!it || !it->it_disposition) { - err = ll_add_link(dentry, inode); - if (err) - goto out_fail; - } +int ll_objects_destroy(struct ptlrpc_request *request, struct inode *dir) +{ + struct mds_body *body; + struct lov_mds_md *eadata; + struct lov_stripe_md *lsm = NULL; + struct obd_trans_info oti = { 0 }; + struct obdo *oa; + int rc; + ENTRY; - d_instantiate(dentry, inode); -out: - EXIT; - return err; + /* req is swabbed so this is safe */ + body = lustre_msg_buf(request->rq_repmsg, 0, sizeof(*body)); -out_fail: - ext2_dec_count(inode); - ext2_dec_count(inode); - iput(inode); - EXIT; -out_dir: - ext2_dec_count(dir); - EXIT; - goto out; -} + if (!(body->valid & OBD_MD_FLEASIZE)) + RETURN(0); -static int ll_common_unlink(struct inode *dir, struct dentry *dentry, - struct lookup_intent *it, __u32 mode) -{ - struct inode *inode = dentry->d_inode; - struct ext2_dir_entry_2 * de; - struct page * page; - int rc = 0; + if (body->eadatasize == 0) { + CERROR("OBD_MD_FLEASIZE set but eadatasize zero\n"); + GOTO(out, rc = -EPROTO); + } - if (it && it->it_disposition) { - rc = it->it_status; - invalidate_inode_pages(dir); - if (rc) - GOTO(out, rc); - GOTO(out_dec, 0); + /* The MDS sent back the EA because we unlinked the last reference + * to this file. Use this EA to unlink the objects on the OST. + * It's opaque so we don't swab here; we leave it to obd_unpackmd() to + * check it is complete and sensible. */ + eadata = lustre_swab_repbuf(request, 1, body->eadatasize, NULL); + LASSERT(eadata != NULL); + if (eadata == NULL) { + CERROR("Can't unpack MDS EA data\n"); + GOTO(out, rc = -EPROTO); } - de = ext2_find_entry(dir, dentry, &page); - if (!de) - GOTO(out, rc = -ENOENT); - rc = ll_mdc_unlink(dir, dentry->d_inode, mode, - dentry->d_name.name, dentry->d_name.len); - if (rc) + rc = obd_unpackmd(ll_i2obdexp(dir), &lsm, eadata, body->eadatasize); + if (rc < 0) { + CERROR("obd_unpackmd: %d\n", rc); GOTO(out, rc); + } + LASSERT(rc >= sizeof(*lsm)); + + oa = obdo_alloc(); + if (oa == NULL) + GOTO(out_free_memmd, rc = -ENOMEM); + + oa->o_id = lsm->lsm_object_id; + oa->o_gr = lsm->lsm_object_gr; + oa->o_mode = body->mode & S_IFMT; + oa->o_valid = OBD_MD_FLID | OBD_MD_FLTYPE | OBD_MD_FLGROUP; + + if (body->valid & OBD_MD_FLCOOKIE) { + oa->o_valid |= OBD_MD_FLCOOKIE; + oti.oti_logcookies = + lustre_msg_buf(request->rq_repmsg, 2, + sizeof(struct llog_cookie) * + lsm->lsm_stripe_count); + if (oti.oti_logcookies == NULL) { + oa->o_valid &= ~OBD_MD_FLCOOKIE; + body->valid &= ~OBD_MD_FLCOOKIE; + } + } - rc = ext2_delete_entry(de, page); + rc = obd_destroy(ll_i2obdexp(dir), oa, lsm, &oti); + obdo_free(oa); if (rc) - GOTO(out, rc); - - /* AED: not sure if needed - directory lock revocation should do it - * in the case where the client has cached it for non-intent ops. - */ - invalidate_inode_pages(dir); - - inode->i_ctime = dir->i_ctime; -out_dec: - ext2_dec_count(inode); -out: + CERROR("obd destroy objid "LPX64" error %d\n", + lsm->lsm_object_id, rc); + out_free_memmd: + obd_free_memmd(ll_i2obdexp(dir), &lsm); + out: return rc; } -static int ll_unlink(struct inode *dir, struct dentry *dentry) +static int ll_unlink_raw(struct nameidata *nd) { - struct lookup_intent * it; - - LL_GET_INTENT(dentry, it); - - return ll_common_unlink(dir, dentry, it, S_IFREG); -} - -static int ll_rmdir(struct inode *dir, struct dentry *dentry) -{ - struct inode * inode = dentry->d_inode; - struct lookup_intent *it; + struct inode *dir = nd->dentry->d_inode; + const char *name = nd->last.name; + int len = nd->last.len; + struct ptlrpc_request *request = NULL; + struct mdc_op_data op_data; int rc; ENTRY; + CDEBUG(D_VFSTRACE, "VFS Op:name=%s,dir=%lu/%u(%p)\n", + name, dir->i_ino, dir->i_generation, dir); - LL_GET_INTENT(dentry, it); - - - if ((!it || !it->it_disposition) && !ext2_empty_dir(inode)) - RETURN(-ENOTEMPTY); - - rc = ll_common_unlink(dir, dentry, it, S_IFDIR); - if (!rc) { - inode->i_size = 0; - ext2_dec_count(inode); - ext2_dec_count(dir); - } + ll_prepare_mdc_op_data(&op_data, dir, NULL, name, len, 0); + rc = md_unlink(ll_i2sbi(dir)->ll_mdc_exp, &op_data, &request); + if (rc) + GOTO(out, rc); + rc = ll_objects_destroy(request, dir); + out: + ptlrpc_req_finished(request); RETURN(rc); } -static int ll_rename(struct inode * old_dir, struct dentry * old_dentry, - struct inode * new_dir, struct dentry * new_dentry) +static int ll_rename_raw(struct nameidata *oldnd, struct nameidata *newnd) { - struct lookup_intent *it; - struct inode * old_inode = old_dentry->d_inode; - struct inode * tgt_inode = new_dentry->d_inode; - struct page * dir_page = NULL; - struct ext2_dir_entry_2 * dir_de = NULL; - struct ext2_dir_entry_2 * old_de; - struct page * old_page; + struct inode *src = oldnd->dentry->d_inode; + struct inode *tgt = newnd->dentry->d_inode; + const char *oldname = oldnd->last.name; + int oldlen = oldnd->last.len; + const char *newname = newnd->last.name; + int newlen = newnd->last.len; + struct ptlrpc_request *request = NULL; + struct ll_sb_info *sbi = ll_i2sbi(src); + struct mdc_op_data op_data; int err; + ENTRY; + CDEBUG(D_VFSTRACE, "VFS Op:oldname=%s,src_dir=%lu/%u(%p),newname=%s," + "tgt_dir=%lu/%u(%p)\n", oldname, src->i_ino, src->i_generation, + src, newname, tgt->i_ino, tgt->i_generation, tgt); - LL_GET_INTENT(new_dentry, it); - - if (it && it->it_disposition) { - if (tgt_inode) { - tgt_inode->i_ctime = CURRENT_TIME; - tgt_inode->i_nlink--; - } - invalidate_inode_pages(old_dir); - invalidate_inode_pages(new_dir); - GOTO(out, err = 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 (tgt_inode) { - struct page *new_page; - struct ext2_dir_entry_2 *new_de; - - err = -ENOTEMPTY; - if (dir_de && !ext2_empty_dir (tgt_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); - tgt_inode->i_ctime = CURRENT_TIME; - if (dir_de) - tgt_inode->i_nlink--; - ext2_dec_count(tgt_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); + ll_prepare_mdc_op_data(&op_data, src, tgt, NULL, 0, 0); + err = md_rename(sbi->ll_mdc_exp, &op_data, + oldname, oldlen, newname, newlen, &request); + if (!err) { + err = ll_objects_destroy(request, src); } - 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; + ptlrpc_req_finished(request); -out_dir: - if (dir_de) { - kunmap(dir_page); - page_cache_release(dir_page); - } -out_old: - kunmap(old_page); - page_cache_release(old_page); -out: - return err; + RETURN(err); } struct inode_operations ll_dir_inode_operations = { - 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 + .link_raw = ll_link_raw, + .unlink_raw = ll_unlink_raw, + .symlink_raw = ll_symlink_raw, + .mkdir_raw = ll_mkdir_raw, + .rmdir_raw = ll_rmdir_raw, + .mknod_raw = ll_mknod_raw, + .mknod = ll_mknod, + .rename_raw = ll_rename_raw, + .setattr = ll_setattr, + .setattr_raw = ll_setattr_raw, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) + .create_it = ll_create_it, + .lookup_it = ll_lookup_it, + .revalidate_it = ll_inode_revalidate_it, +#else + .lookup = ll_lookup_nd, + .create = ll_create_nd, + .getattr_it = ll_getattr, +#endif };