Whamcloud - gitweb
LU-14644 vvp: wait for nrpages to be updated
[fs/lustre-release.git] / lustre / llite / llite_lib.c
index 4aa1515..c11da6c 100644 (file)
@@ -27,7 +27,6 @@
  */
 /*
  * This file is part of Lustre, http://www.lustre.org/
- * Lustre is a trademark of Sun Microsystems, Inc.
  *
  * lustre/llite/llite_lib.c
  *
@@ -48,7 +47,6 @@
 #include <linux/user_namespace.h>
 #include <linux/delay.h>
 #include <linux/uidgid.h>
-#include <linux/security.h>
 #include <linux/fs_struct.h>
 
 #ifndef HAVE_CPUS_READ_LOCK
@@ -129,6 +127,25 @@ static struct ll_sb_info *ll_init_sbi(void)
        if (sbi->ll_cache == NULL)
                GOTO(out_destroy_ra, rc = -ENOMEM);
 
+       /* initialize foreign symlink prefix path */
+       OBD_ALLOC(sbi->ll_foreign_symlink_prefix, sizeof("/mnt/"));
+       if (sbi->ll_foreign_symlink_prefix == NULL)
+               GOTO(out_destroy_ra, rc = -ENOMEM);
+       memcpy(sbi->ll_foreign_symlink_prefix, "/mnt/", sizeof("/mnt/"));
+       sbi->ll_foreign_symlink_prefix_size = sizeof("/mnt/");
+
+       /* initialize foreign symlink upcall path, none by default */
+       OBD_ALLOC(sbi->ll_foreign_symlink_upcall, sizeof("none"));
+       if (sbi->ll_foreign_symlink_upcall == NULL)
+               GOTO(out_destroy_ra, rc = -ENOMEM);
+       memcpy(sbi->ll_foreign_symlink_upcall, "none", sizeof("none"));
+       sbi->ll_foreign_symlink_upcall_items = NULL;
+       sbi->ll_foreign_symlink_upcall_nb_items = 0;
+       init_rwsem(&sbi->ll_foreign_symlink_sem);
+       /* foreign symlink support (LL_SBI_FOREIGN_SYMLINK in ll_flags)
+        * not enabled by default
+        */
+
        sbi->ll_ra_info.ra_max_pages =
                min(pages / 32, SBI_DEFAULT_READ_AHEAD_MAX);
        sbi->ll_ra_info.ra_max_pages_per_file =
@@ -136,6 +153,7 @@ static struct ll_sb_info *ll_init_sbi(void)
                    SBI_DEFAULT_READ_AHEAD_PER_FILE_MAX);
        sbi->ll_ra_info.ra_async_pages_per_file_threshold =
                                sbi->ll_ra_info.ra_max_pages_per_file;
+       sbi->ll_ra_info.ra_range_pages = SBI_DEFAULT_RA_RANGE_PAGES;
        sbi->ll_ra_info.ra_max_read_ahead_whole_pages = -1;
        atomic_set(&sbi->ll_ra_info.ra_async_inflight, 0);
 
@@ -180,8 +198,19 @@ static struct ll_sb_info *ll_init_sbi(void)
        /* Per-filesystem file heat */
        sbi->ll_heat_decay_weight = SBI_DEFAULT_HEAT_DECAY_WEIGHT;
        sbi->ll_heat_period_second = SBI_DEFAULT_HEAT_PERIOD_SECOND;
+
+       /* Per-fs open heat level before requesting open lock */
+       sbi->ll_oc_thrsh_count = SBI_DEFAULT_OPENCACHE_THRESHOLD_COUNT;
+       sbi->ll_oc_max_ms = SBI_DEFAULT_OPENCACHE_THRESHOLD_MAX_MS;
+       sbi->ll_oc_thrsh_ms = SBI_DEFAULT_OPENCACHE_THRESHOLD_MS;
        RETURN(sbi);
 out_destroy_ra:
+       if (sbi->ll_foreign_symlink_prefix)
+               OBD_FREE(sbi->ll_foreign_symlink_prefix, sizeof("/mnt/"));
+       if (sbi->ll_cache) {
+               cl_cache_decref(sbi->ll_cache);
+               sbi->ll_cache = NULL;
+       }
        destroy_workqueue(sbi->ll_ra_info.ll_readahead_wq);
 out_pcc:
        pcc_super_fini(&sbi->ll_pcc_super);
@@ -204,6 +233,32 @@ static void ll_free_sbi(struct super_block *sb)
                        cl_cache_decref(sbi->ll_cache);
                        sbi->ll_cache = NULL;
                }
+               if (sbi->ll_foreign_symlink_prefix) {
+                       OBD_FREE(sbi->ll_foreign_symlink_prefix,
+                                sbi->ll_foreign_symlink_prefix_size);
+                       sbi->ll_foreign_symlink_prefix = NULL;
+               }
+               if (sbi->ll_foreign_symlink_upcall) {
+                       OBD_FREE(sbi->ll_foreign_symlink_upcall,
+                                strlen(sbi->ll_foreign_symlink_upcall) +
+                                      1);
+                       sbi->ll_foreign_symlink_upcall = NULL;
+               }
+               if (sbi->ll_foreign_symlink_upcall_items) {
+                       int i;
+                       int nb_items = sbi->ll_foreign_symlink_upcall_nb_items;
+                       struct ll_foreign_symlink_upcall_item *items =
+                               sbi->ll_foreign_symlink_upcall_items;
+
+                       for (i = 0 ; i < nb_items; i++)
+                               if (items[i].type == STRING_TYPE)
+                                       OBD_FREE(items[i].string,
+                                                      items[i].size);
+
+                       OBD_FREE_LARGE(items, nb_items *
+                               sizeof(struct ll_foreign_symlink_upcall_item));
+                       sbi->ll_foreign_symlink_upcall_items = NULL;
+               }
                pcc_super_fini(&sbi->ll_pcc_super);
                OBD_FREE(sbi, sizeof(*sbi));
        }
@@ -278,8 +333,10 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt)
                                   OBD_CONNECT2_LSOM |
                                   OBD_CONNECT2_ASYNC_DISCARD |
                                   OBD_CONNECT2_PCC |
-                                  OBD_CONNECT2_CRUSH |
-                                  OBD_CONNECT2_GETATTR_PFID;
+                                  OBD_CONNECT2_CRUSH | OBD_CONNECT2_LSEEK |
+                                  OBD_CONNECT2_GETATTR_PFID |
+                                  OBD_CONNECT2_DOM_LVB |
+                                  OBD_CONNECT2_REP_MBITS;
 
 #ifdef HAVE_LRU_RESIZE_SUPPORT
         if (sbi->ll_flags & LL_SBI_LRU_RESIZE)
@@ -308,13 +365,7 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt)
         */
        sb->s_flags |= SB_NOSEC;
 #endif
-
-       if (sbi->ll_flags & LL_SBI_FLOCK)
-               sbi->ll_fop = &ll_file_operations_flock;
-       else if (sbi->ll_flags & LL_SBI_LOCALFLOCK)
-               sbi->ll_fop = &ll_file_operations;
-       else
-               sbi->ll_fop = &ll_file_operations_noflock;
+       sbi->ll_fop = ll_select_file_operations(sbi);
 
        /* always ping even if server suppress_pings */
        if (sbi->ll_flags & LL_SBI_ALWAYS_PING)
@@ -477,7 +528,8 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt)
                                  OBD_CONNECT_BULK_MBITS | OBD_CONNECT_SHORTIO |
                                  OBD_CONNECT_FLAGS2 | OBD_CONNECT_GRANT_SHRINK;
        data->ocd_connect_flags2 = OBD_CONNECT2_LOCKAHEAD |
-                                  OBD_CONNECT2_INC_XID;
+                                  OBD_CONNECT2_INC_XID | OBD_CONNECT2_LSEEK |
+                                  OBD_CONNECT2_REP_MBITS;
 
        if (!OBD_FAIL_CHECK(OBD_FAIL_OSC_CONNECT_GRANT_PARAM))
                data->ocd_connect_flags |= OBD_CONNECT_GRANT_PARAM;
@@ -696,8 +748,7 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt)
 
        RETURN(err);
 out_root:
-       if (root)
-               iput(root);
+       iput(root);
 out_lock_cn_cb:
        obd_fid_fini(sbi->ll_dt_exp->exp_obd);
 out_dt:
@@ -986,6 +1037,58 @@ static int ll_options(char *options, struct ll_sb_info *sbi)
 #endif
                        goto next;
                }
+               tmp = ll_set_opt("foreign_symlink", s1, LL_SBI_FOREIGN_SYMLINK);
+               if (tmp) {
+                       int prefix_pos = sizeof("foreign_symlink=") - 1;
+                       int equal_pos = sizeof("foreign_symlink=") - 2;
+
+                       /* non-default prefix provided ? */
+                       if (strlen(s1) >= sizeof("foreign_symlink=") &&
+                           *(s1 + equal_pos) == '=') {
+                               char *old = sbi->ll_foreign_symlink_prefix;
+                               size_t old_len =
+                                       sbi->ll_foreign_symlink_prefix_size;
+
+                               /* path must be absolute */
+                               if (*(s1 + sizeof("foreign_symlink=")
+                                     - 1) != '/') {
+                                       LCONSOLE_ERROR_MSG(0x152,
+                                               "foreign prefix '%s' must be an absolute path\n",
+                                               s1 + prefix_pos);
+                                       RETURN(-EINVAL);
+                               }
+                               /* last option ? */
+                               s2 = strchrnul(s1 + prefix_pos, ',');
+
+                               if (sbi->ll_foreign_symlink_prefix) {
+                                       sbi->ll_foreign_symlink_prefix = NULL;
+                                       sbi->ll_foreign_symlink_prefix_size = 0;
+                               }
+                               /* alloc for path length and '\0' */
+                               OBD_ALLOC(sbi->ll_foreign_symlink_prefix,
+                                               s2 - (s1 + prefix_pos) + 1);
+                               if (!sbi->ll_foreign_symlink_prefix) {
+                                       /* restore previous */
+                                       sbi->ll_foreign_symlink_prefix = old;
+                                       sbi->ll_foreign_symlink_prefix_size =
+                                               old_len;
+                                       RETURN(-ENOMEM);
+                               }
+                               if (old)
+                                       OBD_FREE(old, old_len);
+                               strncpy(sbi->ll_foreign_symlink_prefix,
+                                       s1 + prefix_pos,
+                                       s2 - (s1 + prefix_pos));
+                               sbi->ll_foreign_symlink_prefix_size =
+                                       s2 - (s1 + prefix_pos) + 1;
+                       } else {
+                               LCONSOLE_ERROR_MSG(0x152,
+                                                  "invalid %s option\n", s1);
+                       }
+                       /* enable foreign symlink support */
+                       *flags |= tmp;
+                       goto next;
+               }
                 LCONSOLE_ERROR_MSG(0x152, "Unknown option '%s', won't mount.\n",
                                    s1);
                 RETURN(-EINVAL);
@@ -1118,6 +1221,8 @@ int ll_fill_super(struct super_block *sb)
        CDEBUG(D_VFSTRACE, "VFS Op: cfg_instance %s-%016lx (sb %p)\n",
               profilenm, cfg_instance, sb);
 
+       OBD_RACE(OBD_FAIL_LLITE_RACE_MOUNT);
+
        OBD_ALLOC_PTR(cfg);
        if (cfg == NULL)
                GOTO(out_free_cfg, err = -ENOMEM);
@@ -1324,8 +1429,6 @@ out_no_sbi:
 
        cl_env_cache_purge(~0);
 
-       module_put(THIS_MODULE);
-
        EXIT;
 } /* client_put_super */
 
@@ -1487,30 +1590,27 @@ static void ll_update_default_lsm_md(struct inode *inode, struct lustre_md *md)
                        }
                        up_write(&lli->lli_lsm_sem);
                }
-       } else if (lli->lli_default_lsm_md) {
-               /* update default lsm if it changes */
+               return;
+       }
+
+       if (lli->lli_default_lsm_md) {
+               /* do nonthing if default lsm isn't changed */
                down_read(&lli->lli_lsm_sem);
                if (lli->lli_default_lsm_md &&
-                   !lsm_md_eq(lli->lli_default_lsm_md, md->default_lmv)) {
-                       up_read(&lli->lli_lsm_sem);
-                       down_write(&lli->lli_lsm_sem);
-                       if (lli->lli_default_lsm_md)
-                               lmv_free_memmd(lli->lli_default_lsm_md);
-                       lli->lli_default_lsm_md = md->default_lmv;
-                       lsm_md_dump(D_INODE, md->default_lmv);
-                       md->default_lmv = NULL;
-                       up_write(&lli->lli_lsm_sem);
-               } else {
+                   lsm_md_eq(lli->lli_default_lsm_md, md->default_lmv)) {
                        up_read(&lli->lli_lsm_sem);
+                       return;
                }
-       } else {
-               /* init default lsm */
-               down_write(&lli->lli_lsm_sem);
-               lli->lli_default_lsm_md = md->default_lmv;
-               lsm_md_dump(D_INODE, md->default_lmv);
-               md->default_lmv = NULL;
-               up_write(&lli->lli_lsm_sem);
+               up_read(&lli->lli_lsm_sem);
        }
+
+       down_write(&lli->lli_lsm_sem);
+       if (lli->lli_default_lsm_md)
+               lmv_free_memmd(lli->lli_default_lsm_md);
+       lli->lli_default_lsm_md = md->default_lmv;
+       lsm_md_dump(D_INODE, md->default_lmv);
+       md->default_lmv = NULL;
+       up_write(&lli->lli_lsm_sem);
 }
 
 static int ll_update_lsm_md(struct inode *inode, struct lustre_md *md)
@@ -1595,8 +1695,8 @@ static int ll_update_lsm_md(struct inode *inode, struct lustre_md *md)
                GOTO(unlock, rc = -ENOMEM);
 
        /* validate the lsm */
-       rc = md_merge_attr(ll_i2mdexp(inode), &lli->lli_fid, lli->lli_lsm_md,
-                          attr, ll_md_blocking_ast);
+       rc = md_merge_attr(ll_i2mdexp(inode), lli->lli_lsm_md, attr,
+                          ll_md_blocking_ast);
        if (!rc) {
                if (md->body->mbo_valid & OBD_MD_FLNLINK)
                        md->body->mbo_nlink = attr->cat_nlink;
@@ -1946,7 +2046,7 @@ int ll_setattr_raw(struct dentry *dentry, struct iattr *attr,
        /* POSIX: check before ATTR_*TIME_SET set (from inode_change_ok) */
        if (attr->ia_valid & TIMES_SET_FLAGS) {
                if ((!uid_eq(current_fsuid(), inode->i_uid)) &&
-                   !cfs_capable(CFS_CAP_FOWNER))
+                   !capable(CAP_FOWNER))
                        RETURN(-EPERM);
        }
 
@@ -1988,7 +2088,7 @@ int ll_setattr_raw(struct dentry *dentry, struct iattr *attr,
                 */
                xvalid |= OP_XVALID_OWNEROVERRIDE;
                op_data->op_bias |= MDS_DATA_MODIFIED;
-               ll_file_clear_flag(lli, LLIF_DATA_MODIFIED);
+               clear_bit(LLIF_DATA_MODIFIED, &lli->lli_flags);
        }
 
        if (attr->ia_valid & ATTR_FILE) {
@@ -2073,7 +2173,7 @@ int ll_setattr_raw(struct dentry *dentry, struct iattr *attr,
         * LLIF_DATA_MODIFIED is not set(see vvp_io_setattr_fini()).
         * This way we can save an RPC for common open + trunc
         * operation. */
-       if (ll_file_test_and_clear_flag(lli, LLIF_DATA_MODIFIED)) {
+       if (test_and_clear_bit(LLIF_DATA_MODIFIED, &lli->lli_flags)) {
                struct hsm_state_set hss = {
                        .hss_valid = HSS_SETMASK,
                        .hss_setmask = HS_DIRTY,
@@ -2205,6 +2305,52 @@ out:
        RETURN(rc);
 }
 
+static int ll_statfs_project(struct inode *inode, struct kstatfs *sfs)
+{
+       struct if_quotactl qctl = {
+               .qc_cmd = LUSTRE_Q_GETQUOTA,
+               .qc_type = PRJQUOTA,
+               .qc_valid = QC_GENERAL,
+       };
+       u64 limit, curblock;
+       int ret;
+
+       qctl.qc_id = ll_i2info(inode)->lli_projid;
+       ret = quotactl_ioctl(ll_i2sbi(inode), &qctl);
+       if (ret) {
+               /* ignore errors if project ID does not have
+                * a quota limit or feature unsupported.
+                */
+               if (ret == -ESRCH || ret == -EOPNOTSUPP)
+                       ret = 0;
+               return ret;
+       }
+
+       limit = ((qctl.qc_dqblk.dqb_bsoftlimit ?
+                qctl.qc_dqblk.dqb_bsoftlimit :
+                qctl.qc_dqblk.dqb_bhardlimit) * 1024) / sfs->f_bsize;
+       if (limit && sfs->f_blocks > limit) {
+               curblock = (qctl.qc_dqblk.dqb_curspace +
+                               sfs->f_bsize - 1) / sfs->f_bsize;
+               sfs->f_blocks = limit;
+               sfs->f_bfree = sfs->f_bavail =
+                       (sfs->f_blocks > curblock) ?
+                       (sfs->f_blocks - curblock) : 0;
+       }
+
+       limit = qctl.qc_dqblk.dqb_isoftlimit ?
+               qctl.qc_dqblk.dqb_isoftlimit :
+               qctl.qc_dqblk.dqb_ihardlimit;
+       if (limit && sfs->f_files > limit) {
+               sfs->f_files = limit;
+               sfs->f_ffree = (sfs->f_files >
+                       qctl.qc_dqblk.dqb_curinodes) ?
+                       (sfs->f_files - qctl.qc_dqblk.dqb_curinodes) : 0;
+       }
+
+       return 0;
+}
+
 int ll_statfs(struct dentry *de, struct kstatfs *sfs)
 {
        struct super_block *sb = de->d_sb;
@@ -2241,6 +2387,8 @@ int ll_statfs(struct dentry *de, struct kstatfs *sfs)
        sfs->f_bavail = osfs.os_bavail;
        sfs->f_fsid.val[0] = (__u32)fsid;
        sfs->f_fsid.val[1] = (__u32)(fsid >> 32);
+       if (ll_i2info(de->d_inode)->lli_projid)
+               return ll_statfs_project(de->d_inode, sfs);
 
        ll_stats_ops_tally(ll_s2sbi(sb), LPROC_LL_STATFS,
                           ktime_us_delta(ktime_get(), kstart));
@@ -2266,15 +2414,15 @@ void ll_inode_size_unlock(struct inode *inode)
        mutex_unlock(&lli->lli_size_mutex);
 }
 
-void ll_update_inode_flags(struct inode *inode, int ext_flags)
+void ll_update_inode_flags(struct inode *inode, unsigned int ext_flags)
 {
        /* do not clear encryption flag */
        ext_flags |= ll_inode_to_ext_flags(inode->i_flags) & LUSTRE_ENCRYPT_FL;
        inode->i_flags = ll_ext_to_inode_flags(ext_flags);
        if (ext_flags & LUSTRE_PROJINHERIT_FL)
-               ll_file_set_flag(ll_i2info(inode), LLIF_PROJECT_INHERIT);
+               set_bit(LLIF_PROJECT_INHERIT, &ll_i2info(inode)->lli_flags);
        else
-               ll_file_clear_flag(ll_i2info(inode), LLIF_PROJECT_INHERIT);
+               clear_bit(LLIF_PROJECT_INHERIT, &ll_i2info(inode)->lli_flags);
 }
 
 int ll_update_inode(struct inode *inode, struct lustre_md *md)
@@ -2390,14 +2538,42 @@ int ll_update_inode(struct inode *inode, struct lustre_md *md)
                 * glimpsing updated attrs
                 */
                if (body->mbo_t_state & MS_RESTORE)
-                       ll_file_set_flag(lli, LLIF_FILE_RESTORING);
+                       set_bit(LLIF_FILE_RESTORING, &lli->lli_flags);
                else
-                       ll_file_clear_flag(lli, LLIF_FILE_RESTORING);
+                       clear_bit(LLIF_FILE_RESTORING, &lli->lli_flags);
        }
 
        return 0;
 }
 
+void ll_truncate_inode_pages_final(struct inode *inode)
+{
+       struct address_space *mapping = &inode->i_data;
+       unsigned long nrpages;
+       unsigned long flags;
+
+       truncate_inode_pages_final(mapping);
+
+       /* Workaround for LU-118: Note nrpages may not be totally updated when
+        * truncate_inode_pages() returns, as there can be a page in the process
+        * of deletion (inside __delete_from_page_cache()) in the specified
+        * range. Thus mapping->nrpages can be non-zero when this function
+        * returns even after truncation of the whole mapping.  Only do this if
+        * npages isn't already zero.
+        */
+       nrpages = mapping->nrpages;
+       if (nrpages) {
+               ll_xa_lock_irqsave(&mapping->i_pages, flags);
+               nrpages = mapping->nrpages;
+               ll_xa_unlock_irqrestore(&mapping->i_pages, flags);
+       } /* Workaround end */
+
+       LASSERTF(nrpages == 0, "%s: inode="DFID"(%p) nrpages=%lu, "
+                "see https://jira.whamcloud.com/browse/LU-118\n",
+                ll_i2sbi(inode)->ll_fsname,
+                PFID(ll_inode2fid(inode)), inode, nrpages);
+}
+
 int ll_read_inode2(struct inode *inode, void *opaque)
 {
         struct lustre_md *md = opaque;
@@ -2455,10 +2631,6 @@ int ll_read_inode2(struct inode *inode, void *opaque)
 void ll_delete_inode(struct inode *inode)
 {
        struct ll_inode_info *lli = ll_i2info(inode);
-       struct address_space *mapping = &inode->i_data;
-       unsigned long nrpages;
-       unsigned long flags;
-
        ENTRY;
 
        if (S_ISREG(inode->i_mode) && lli->lli_clob != NULL) {
@@ -2472,27 +2644,8 @@ void ll_delete_inode(struct inode *inode)
                cl_sync_file_range(inode, 0, OBD_OBJECT_EOF, inode->i_nlink ?
                                   CL_FSYNC_LOCAL : CL_FSYNC_DISCARD, 1);
        }
-       truncate_inode_pages_final(mapping);
-
-       /* Workaround for LU-118: Note nrpages may not be totally updated when
-        * truncate_inode_pages() returns, as there can be a page in the process
-        * of deletion (inside __delete_from_page_cache()) in the specified
-        * range. Thus mapping->nrpages can be non-zero when this function
-        * returns even after truncation of the whole mapping.  Only do this if
-        * npages isn't already zero.
-        */
-       nrpages = mapping->nrpages;
-       if (nrpages) {
-               ll_xa_lock_irqsave(&mapping->i_pages, flags);
-               nrpages = mapping->nrpages;
-               ll_xa_unlock_irqrestore(&mapping->i_pages, flags);
-       } /* Workaround end */
-
-       LASSERTF(nrpages == 0, "%s: inode="DFID"(%p) nrpages=%lu, "
-                "see https://jira.whamcloud.com/browse/LU-118\n",
-                ll_i2sbi(inode)->ll_fsname,
-                PFID(ll_inode2fid(inode)), inode, nrpages);
 
+       ll_truncate_inode_pages_final(inode);
        ll_clear_inode(inode);
        clear_inode(inode);
 
@@ -2820,6 +2973,13 @@ int ll_prep_inode(struct inode **inode, struct ptlrpc_request *req,
        if (default_lmv_deleted)
                ll_update_default_lsm_md(*inode, &md);
 
+       /* we may want to apply some policy for foreign file/dir */
+       if (ll_sbi_has_foreign_symlink(sbi)) {
+               rc = ll_manage_foreign(*inode, &md);
+               if (rc < 0)
+                       GOTO(out, rc);
+       }
+
        GOTO(out, rc = 0);
 
 out:
@@ -2836,44 +2996,44 @@ out:
 
 int ll_obd_statfs(struct inode *inode, void __user *arg)
 {
-        struct ll_sb_info *sbi = NULL;
-        struct obd_export *exp;
-        char *buf = NULL;
-        struct obd_ioctl_data *data = NULL;
-        __u32 type;
-        int len = 0, rc;
-
-        if (!inode || !(sbi = ll_i2sbi(inode)))
-                GOTO(out_statfs, rc = -EINVAL);
-
-        rc = obd_ioctl_getdata(&buf, &len, arg);
-        if (rc)
-                GOTO(out_statfs, rc);
-
-        data = (void*)buf;
-        if (!data->ioc_inlbuf1 || !data->ioc_inlbuf2 ||
-            !data->ioc_pbuf1 || !data->ioc_pbuf2)
-                GOTO(out_statfs, rc = -EINVAL);
-
-        if (data->ioc_inllen1 != sizeof(__u32) ||
-            data->ioc_inllen2 != sizeof(__u32) ||
-            data->ioc_plen1 != sizeof(struct obd_statfs) ||
-            data->ioc_plen2 != sizeof(struct obd_uuid))
-                GOTO(out_statfs, rc = -EINVAL);
-
-        memcpy(&type, data->ioc_inlbuf1, sizeof(__u32));
+       struct ll_sb_info *sbi = NULL;
+       struct obd_export *exp;
+       struct obd_ioctl_data *data = NULL;
+       __u32 type;
+       int len = 0, rc;
+
+       if (inode)
+               sbi = ll_i2sbi(inode);
+       if (!sbi)
+               GOTO(out_statfs, rc = -EINVAL);
+
+       rc = obd_ioctl_getdata(&data, &len, arg);
+       if (rc)
+               GOTO(out_statfs, rc);
+
+       if (!data->ioc_inlbuf1 || !data->ioc_inlbuf2 ||
+           !data->ioc_pbuf1 || !data->ioc_pbuf2)
+               GOTO(out_statfs, rc = -EINVAL);
+
+       if (data->ioc_inllen1 != sizeof(__u32) ||
+           data->ioc_inllen2 != sizeof(__u32) ||
+           data->ioc_plen1 != sizeof(struct obd_statfs) ||
+           data->ioc_plen2 != sizeof(struct obd_uuid))
+               GOTO(out_statfs, rc = -EINVAL);
+
+       memcpy(&type, data->ioc_inlbuf1, sizeof(__u32));
        if (type & LL_STATFS_LMV)
-                exp = sbi->ll_md_exp;
+               exp = sbi->ll_md_exp;
        else if (type & LL_STATFS_LOV)
-                exp = sbi->ll_dt_exp;
-        else
-                GOTO(out_statfs, rc = -ENODEV);
+               exp = sbi->ll_dt_exp;
+       else
+               GOTO(out_statfs, rc = -ENODEV);
 
-       rc = obd_iocontrol(IOC_OBD_STATFS, exp, len, buf, NULL);
-        if (rc)
-                GOTO(out_statfs, rc);
+       rc = obd_iocontrol(IOC_OBD_STATFS, exp, len, data, NULL);
+       if (rc)
+               GOTO(out_statfs, rc);
 out_statfs:
-       OBD_FREE_LARGE(buf, len);
+       OBD_FREE_LARGE(data, len);
        return rc;
 }
 
@@ -2977,8 +3137,8 @@ struct md_op_data *ll_prep_md_op_data(struct md_op_data *op_data,
 void ll_finish_md_op_data(struct md_op_data *op_data)
 {
        ll_unlock_md_op_lsm(op_data);
-       security_release_secctx(op_data->op_file_secctx,
-                               op_data->op_file_secctx_size);
+       ll_security_release_secctx(op_data->op_file_secctx,
+                                  op_data->op_file_secctx_size);
        llcrypt_free_ctx(op_data->op_file_encctx, op_data->op_file_encctx_size);
        OBD_FREE_PTR(op_data);
 }
@@ -3024,6 +3184,11 @@ int ll_show_options(struct seq_file *seq, struct dentry *dentry)
        else
                seq_puts(seq, ",noencrypt");
 
+       if (sbi->ll_flags & LL_SBI_FOREIGN_SYMLINK) {
+               seq_puts(seq, ",foreign_symlink=");
+               seq_puts(seq, sbi->ll_foreign_symlink_prefix);
+       }
+
        RETURN(0);
 }
 
@@ -3036,7 +3201,7 @@ int ll_get_obd_name(struct inode *inode, unsigned int cmd, unsigned long arg)
         struct obd_device *obd;
         ENTRY;
 
-        if (cmd == OBD_IOC_GETDTNAME)
+       if (cmd == OBD_IOC_GETNAME_OLD || cmd == OBD_IOC_GETDTNAME)
                 obd = class_exp2obd(sbi->ll_dt_exp);
         else if (cmd == OBD_IOC_GETMDNAME)
                 obd = class_exp2obd(sbi->ll_md_exp);
@@ -3226,7 +3391,7 @@ int ll_getparent(struct file *file, struct getparent __user *arg)
 
        ENTRY;
 
-       if (!cfs_capable(CFS_CAP_DAC_READ_SEARCH) &&
+       if (!capable(CAP_DAC_READ_SEARCH) &&
            !(ll_i2sbi(inode)->ll_flags & LL_SBI_USER_FID2PATH))
                RETURN(-EPERM);