Merge branch 'work.misc' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
[cascardo/linux.git] / drivers / staging / lustre / lustre / llite / llite_lib.c
index dd44ee8..e5c62f4 100644 (file)
@@ -42,7 +42,6 @@
 #include <linux/mm.h>
 
 #include "../include/lustre/lustre_ioctl.h"
-#include "../include/lustre_lite.h"
 #include "../include/lustre_ha.h"
 #include "../include/lustre_dlm.h"
 #include "../include/lprocfs_status.h"
@@ -116,6 +115,7 @@ static struct ll_sb_info *ll_init_sbi(struct super_block *sb)
        sbi->ll_sa_max = LL_SA_RPC_DEF;
        atomic_set(&sbi->ll_sa_total, 0);
        atomic_set(&sbi->ll_sa_wrong, 0);
+       atomic_set(&sbi->ll_sa_running, 0);
        atomic_set(&sbi->ll_agl_total, 0);
        sbi->ll_flags |= LL_SBI_AGL_ENABLED;
 
@@ -189,7 +189,9 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt,
                                  OBD_CONNECT_PINGLESS |
                                  OBD_CONNECT_MAX_EASIZE |
                                  OBD_CONNECT_FLOCK_DEAD |
-                                 OBD_CONNECT_DISP_STRIPE | OBD_CONNECT_LFSCK;
+                                 OBD_CONNECT_DISP_STRIPE | OBD_CONNECT_LFSCK |
+                                 OBD_CONNECT_OPEN_BY_FID |
+                                 OBD_CONNECT_DIR_STRIPE;
 
        if (sbi->ll_flags & LL_SBI_SOM_PREVIEW)
                data->ocd_connect_flags |= OBD_CONNECT_SOM;
@@ -496,11 +498,21 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt,
        err = obd_set_info_async(NULL, sbi->ll_dt_exp, sizeof(KEY_CHECKSUM),
                                 KEY_CHECKSUM, sizeof(checksum), &checksum,
                                 NULL);
+       if (err) {
+               CERROR("%s: Set checksum failed: rc = %d\n",
+                      sbi->ll_dt_exp->exp_obd->obd_name, err);
+               goto out_root;
+       }
        cl_sb_init(sb);
 
        err = obd_set_info_async(NULL, sbi->ll_dt_exp, sizeof(KEY_CACHE_SET),
                                 KEY_CACHE_SET, sizeof(*sbi->ll_cache),
                                 sbi->ll_cache, NULL);
+       if (err) {
+               CERROR("%s: Set cache_set failed: rc = %d\n",
+                      sbi->ll_dt_exp->exp_obd->obd_name, err);
+               goto out_root;
+       }
 
        sb->s_root = d_make_root(root);
        if (!sb->s_root) {
@@ -570,6 +582,17 @@ int ll_get_max_mdsize(struct ll_sb_info *sbi, int *lmmsize)
        return rc;
 }
 
+/**
+ * Get the value of the default_easize parameter.
+ *
+ * \see client_obd::cl_default_mds_easize
+ *
+ * \param[in]  sbi     superblock info for this filesystem
+ * \param[out] lmmsize pointer to storage location for value
+ *
+ * \retval 0           on success
+ * \retval negative    negated errno on failure
+ */
 int ll_get_default_mdsize(struct ll_sb_info *sbi, int *lmmsize)
 {
        int size, rc;
@@ -583,6 +606,29 @@ int ll_get_default_mdsize(struct ll_sb_info *sbi, int *lmmsize)
        return rc;
 }
 
+/**
+ * Set the default_easize parameter to the given value.
+ *
+ * \see client_obd::cl_default_mds_easize
+ *
+ * \param[in] sbi      superblock info for this filesystem
+ * \param[in] lmmsize  the size to set
+ *
+ * \retval 0           on success
+ * \retval negative    negated errno on failure
+ */
+int ll_set_default_mdsize(struct ll_sb_info *sbi, int lmmsize)
+{
+       if (lmmsize < sizeof(struct lov_mds_md) ||
+           lmmsize > OBD_MAX_DEFAULT_EA_SIZE)
+               return -EINVAL;
+
+       return obd_set_info_async(NULL, sbi->ll_md_exp,
+                                 sizeof(KEY_DEFAULT_EASIZE),
+                                 KEY_DEFAULT_EASIZE,
+                                 sizeof(int), &lmmsize, NULL);
+}
+
 static void client_common_put_super(struct super_block *sb)
 {
        struct ll_sb_info *sbi = ll_s2sbi(sb);
@@ -618,6 +664,12 @@ void ll_kill_super(struct super_block *sb)
        if (sbi) {
                sb->s_dev = sbi->ll_sdev_orig;
                sbi->ll_umounting = 1;
+
+               /* wait running statahead threads to quit */
+               while (atomic_read(&sbi->ll_sa_running) > 0) {
+                       set_current_state(TASK_UNINTERRUPTIBLE);
+                       schedule_timeout(msecs_to_jiffies(MSEC_PER_SEC >> 3));
+               }
        }
 }
 
@@ -657,7 +709,8 @@ static int ll_options(char *options, int *flags)
                        *flags |= tmp;
                        goto next;
                }
-               tmp = ll_set_opt("noflock", s1, LL_SBI_FLOCK|LL_SBI_LOCALFLOCK);
+               tmp = ll_set_opt("noflock", s1,
+                                LL_SBI_FLOCK | LL_SBI_LOCALFLOCK);
                if (tmp) {
                        *flags &= ~tmp;
                        goto next;
@@ -782,11 +835,13 @@ void ll_lli_init(struct ll_inode_info *lli)
                lli->lli_sai = NULL;
                spin_lock_init(&lli->lli_sa_lock);
                lli->lli_opendir_pid = 0;
+               lli->lli_sa_enabled = 0;
+               lli->lli_def_stripe_offset = -1;
        } else {
                mutex_init(&lli->lli_size_mutex);
                lli->lli_symlink_name = NULL;
                init_rwsem(&lli->lli_trunc_sem);
-               mutex_init(&lli->lli_write_mutex);
+               range_lock_tree_init(&lli->lli_write_tree);
                init_rwsem(&lli->lli_glimpse_sem);
                lli->lli_glimpse_time = 0;
                INIT_LIST_HEAD(&lli->lli_agl_list);
@@ -906,7 +961,8 @@ void ll_put_super(struct super_block *sb)
        struct lustre_sb_info *lsi = s2lsi(sb);
        struct ll_sb_info *sbi = ll_s2sbi(sb);
        char *profilenm = get_profile_name(sb);
-       int ccc_count, next, force = 1, rc = 0;
+       int next, force = 1, rc = 0;
+       long ccc_count;
 
        CDEBUG(D_VFSTRACE, "VFS Op: sb %p - %s\n", sb, profilenm);
 
@@ -927,13 +983,13 @@ void ll_put_super(struct super_block *sb)
                struct l_wait_info lwi = LWI_INTR(LWI_ON_SIGNAL_NOOP, NULL);
 
                rc = l_wait_event(sbi->ll_cache->ccc_unstable_waitq,
-                                 !atomic_read(&sbi->ll_cache->ccc_unstable_nr),
+                                 !atomic_long_read(&sbi->ll_cache->ccc_unstable_nr),
                                  &lwi);
        }
 
-       ccc_count = atomic_read(&sbi->ll_cache->ccc_unstable_nr);
+       ccc_count = atomic_long_read(&sbi->ll_cache->ccc_unstable_nr);
        if (!force && rc != -EINTR)
-               LASSERTF(!ccc_count, "count: %i\n", ccc_count);
+               LASSERTF(!ccc_count, "count: %li\n", ccc_count);
 
        /* We need to set force before the lov_disconnect in
         * lustre_common_put_super, since l_d cleans up osc's as well.
@@ -1035,7 +1091,7 @@ static struct inode *ll_iget_anon_dir(struct super_block *sb,
                struct lmv_stripe_md *lsm = md->lmv;
 
                inode->i_mode = (inode->i_mode & ~S_IFMT) |
-                               (body->mode & S_IFMT);
+                               (body->mbo_mode & S_IFMT);
                LASSERTF(S_ISDIR(inode->i_mode), "Not slave inode "DFID"\n",
                         PFID(fid));
 
@@ -1051,7 +1107,7 @@ static struct inode *ll_iget_anon_dir(struct super_block *sb,
 
                LASSERT(lsm);
                /* master object FID */
-               lli->lli_pfid = body->fid1;
+               lli->lli_pfid = body->mbo_fid1;
                CDEBUG(D_INODE, "lli %p slave "DFID" master "DFID"\n",
                       lli, PFID(fid), PFID(&lli->lli_pfid));
                unlock_new_inode(inode);
@@ -1096,12 +1152,7 @@ static int ll_init_lsm_md(struct inode *inode, struct lustre_md *md)
                }
        }
 
-       /*
-        * Here is where the lsm is being initialized(fill lmo_info) after
-        * client retrieve MD stripe information from MDT.
-        */
-       return md_update_lsm_md(ll_i2mdexp(inode), lsm, md->body,
-                               ll_md_blocking_ast);
+       return 0;
 }
 
 static inline int lli_lsm_md_eq(const struct lmv_stripe_md *lsm_md1,
@@ -1246,7 +1297,6 @@ void ll_clear_inode(struct inode *inode)
 
 #ifdef CONFIG_FS_POSIX_ACL
        if (lli->lli_posix_acl) {
-               LASSERT(atomic_read(&lli->lli_posix_acl->a_refcount) == 1);
                posix_acl_release(lli->lli_posix_acl);
                lli->lli_posix_acl = NULL;
        }
@@ -1320,8 +1370,8 @@ static int ll_md_setattr(struct dentry *dentry, struct md_op_data *op_data,
        op_data->op_attr.ia_valid = ia_valid;
 
        /* Extract epoch data if obtained. */
-       op_data->op_handle = md.body->handle;
-       op_data->op_ioepoch = md.body->ioepoch;
+       op_data->op_handle = md.body->mbo_handle;
+       op_data->op_ioepoch = md.body->mbo_ioepoch;
 
        rc = ll_update_inode(inode, &md);
        ptlrpc_req_finished(request);
@@ -1355,8 +1405,8 @@ static int ll_setattr_done_writing(struct inode *inode,
                rc = ll_som_update(inode, op_data);
        else if (rc) {
                CERROR("%s: inode "DFID" mdc truncate failed: rc = %d\n",
-                     ll_i2sbi(inode)->ll_md_exp->exp_obd->obd_name,
-                     PFID(ll_inode2fid(inode)), rc);
+                      ll_i2sbi(inode)->ll_md_exp->exp_obd->obd_name,
+                      PFID(ll_inode2fid(inode)), rc);
        }
        return rc;
 }
@@ -1409,7 +1459,7 @@ int ll_setattr_raw(struct dentry *dentry, struct iattr *attr, bool hsm_import)
                attr->ia_valid |= ATTR_MTIME | ATTR_CTIME;
        }
 
-       /* POSIX: check before ATTR_*TIME_SET set (from inode_change_ok) */
+       /* POSIX: check before ATTR_*TIME_SET set (from setattr_prepare) */
        if (attr->ia_valid & TIMES_SET_FLAGS) {
                if ((!uid_eq(current_fsuid(), inode->i_uid)) &&
                    !capable(CFS_CAP_FOWNER))
@@ -1548,14 +1598,14 @@ int ll_setattr(struct dentry *de, struct iattr *attr)
 {
        int mode = d_inode(de)->i_mode;
 
-       if ((attr->ia_valid & (ATTR_CTIME|ATTR_SIZE|ATTR_MODE)) ==
-                             (ATTR_CTIME|ATTR_SIZE|ATTR_MODE))
+       if ((attr->ia_valid & (ATTR_CTIME | ATTR_SIZE | ATTR_MODE)) ==
+                             (ATTR_CTIME | ATTR_SIZE | ATTR_MODE))
                attr->ia_valid |= MDS_OPEN_OWNEROVERRIDE;
 
-       if (((attr->ia_valid & (ATTR_MODE|ATTR_FORCE|ATTR_SIZE)) ==
-                              (ATTR_SIZE|ATTR_MODE)) &&
+       if (((attr->ia_valid & (ATTR_MODE | ATTR_FORCE | ATTR_SIZE)) ==
+                              (ATTR_SIZE | ATTR_MODE)) &&
            (((mode & S_ISUID) && !(attr->ia_mode & S_ISUID)) ||
-            (((mode & (S_ISGID|S_IXGRP)) == (S_ISGID|S_IXGRP)) &&
+            (((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) &&
              !(attr->ia_mode & S_ISGID))))
                attr->ia_valid |= ATTR_FORCE;
 
@@ -1566,7 +1616,7 @@ int ll_setattr(struct dentry *de, struct iattr *attr)
                attr->ia_valid |= ATTR_KILL_SUID;
 
        if ((attr->ia_valid & ATTR_MODE) &&
-           ((mode & (S_ISGID|S_IXGRP)) == (S_ISGID|S_IXGRP)) &&
+           ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) &&
            !(attr->ia_mode & S_ISGID) &&
            !(attr->ia_valid & ATTR_KILL_SGID))
                attr->ia_valid |= ATTR_KILL_SGID;
@@ -1689,7 +1739,7 @@ int ll_update_inode(struct inode *inode, struct lustre_md *md)
        struct lov_stripe_md *lsm = md->lsm;
        struct ll_sb_info *sbi = ll_i2sbi(inode);
 
-       LASSERT((lsm != NULL) == ((body->valid & OBD_MD_FLEASIZE) != 0));
+       LASSERT((lsm != NULL) == ((body->mbo_valid & OBD_MD_FLEASIZE) != 0));
        if (lsm) {
                if (!lli->lli_has_smd &&
                    !(sbi->ll_flags & LL_SBI_LAYOUT_LOCK))
@@ -1709,7 +1759,7 @@ int ll_update_inode(struct inode *inode, struct lustre_md *md)
        }
 
 #ifdef CONFIG_FS_POSIX_ACL
-       if (body->valid & OBD_MD_FLACL) {
+       if (body->mbo_valid & OBD_MD_FLACL) {
                spin_lock(&lli->lli_lock);
                if (lli->lli_posix_acl)
                        posix_acl_release(lli->lli_posix_acl);
@@ -1717,65 +1767,67 @@ int ll_update_inode(struct inode *inode, struct lustre_md *md)
                spin_unlock(&lli->lli_lock);
        }
 #endif
-       inode->i_ino = cl_fid_build_ino(&body->fid1,
+       inode->i_ino = cl_fid_build_ino(&body->mbo_fid1,
                                        sbi->ll_flags & LL_SBI_32BIT_API);
-       inode->i_generation = cl_fid_build_gen(&body->fid1);
+       inode->i_generation = cl_fid_build_gen(&body->mbo_fid1);
 
-       if (body->valid & OBD_MD_FLATIME) {
-               if (body->atime > LTIME_S(inode->i_atime))
-                       LTIME_S(inode->i_atime) = body->atime;
-               lli->lli_atime = body->atime;
+       if (body->mbo_valid & OBD_MD_FLATIME) {
+               if (body->mbo_atime > LTIME_S(inode->i_atime))
+                       LTIME_S(inode->i_atime) = body->mbo_atime;
+               lli->lli_atime = body->mbo_atime;
        }
-       if (body->valid & OBD_MD_FLMTIME) {
-               if (body->mtime > LTIME_S(inode->i_mtime)) {
+       if (body->mbo_valid & OBD_MD_FLMTIME) {
+               if (body->mbo_mtime > LTIME_S(inode->i_mtime)) {
                        CDEBUG(D_INODE, "setting ino %lu mtime from %lu to %llu\n",
                               inode->i_ino, LTIME_S(inode->i_mtime),
-                              body->mtime);
-                       LTIME_S(inode->i_mtime) = body->mtime;
+                              body->mbo_mtime);
+                       LTIME_S(inode->i_mtime) = body->mbo_mtime;
                }
-               lli->lli_mtime = body->mtime;
+               lli->lli_mtime = body->mbo_mtime;
        }
-       if (body->valid & OBD_MD_FLCTIME) {
-               if (body->ctime > LTIME_S(inode->i_ctime))
-                       LTIME_S(inode->i_ctime) = body->ctime;
-               lli->lli_ctime = body->ctime;
+       if (body->mbo_valid & OBD_MD_FLCTIME) {
+               if (body->mbo_ctime > LTIME_S(inode->i_ctime))
+                       LTIME_S(inode->i_ctime) = body->mbo_ctime;
+               lli->lli_ctime = body->mbo_ctime;
        }
-       if (body->valid & OBD_MD_FLMODE)
-               inode->i_mode = (inode->i_mode & S_IFMT)|(body->mode & ~S_IFMT);
-       if (body->valid & OBD_MD_FLTYPE)
-               inode->i_mode = (inode->i_mode & ~S_IFMT)|(body->mode & S_IFMT);
+       if (body->mbo_valid & OBD_MD_FLMODE)
+               inode->i_mode = (inode->i_mode & S_IFMT) |
+                               (body->mbo_mode & ~S_IFMT);
+       if (body->mbo_valid & OBD_MD_FLTYPE)
+               inode->i_mode = (inode->i_mode & ~S_IFMT) |
+                               (body->mbo_mode & S_IFMT);
        LASSERT(inode->i_mode != 0);
        if (S_ISREG(inode->i_mode))
                inode->i_blkbits = min(PTLRPC_MAX_BRW_BITS + 1,
                                       LL_MAX_BLKSIZE_BITS);
        else
                inode->i_blkbits = inode->i_sb->s_blocksize_bits;
-       if (body->valid & OBD_MD_FLUID)
-               inode->i_uid = make_kuid(&init_user_ns, body->uid);
-       if (body->valid & OBD_MD_FLGID)
-               inode->i_gid = make_kgid(&init_user_ns, body->gid);
-       if (body->valid & OBD_MD_FLFLAGS)
-               inode->i_flags = ll_ext_to_inode_flags(body->flags);
-       if (body->valid & OBD_MD_FLNLINK)
-               set_nlink(inode, body->nlink);
-       if (body->valid & OBD_MD_FLRDEV)
-               inode->i_rdev = old_decode_dev(body->rdev);
-
-       if (body->valid & OBD_MD_FLID) {
+       if (body->mbo_valid & OBD_MD_FLUID)
+               inode->i_uid = make_kuid(&init_user_ns, body->mbo_uid);
+       if (body->mbo_valid & OBD_MD_FLGID)
+               inode->i_gid = make_kgid(&init_user_ns, body->mbo_gid);
+       if (body->mbo_valid & OBD_MD_FLFLAGS)
+               inode->i_flags = ll_ext_to_inode_flags(body->mbo_flags);
+       if (body->mbo_valid & OBD_MD_FLNLINK)
+               set_nlink(inode, body->mbo_nlink);
+       if (body->mbo_valid & OBD_MD_FLRDEV)
+               inode->i_rdev = old_decode_dev(body->mbo_rdev);
+
+       if (body->mbo_valid & OBD_MD_FLID) {
                /* FID shouldn't be changed! */
                if (fid_is_sane(&lli->lli_fid)) {
-                       LASSERTF(lu_fid_eq(&lli->lli_fid, &body->fid1),
+                       LASSERTF(lu_fid_eq(&lli->lli_fid, &body->mbo_fid1),
                                 "Trying to change FID "DFID" to the "DFID", inode "DFID"(%p)\n",
-                                PFID(&lli->lli_fid), PFID(&body->fid1),
+                                PFID(&lli->lli_fid), PFID(&body->mbo_fid1),
                                 PFID(ll_inode2fid(inode)), inode);
                } else {
-                       lli->lli_fid = body->fid1;
+                       lli->lli_fid = body->mbo_fid1;
                }
        }
 
        LASSERT(fid_seq(&lli->lli_fid) != 0);
 
-       if (body->valid & OBD_MD_FLSIZE) {
+       if (body->mbo_valid & OBD_MD_FLSIZE) {
                if (exp_connect_som(ll_i2mdexp(inode)) &&
                    S_ISREG(inode->i_mode)) {
                        struct lustre_handle lockh;
@@ -1802,7 +1854,7 @@ int ll_update_inode(struct inode *inode, struct lustre_md *md)
                                        /* Use old size assignment to avoid
                                         * deadlock bz14138 & bz14326
                                         */
-                                       i_size_write(inode, body->size);
+                                       i_size_write(inode, body->mbo_size);
                                        spin_lock(&lli->lli_lock);
                                        lli->lli_flags |= LLIF_MDS_SIZE_LOCK;
                                        spin_unlock(&lli->lli_lock);
@@ -1813,18 +1865,18 @@ int ll_update_inode(struct inode *inode, struct lustre_md *md)
                        /* Use old size assignment to avoid
                         * deadlock bz14138 & bz14326
                         */
-                       i_size_write(inode, body->size);
+                       i_size_write(inode, body->mbo_size);
 
                        CDEBUG(D_VFSTRACE, "inode=%lu, updating i_size %llu\n",
-                              inode->i_ino, (unsigned long long)body->size);
+                              inode->i_ino, (unsigned long long)body->mbo_size);
                }
 
-               if (body->valid & OBD_MD_FLBLOCKS)
-                       inode->i_blocks = body->blocks;
+               if (body->mbo_valid & OBD_MD_FLBLOCKS)
+                       inode->i_blocks = body->mbo_blocks;
        }
 
-       if (body->valid & OBD_MD_TSTATE) {
-               if (body->t_state & MS_RESTORE)
+       if (body->mbo_valid & OBD_MD_TSTATE) {
+               if (body->mbo_t_state & MS_RESTORE)
                        lli->lli_flags |= LLIF_FILE_RESTORING;
        }
 
@@ -1887,20 +1939,13 @@ void ll_delete_inode(struct inode *inode)
                 * osc_extent implementation at LU-1030.
                 */
                cl_sync_file_range(inode, 0, OBD_OBJECT_EOF,
-                                  CL_FSYNC_DISCARD, 1);
+                                  CL_FSYNC_LOCAL, 1);
 
        truncate_inode_pages_final(&inode->i_data);
 
-       /* Workaround for LU-118 */
-       if (inode->i_data.nrpages) {
-               spin_lock_irq(&inode->i_data.tree_lock);
-               spin_unlock_irq(&inode->i_data.tree_lock);
-               LASSERTF(inode->i_data.nrpages == 0,
-                        "inode="DFID"(%p) nrpages=%lu, see http://jira.whamcloud.com/browse/LU-118\n",
-                        PFID(ll_inode2fid(inode)), inode,
-                        inode->i_data.nrpages);
-       }
-       /* Workaround end */
+       LASSERTF(!inode->i_data.nrpages,
+                "inode=" DFID "(%p) nrpages=%lu, see http://jira.whamcloud.com/browse/LU-118\n",
+                PFID(ll_inode2fid(inode)), inode, inode->i_data.nrpages);
 
        ll_clear_inode(inode);
        clear_inode(inode);
@@ -1936,7 +1981,7 @@ int ll_iocontrol(struct inode *inode, struct file *file,
 
                body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY);
 
-               flags = body->flags;
+               flags = body->mbo_flags;
 
                ptlrpc_req_finished(req);
 
@@ -2118,9 +2163,9 @@ void ll_open_cleanup(struct super_block *sb, struct ptlrpc_request *open_req)
        if (!op_data)
                return;
 
-       op_data->op_fid1 = body->fid1;
-       op_data->op_ioepoch = body->ioepoch;
-       op_data->op_handle = body->handle;
+       op_data->op_fid1 = body->mbo_fid1;
+       op_data->op_ioepoch = body->mbo_ioepoch;
+       op_data->op_handle = body->mbo_handle;
        op_data->op_mod_time = get_seconds();
        md_close(exp, op_data, NULL, &close_req);
        ptlrpc_req_finished(close_req);
@@ -2152,15 +2197,15 @@ int ll_prep_inode(struct inode **inode, struct ptlrpc_request *req,
                 * At this point server returns to client's same fid as client
                 * generated for creating. So using ->fid1 is okay here.
                 */
-               if (!fid_is_sane(&md.body->fid1)) {
+               if (!fid_is_sane(&md.body->mbo_fid1)) {
                        CERROR("%s: Fid is insane " DFID "\n",
                               ll_get_fsname(sb, NULL, 0),
-                              PFID(&md.body->fid1));
+                              PFID(&md.body->mbo_fid1));
                        rc = -EINVAL;
                        goto out;
                }
 
-               *inode = ll_iget(sb, cl_fid_build_ino(&md.body->fid1,
+               *inode = ll_iget(sb, cl_fid_build_ino(&md.body->mbo_fid1,
                                             sbi->ll_flags & LL_SBI_32BIT_API),
                                 &md);
                if (IS_ERR(*inode)) {
@@ -2309,8 +2354,8 @@ int ll_process_config(struct lustre_cfg *lcfg)
 /* this function prepares md_op_data hint for passing ot down to MD stack. */
 struct md_op_data *ll_prep_md_op_data(struct md_op_data *op_data,
                                      struct inode *i1, struct inode *i2,
-                                     const char *name, int namelen,
-                                     int mode, __u32 opc, void *data)
+                                     const char *name, size_t namelen,
+                                     u32 mode, __u32 opc, void *data)
 {
        if (!name) {
                /* Do not reuse namelen for something else. */
@@ -2332,8 +2377,12 @@ struct md_op_data *ll_prep_md_op_data(struct md_op_data *op_data,
 
        ll_i2gids(op_data->op_suppgids, i1, i2);
        op_data->op_fid1 = *ll_inode2fid(i1);
-       if (S_ISDIR(i1->i_mode))
+       op_data->op_default_stripe_offset = -1;
+       if (S_ISDIR(i1->i_mode)) {
                op_data->op_mea1 = ll_i2info(i1)->lli_lsm_md;
+               op_data->op_default_stripe_offset =
+                       ll_i2info(i1)->lli_def_stripe_offset;
+       }
 
        if (i2) {
                op_data->op_fid2 = *ll_inode2fid(i2);
@@ -2359,25 +2408,12 @@ struct md_op_data *ll_prep_md_op_data(struct md_op_data *op_data,
        op_data->op_bias = 0;
        op_data->op_cli_flags = 0;
        if ((opc == LUSTRE_OPC_CREATE) && name &&
-           filename_is_volatile(name, namelen, NULL))
+           filename_is_volatile(name, namelen, &op_data->op_mds))
                op_data->op_bias |= MDS_CREATE_VOLATILE;
-       op_data->op_mds = 0;
+       else
+               op_data->op_mds = 0;
        op_data->op_data = data;
 
-       /* If the file is being opened after mknod() (normally due to NFS)
-        * try to use the default stripe data from parent directory for
-        * allocating OST objects.  Try to pass the parent FID to MDS.
-        */
-       if (opc == LUSTRE_OPC_CREATE && i1 == i2 && S_ISREG(i2->i_mode) &&
-           !ll_i2info(i2)->lli_has_smd) {
-               struct ll_inode_info *lli = ll_i2info(i2);
-
-               spin_lock(&lli->lli_lock);
-               if (likely(!lli->lli_has_smd && !fid_is_zero(&lli->lli_pfid)))
-                       op_data->op_fid1 = lli->lli_pfid;
-               spin_unlock(&lli->lli_lock);
-       }
-
        /* When called by ll_setattr_raw, file is i1. */
        if (ll_i2info(i1)->lli_flags & LLIF_DATA_MODIFIED)
                op_data->op_bias |= MDS_DATA_MODIFIED;
@@ -2505,6 +2541,36 @@ void ll_dirty_page_discard_warn(struct page *page, int ioret)
                free_page((unsigned long)buf);
 }
 
+ssize_t ll_copy_user_md(const struct lov_user_md __user *md,
+                       struct lov_user_md **kbuf)
+{
+       struct lov_user_md lum;
+       ssize_t lum_size;
+
+       if (copy_from_user(&lum, md, sizeof(lum))) {
+               lum_size = -EFAULT;
+               goto no_kbuf;
+       }
+
+       lum_size = ll_lov_user_md_size(&lum);
+       if (lum_size < 0)
+               goto no_kbuf;
+
+       *kbuf = kzalloc(lum_size, GFP_NOFS);
+       if (!*kbuf) {
+               lum_size = -ENOMEM;
+               goto no_kbuf;
+       }
+
+       if (copy_from_user(*kbuf, md, lum_size) != 0) {
+               kfree(*kbuf);
+               *kbuf = NULL;
+               lum_size = -EFAULT;
+       }
+no_kbuf:
+       return lum_size;
+}
+
 /*
  * Compute llite root squash state after a change of root squash
  * configuration setting or add/remove of a lnet nid
@@ -2543,3 +2609,128 @@ void ll_compute_rootsquash_state(struct ll_sb_info *sbi)
        }
        up_write(&squash->rsi_sem);
 }
+
+/**
+ * Parse linkea content to extract information about a given hardlink
+ *
+ * \param[in]  ldata           - Initialized linkea data
+ * \param[in]  linkno          - Link identifier
+ * \param[out] parent_fid      - The entry's parent FID
+ * \param[in]  size            - Entry name destination buffer
+ *
+ * \retval 0 on success
+ * \retval Appropriate negative error code on failure
+ */
+static int ll_linkea_decode(struct linkea_data *ldata, unsigned int linkno,
+                           struct lu_fid *parent_fid, struct lu_name *ln)
+{
+       unsigned int idx;
+       int rc;
+
+       rc = linkea_init(ldata);
+       if (rc < 0)
+               return rc;
+
+       if (linkno >= ldata->ld_leh->leh_reccount)
+               /* beyond last link */
+               return -ENODATA;
+
+       linkea_first_entry(ldata);
+       for (idx = 0; ldata->ld_lee; idx++) {
+               linkea_entry_unpack(ldata->ld_lee, &ldata->ld_reclen, ln,
+                                   parent_fid);
+               if (idx == linkno)
+                       break;
+
+               linkea_next_entry(ldata);
+       }
+
+       if (idx < linkno)
+               return -ENODATA;
+
+       return 0;
+}
+
+/**
+ * Get parent FID and name of an identified link. Operation is performed for
+ * a given link number, letting the caller iterate over linkno to list one or
+ * all links of an entry.
+ *
+ * \param[in]    file  - File descriptor against which to perform the operation
+ * \param[in,out] arg  - User-filled structure containing the linkno to operate
+ *                       on and the available size. It is eventually filled with
+ *                       the requested information or left untouched on error
+ *
+ * \retval - 0 on success
+ * \retval - Appropriate negative error code on failure
+ */
+int ll_getparent(struct file *file, struct getparent __user *arg)
+{
+       struct inode *inode = file_inode(file);
+       struct linkea_data *ldata;
+       struct lu_fid parent_fid;
+       struct lu_buf buf = {
+               .lb_buf = NULL,
+               .lb_len = 0
+       };
+       struct lu_name ln;
+       u32 name_size;
+       u32 linkno;
+       int rc;
+
+       if (!capable(CFS_CAP_DAC_READ_SEARCH) &&
+           !(ll_i2sbi(inode)->ll_flags & LL_SBI_USER_FID2PATH))
+               return -EPERM;
+
+       if (get_user(name_size, &arg->gp_name_size))
+               return -EFAULT;
+
+       if (get_user(linkno, &arg->gp_linkno))
+               return -EFAULT;
+
+       if (name_size > PATH_MAX)
+               return -EINVAL;
+
+       ldata = kzalloc(sizeof(*ldata), GFP_NOFS);
+       if (!ldata)
+               return -ENOMEM;
+
+       rc = linkea_data_new(ldata, &buf);
+       if (rc < 0)
+               goto ldata_free;
+
+       rc = ll_xattr_list(inode, XATTR_NAME_LINK, XATTR_TRUSTED_T, buf.lb_buf,
+                          buf.lb_len, OBD_MD_FLXATTR);
+       if (rc < 0)
+               goto lb_free;
+
+       rc = ll_linkea_decode(ldata, linkno, &parent_fid, &ln);
+       if (rc < 0)
+               goto lb_free;
+
+       if (ln.ln_namelen >= name_size) {
+               rc = -EOVERFLOW;
+               goto lb_free;
+       }
+
+       if (copy_to_user(&arg->gp_fid, &parent_fid, sizeof(arg->gp_fid))) {
+               rc = -EFAULT;
+               goto lb_free;
+       }
+
+       if (copy_to_user(&arg->gp_name, ln.ln_name, ln.ln_namelen)) {
+               rc = -EFAULT;
+               goto lb_free;
+       }
+
+       if (put_user('\0', arg->gp_name + ln.ln_namelen)) {
+               rc = -EFAULT;
+               goto lb_free;
+       }
+
+lb_free:
+       lu_buf_free(&buf);
+ldata_free:
+       kfree(ldata);
+       return rc;
+}