X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lustre%2Fllite%2Fnamei.c;h=61cf15b6ca697db84739a2ee7577e3c4ac80943b;hb=40e5945377e1b71dbd6afeaa10ea17f2b876db86;hp=b349bc80d47c6f07e52f6cbb1bc7e9c6824501ac;hpb=b778f841e8f0c139110c26de0c05777ca9c382c8;p=fs%2Flustre-release.git diff --git a/lustre/llite/namei.c b/lustre/llite/namei.c index b349bc8..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,68 +41,55 @@ #include #include #include +#include +#include "llite_internal.h" -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); +/* methods */ -/* - * Couple of helper functions - make the code slightly cleaner. - */ -static inline void ext2_inc_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; -/* postpone the disk update until the inode really goes away */ -static inline void ext2_dec_count(struct inode *inode) -{ - 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); + 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 */ + 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)) -static int ll_find_inode(struct inode *inode, unsigned long ino, void *opaque) -#else -static int ll_test_inode(struct inode *inode, void *opaque) +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) + if (inode->i_ino != md->body->ino) + return 0; #endif -{ - struct ll_read_inode2_cookie *lic = opaque; - struct mds_body *body = lic->lic_body; + 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; } @@ -116,270 +104,122 @@ 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); +int ll_set_inode(struct inode *inode, void *opaque) +{ + ll_read_inode2(inode, opaque); + return 0; +} + struct inode *ll_iget(struct super_block *sb, ino_t hash, - struct ll_read_inode2_cookie *lic) + struct lustre_md *md) { struct inode *inode; LASSERT(hash != 0); - inode = iget5_locked(sb, hash, ll_test_inode, ll_read_inode2, lic); + inode = iget5_locked(sb, hash, ll_test_inode, ll_set_inode, md); - if (!inode) - return ERR_PTR(-ENOMEM); - - 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, ino_t hash, - struct ll_read_inode2_cookie *lic) + struct lustre_md *md) { struct inode *inode; LASSERT(hash != 0); - inode = iget4(sb, hash, ll_find_inode, lic); + 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 int ll_intent_to_lock_mode(struct lookup_intent *it) +int ll_mdc_blocking_ast(struct ldlm_lock *lock, struct ldlm_lock_desc *desc, + void *data, int flag) { - /* CREAT needs to be tested before open (both could be set) */ - if ((it->it_op & (IT_CREAT | IT_MKDIR | IT_SETATTR | IT_MKNOD))) { - return 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 | IT_SYMLINK)) { - return LCK_PR; - } - - LBUG(); - RETURN(-EINVAL); -} - -#define LL_LOOKUP_POSITIVE 1 -#define LL_LOOKUP_NEGATIVE 2 - -int ll_intent_lock(struct inode *parent, struct dentry **de, - struct lookup_intent *it, - intent_finish_cb intent_finish) -{ - struct dentry *dentry = *de; - struct ll_sb_info *sbi = ll_i2sbi(parent); + int rc; struct lustre_handle lockh; - struct lookup_intent lookup_it = { .it_op = IT_LOOKUP }; - struct ptlrpc_request *request = NULL; - char *data = NULL; - int rc, lock_mode, datalen = 0, offset, flag = LL_LOOKUP_POSITIVE; - obd_id ino = 0; - ENTRY; - if (it == NULL) - it = &lookup_it; - - CDEBUG(D_INFO, "name: %*s, intent: %s\n", dentry->d_name.len, - dentry->d_name.name, ldlm_it2str(it->it_op)); - - if (dentry->d_name.len > EXT2_NAME_LEN) - RETURN(-ENAMETOOLONG); - - lock_mode = ll_intent_to_lock_mode(it); - if (it->it_op & IT_SYMLINK) { - data = it->it_data; - datalen = strlen(data) + 1; - it->it_data = NULL; - } - - rc = mdc_enqueue(&sbi->ll_mdc_conn, LDLM_PLAIN, it, lock_mode, parent, - dentry, &lockh, data, datalen, parent,sizeof(*parent)); - if (rc < 0) - RETURN(rc); - memcpy(it->it_lock_handle, &lockh, sizeof(lockh)); - - request = (struct ptlrpc_request *)it->it_data; - /* it_disposition == 1 indicates that the server performed the - * intent on our behalf. */ - if (it->it_disposition) { - struct mds_body *mds_body; - int mode; - obd_flag valid; - - /* This long block is all about fixing up the local - * state so that it is correct as of the moment - * _before_ the operation was applied; that way, the - * VFS will think that everything is normal and call - * Lustre's regular FS function. - * - * If we're performing a creation, that means that unless the - * creation failed with EEXIST, we should fake up a negative - * dentry. Likewise for the target of a hard link. - * - * For everything else, we want to lookup to succeed. */ - - /* One additional note: we add an extra reference to - * the request because we need to keep it around until - * ll_create gets called. For anything else which - * results in LL_LOOKUP_POSITIVE, we can do the iget() - * immediately with the contents of the reply (in the - * intent_finish callback). In the create case, - * however, we need to wait until ll_create_node to do - * the iget() or the VFS will abort with -EEXISTS. - */ - - offset = 1; - mds_body = lustre_msg_buf(request->rq_repmsg, offset); - ino = mds_body->fid1.id; - mode = mds_body->mode; - - if (it->it_op & (IT_CREAT | IT_MKDIR | IT_SYMLINK | IT_MKNOD)) { - mdc_store_inode_generation(request, 2, 1); - /* 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) { - atomic_inc(&request->rq_refcount); - GOTO(out, flag = LL_LOOKUP_NEGATIVE); - } - /* - * Fall through to update attibutes: it may already - * have appeared in the namespace of another client - */ - } 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(out, flag = LL_LOOKUP_NEGATIVE); - /* Fall through to update attibutes. */ - } 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); - } - /* Fall through to update attibutes. */ - } 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(out, flag = LL_LOOKUP_NEGATIVE); - /* No point in updating attributes that we're about to - * unlink. -phil */ - GOTO(out, flag = LL_LOOKUP_POSITIVE); - } else if (it->it_op == IT_OPEN) { - it->it_data = NULL; - if (it->it_status && it->it_status != -EEXIST) - GOTO(out, flag = LL_LOOKUP_NEGATIVE); - /* Fall through to update attibutes. */ - } else if (it->it_op & (IT_RENAME2 | IT_LINK2)) { - it->it_data = NULL; - /* This means the target lookup is negative */ - if (mds_body->valid == 0) - GOTO(out, flag = LL_LOOKUP_NEGATIVE); - /* XXX bug 289: should we maybe fall through here? -p */ - GOTO(out, flag = LL_LOOKUP_POSITIVE); - } - - /* Do a getattr now that we have the lock */ - valid = OBD_MD_FLNOTOBD; - if (it->it_op == IT_READLINK) { - datalen = mds_body->size; - valid |= OBD_MD_LINKNAME; - } else if (S_ISREG(mode)) { - datalen = obd_size_wiremd(&sbi->ll_osc_conn, NULL); - valid |= OBD_MD_FLEASIZE; - } - ptlrpc_req_finished(request); - request = NULL; - rc = mdc_getattr(&sbi->ll_mdc_conn, ino, mode, - valid, datalen, &request); - if (rc) { - CERROR("failure %d inode "LPX64"\n", rc, ino); - GOTO(drop_req, rc = -abs(rc)); + 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); } - offset = 0; - } else { - struct ll_inode_info *lli = ll_i2info(parent); - obd_flag valid; - int mode; - - LBUG(); /* For the moment, no non-intent locks */ + break; + case LDLM_CB_CANCELING: { + struct inode *inode = ll_inode_from_lock(lock); + __u64 bits = lock->l_policy_data.l_inodebits.bits; - /* it_disposition == 0 indicates that it just did a simple lock - * request, for which we are very thankful. move along with - * the local lookup then. */ + /* For lookup locks: Invalidate all dentries associated with + this inode, for UPDATE locks - invalidate directory pages */ + if (inode == NULL) + break; - memcpy(&lli->lli_intent_lock_handle, &lockh, sizeof(lockh)); - offset = 0; + if (bits & MDS_INODELOCK_UPDATE) + clear_bit(LLI_F_HAVE_MDS_SIZE_LOCK, + &(ll_i2info(inode)->lli_flags)); - ino = ll_inode_by_name(parent, 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); - } - - valid = OBD_MD_FLNOTOBD; - if (S_ISREG(mode)) { - datalen = obd_size_wiremd(&sbi->ll_osc_conn, NULL), - valid |= OBD_MD_FLEASIZE; + 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); } - rc = mdc_getattr(&sbi->ll_mdc_conn, ino, mode, valid, - datalen, &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); } - } - EXIT; - out: - if (intent_finish != NULL) { - rc = intent_finish(flag, request, de, it, offset, ino); - dentry = *de; /* intent_finish may change *de */ - } else { - ptlrpc_req_finished(request); + 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; } - - if (it->it_disposition && it->it_op & (IT_RENAME | IT_LINK)) - it->it_data = dentry; - - /* this places the intent in the dentry so that the vfs_xxx - * operation can lay its hands on it; but that is not - * always needed... - */ - if ( // it->it_status == 0 && - it->it_op != IT_RENAME2 && - it->it_op != IT_SETATTR && - it->it_op != IT_GETATTR && - it->it_op != IT_READDIR && - it->it_op != IT_LOOKUP) { - LL_SAVE_INTENT(dentry, it); - } else { - 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); + default: + LBUG(); } - if (rc < 0 || it->it_op == IT_LOOKUP) - ll_intent_release(dentry, it); - - RETURN(rc); + RETURN(0); +} - drop_req: - ptlrpc_free_req(request); - drop_lock: -#warning FIXME: must release lock here - RETURN(rc); +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 @@ -393,7 +233,7 @@ struct dentry *ll_find_alias(struct inode *inode, struct dentry *de) struct dentry *dentry = list_entry(tmp, struct dentry, d_alias); /* We are called here with 'de' already on the aliases list. */ - if (dentry == de) { + if (dentry == de) { CERROR("whoops\n"); continue; } @@ -411,11 +251,15 @@ struct dentry *ll_find_alias(struct inode *inode, struct dentry *de) if (!list_empty(&dentry->d_lru)) list_del_init(&dentry->d_lru); - list_del_init(&dentry->d_hash); + hlist_del_init(&dentry->d_hash); + __d_rehash(dentry, 0); /* avoid taking dcache_lock inside */ spin_unlock(&dcache_lock); - d_rehash(dentry); 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; } @@ -424,202 +268,192 @@ struct dentry *ll_find_alias(struct inode *inode, struct dentry *de) return de; } -static int -lookup2_finish(int flag, struct ptlrpc_request *request, struct dentry **de, - struct lookup_intent *it, int offset, obd_id ino) +static int lookup_it_finish(struct ptlrpc_request *request, int offset, + struct lookup_intent *it, void *data) { + 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; - struct ll_read_inode2_cookie lic = {.lic_body = NULL, .lic_lmm = NULL}; + int rc; - if (flag == LL_LOOKUP_POSITIVE) { + /* NB 1 request reference will be taken away by ll_intent_lock() + * when I return */ + if (!it_disposition(it, DISP_LOOKUP_NEG)) { ENTRY; - 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 */ - inode = ll_iget(dentry->d_sb, ino, &lic); - if (!inode) { - /* XXX make sure that request is freed in this case; - * I think it is, but double-check refcounts. -phil */ - RETURN(-ENOMEM); - } + rc = ll_prep_inode(sbi->ll_osc_exp, sbi->ll_mdc_exp, + &inode, request, offset, dentry->d_sb); + if (rc) + RETURN(rc); - dentry = *de = ll_find_alias(inode, dentry); + 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); - /* We asked for a lock on the directory, and may have been - * granted a lock on the inode. Just in case, fixup the data - * pointer. */ - ldlm_lock_set_data((struct lustre_handle *)it->it_lock_handle, - inode, sizeof(*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; - EXIT; + 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; + } + + dentry = *de = ll_find_alias(inode, dentry); } else { ENTRY; } - ptlrpc_req_finished(request); - dentry->d_op = &ll_d_ops; - if (ll_d2d(dentry) == NULL) { - ll_set_dd(dentry); - } + ll_set_dd(dentry); - if (dentry == saved) + if (dentry == saved) { d_add(dentry, inode); + } RETURN(0); } -static struct dentry *ll_lookup2(struct inode *parent, struct dentry *dentry, - struct lookup_intent *it) + +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; + 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; - rc = ll_intent_lock(parent, &dentry, it, lookup2_finish); - if (rc < 0) { - CERROR("ll_intent_lock: %d\n", rc); - return ERR_PTR(rc); - } + if (dentry->d_name.len > EXT3_NAME_LEN) + RETURN(ERR_PTR(-ENAMETOOLONG)); - if (dentry == save) - return NULL; - else - return dentry; -} + 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)); -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; - 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 = { .lic_lmm = NULL, }; - ENTRY; + if (d_mountpoint(dentry)) + CERROR("Tell Peter, lookup on mtpt, it %s\n", LL_IT2STR(it)); - 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)); - } - ll_invalidate_inode_pages(dir); - request = it->it_data; - body = lustre_msg_buf(request->rq_repmsg, 1); - } else { - int gid = current->fsgid; - int rc; + if (nd != NULL) + nd->mnt->mnt_last_used = jiffies; - if (dir->i_mode & S_ISGID) { - gid = dir->i_gid; - if (S_ISDIR(mode)) - mode |= S_ISGID; - } + ll_frob_intent(&it, &lookup_it); - rc = mdc_create(&sbi->ll_mdc_conn, dir, name, namelen, - data, datalen, mode, current->fsuid, gid, - time, extra, &request); - if (rc) { - inode = ERR_PTR(rc); - GOTO(out, rc); - } - body = lustre_msg_buf(request->rq_repmsg, 0); - } + icbd.icbd_childp = &dentry; + icbd.icbd_parent = parent; + ll_inode2fid(&pfid, parent); + ll_i2uctxt(&ctxt, parent, NULL); - lic.lic_body = body; + 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)); - 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); + rc = lookup_it_finish(req, 1, it, &icbd); + if (rc != 0) { + ll_intent_release(it); + GOTO(out, retval = ERR_PTR(rc)); } - 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); - } + ll_lookup_finish_locks(it, dentry); - if (it && it->it_disposition) { - /* 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. */ - ldlm_lock_set_data((struct lustre_handle *)it->it_lock_handle, - inode, sizeof(*inode)); - } + 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); - EXIT; + if (dentry == save) + GOTO(out, retval = NULL); + else + GOTO(out, retval = dentry); out: - 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; } /* @@ -636,356 +470,360 @@ int ll_mdc_rename(struct inode *src, struct inode *tgt, * 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; - LL_GET_INTENT(dentry, it); + 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)); + 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); - - if (IS_ERR(inode)) + if (IS_ERR(inode)) { RETURN(PTR_ERR(inode)); - - if (it && 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); - - if (IS_ERR(inode)) - RETURN(PTR_ERR(inode)); + return ll_create_it(dir, dentry, mode, &nd->intent); +} +#endif - /* no directory data updates when intents rule */ - if (it && it->it_disposition) - d_instantiate(dentry, inode); - else - rc = ext2_add_nondir(dentry, inode); +static int ll_mknod_raw(struct nameidata *nd, int mode, dev_t rdev) +{ + 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; - return rc; + 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); } -static int ll_symlink(struct inode *dir, struct dentry *dentry, - const char *symname) +static int ll_mknod(struct inode *dir, struct dentry *child, int mode, + ll_dev_t rdev) { - struct lookup_intent *it; - unsigned l = strlen(symname) + 1; - struct inode *inode; - struct ll_inode_info *lli; - int err = 0; + 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; - LL_GET_INTENT(dentry, it); - - inode = ll_create_node(dir, dentry->d_name.name, dentry->d_name.len, - symname, l, S_IFLNK | S_IRWXUGO, 0, it); - 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); - /* 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); - inode->i_size = l - 1; + 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); + 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); - 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); - ll_invalidate_inode_pages(dir); - RETURN(0); - } + 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); - if (S_ISDIR(inode->i_mode)) - return -EPERM; + 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); - if (inode->i_nlink >= EXT2_LINK_MAX) - return -EMLINK; + RETURN(err); +} - rc = ll_mdc_link(old_dentry, dir, - dentry->d_name.name, dentry->d_name.len); - if (rc) - RETURN(rc); - inode->i_ctime = CURRENT_TIME; - ext2_inc_count(inode); - atomic_inc(&inode->i_count); +static int ll_mkdir_raw(struct nameidata *nd, int mode) +{ + 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); - return ext2_add_nondir(dentry, inode); + 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); } -static int ll_mkdir(struct inode *dir, struct dentry *dentry, int mode) +static int ll_rmdir_raw(struct nameidata *nd) { - struct lookup_intent *it; - struct inode * inode; - int err = -EMLINK; + 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 (dir->i_nlink >= EXT2_LINK_MAX) - goto out; + 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); +} - ext2_inc_count(dir); - inode = ll_create_node(dir, dentry->d_name.name, dentry->d_name.len, - NULL, 0, S_IFDIR | mode, 0, it); - err = PTR_ERR(inode); - if (IS_ERR(inode)) - goto out_dir; - - err = ext2_make_empty(inode, dir); - if (err) - goto out_fail; - - /* no directory data updates when intents rule */ - if (!it || !it->it_disposition) { - /* XXX FIXME This code needs re-checked for non-intents */ - ext2_inc_count(inode); - 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; - ll_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. - */ - ll_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) -{ - 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) +static int ll_unlink_raw(struct nameidata *nd) { - 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(old_dentry, it); - - if (it && it->it_disposition) { - if (tgt_inode) { - tgt_inode->i_ctime = CURRENT_TIME; - tgt_inode->i_nlink--; - } - ll_invalidate_inode_pages(old_dir); - ll_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 };