Whamcloud - gitweb
LU-14677 sec: migrate/extend/split on encrypted file
[fs/lustre-release.git] / lustre / llite / llite_lib.c
index 3744aa2..d0597f2 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);
 
@@ -169,6 +187,7 @@ static struct ll_sb_info *ll_init_sbi(void)
        sbi->ll_flags |= LL_SBI_AGL_ENABLED;
        sbi->ll_flags |= LL_SBI_FAST_READ;
        sbi->ll_flags |= LL_SBI_TINY_WRITE;
+       sbi->ll_flags |= LL_SBI_PARALLEL_DIO;
        ll_sbi_set_encrypt(sbi, true);
 
        /* root squash */
@@ -180,8 +199,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 +234,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));
        }
@@ -279,7 +335,10 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt)
                                   OBD_CONNECT2_ASYNC_DISCARD |
                                   OBD_CONNECT2_PCC |
                                   OBD_CONNECT2_CRUSH | OBD_CONNECT2_LSEEK |
-                                  OBD_CONNECT2_GETATTR_PFID;
+                                  OBD_CONNECT2_GETATTR_PFID |
+                                  OBD_CONNECT2_DOM_LVB |
+                                  OBD_CONNECT2_REP_MBITS |
+                                  OBD_CONNECT2_ATOMIC_OPEN_LOCK;
 
 #ifdef HAVE_LRU_RESIZE_SUPPORT
         if (sbi->ll_flags & LL_SBI_LRU_RESIZE)
@@ -308,13 +367,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 +530,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_LSEEK;
+                                  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;
@@ -611,8 +665,8 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt)
                GOTO(out_lock_cn_cb, err);
        }
 
-       err = md_get_lustre_md(sbi->ll_md_exp, request, sbi->ll_dt_exp,
-                              sbi->ll_md_exp, &lmd);
+       err = md_get_lustre_md(sbi->ll_md_exp, &request->rq_pill,
+                              sbi->ll_dt_exp, sbi->ll_md_exp, &lmd);
        if (err) {
                CERROR("failed to understand root inode md: rc = %d\n", err);
                ptlrpc_req_finished(request);
@@ -696,8 +750,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 +1039,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 +1223,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 +1431,6 @@ out_no_sbi:
 
        cl_env_cache_purge(~0);
 
-       module_put(THIS_MODULE);
-
        EXIT;
 } /* client_put_super */
 
@@ -1375,12 +1480,15 @@ static struct inode *ll_iget_anon_dir(struct super_block *sb,
                                      const struct lu_fid *fid,
                                      struct lustre_md *md)
 {
-       struct ll_sb_info       *sbi = ll_s2sbi(sb);
-       struct mdt_body         *body = md->body;
-       struct inode            *inode;
-       ino_t                   ino;
+       struct ll_sb_info *sbi = ll_s2sbi(sb);
+       struct ll_inode_info *lli;
+       struct mdt_body *body = md->body;
+       struct inode *inode;
+       ino_t ino;
+
        ENTRY;
 
+       LASSERT(md->lmv);
        ino = cl_fid_build_ino(fid, sbi->ll_flags & LL_SBI_32BIT_API);
        inode = iget_locked(sb, ino);
        if (inode == NULL) {
@@ -1389,10 +1497,8 @@ static struct inode *ll_iget_anon_dir(struct super_block *sb,
                RETURN(ERR_PTR(-ENOENT));
        }
 
+       lli = ll_i2info(inode);
        if (inode->i_state & I_NEW) {
-               struct ll_inode_info *lli = ll_i2info(inode);
-               struct lmv_stripe_md *lsm = md->lmv;
-
                inode->i_mode = (inode->i_mode & ~S_IFMT) |
                                (body->mbo_mode & S_IFMT);
                LASSERTF(S_ISDIR(inode->i_mode), "Not slave inode "DFID"\n",
@@ -1413,12 +1519,17 @@ static struct inode *ll_iget_anon_dir(struct super_block *sb,
                lli->lli_fid = *fid;
                ll_lli_init(lli);
 
-               LASSERT(lsm != NULL);
                /* master object FID */
                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);
+       } else {
+               /* in directory restripe/auto-split, a directory will be
+                * transformed to a stripe if it's plain, set its pfid here,
+                * otherwise ll_lock_cancel_bits() can't find the master inode.
+                */
+               lli->lli_pfid = body->mbo_fid1;
        }
 
        RETURN(inode);
@@ -1487,30 +1598,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)
@@ -1530,6 +1638,12 @@ static int ll_update_lsm_md(struct inode *inode, struct lustre_md *md)
        if (md->default_lmv)
                ll_update_default_lsm_md(inode, md);
 
+       /* after dir migration/restripe, a stripe may be turned into a
+        * directory, in this case, zero out its lli_pfid.
+        */
+       if (unlikely(fid_is_norm(&lli->lli_pfid)))
+               fid_zero(&lli->lli_pfid);
+
        /*
         * no striped information from request, lustre_md from req does not
         * include stripeEA, see ll_md_setattr()
@@ -1595,8 +1709,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;
@@ -1712,8 +1826,8 @@ static int ll_md_setattr(struct dentry *dentry, struct md_op_data *op_data)
                RETURN(rc);
        }
 
-        rc = md_get_lustre_md(sbi->ll_md_exp, request, sbi->ll_dt_exp,
-                              sbi->ll_md_exp, &md);
+       rc = md_get_lustre_md(sbi->ll_md_exp, &request->rq_pill, sbi->ll_dt_exp,
+                             sbi->ll_md_exp, &md);
         if (rc) {
                 ptlrpc_req_finished(request);
                 RETURN(rc);
@@ -1946,7 +2060,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 +2102,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) {
@@ -2033,8 +2147,7 @@ int ll_setattr_raw(struct dentry *dentry, struct iattr *attr,
                         * it is necessary due to possible time
                         * de-synchronization between MDT inode and OST objects
                         */
-                       if (S_ISREG(inode->i_mode) && IS_ENCRYPTED(inode) &&
-                           attr->ia_valid & ATTR_SIZE) {
+                       if (S_ISREG(inode->i_mode) && IS_ENCRYPTED(inode)) {
                                xvalid |= OP_XVALID_FLAGS;
                                flags = LUSTRE_ENCRYPT_FL;
                                /* Call to ll_io_zero_page is not necessary if
@@ -2043,7 +2156,8 @@ int ll_setattr_raw(struct dentry *dentry, struct iattr *attr,
                                 * In case of Direct IO, all we need is to set
                                 * new size.
                                 */
-                               if (attr->ia_size & ~PAGE_MASK &&
+                               if (attr->ia_valid & ATTR_SIZE &&
+                                   attr->ia_size & ~PAGE_MASK &&
                                    !(attr->ia_valid & ATTR_FILE &&
                                      attr->ia_file->f_flags & O_DIRECT)) {
                                        pgoff_t offset =
@@ -2073,7 +2187,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,
@@ -2314,15 +2428,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)
@@ -2438,14 +2552,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;
@@ -2503,10 +2645,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) {
@@ -2520,27 +2658,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);
 
@@ -2597,7 +2716,8 @@ int ll_iocontrol(struct inode *inode, struct file *file,
                if (flags & LUSTRE_PROJINHERIT_FL)
                        fa.fsx_xflags = FS_XFLAG_PROJINHERIT;
 
-               rc = ll_ioctl_check_project(inode, &fa);
+               rc = ll_ioctl_check_project(inode, fa.fsx_xflags,
+                                           fa.fsx_projid);
                if (rc)
                        RETURN(rc);
 
@@ -2754,7 +2874,7 @@ int ll_remount_fs(struct super_block *sb, int *flags, char *data)
  * \param[in] sb       super block for this file-system
  * \param[in] open_req pointer to the original open request
  */
-void ll_open_cleanup(struct super_block *sb, struct ptlrpc_request *open_req)
+void ll_open_cleanup(struct super_block *sb, struct req_capsule *pill)
 {
        struct mdt_body                 *body;
        struct md_op_data               *op_data;
@@ -2762,7 +2882,7 @@ void ll_open_cleanup(struct super_block *sb, struct ptlrpc_request *open_req)
        struct obd_export               *exp       = ll_s2sbi(sb)->ll_md_exp;
        ENTRY;
 
-       body = req_capsule_server_get(&open_req->rq_pill, &RMF_MDT_BODY);
+       body = req_capsule_server_get(pill, &RMF_MDT_BODY);
        OBD_ALLOC_PTR(op_data);
        if (op_data == NULL) {
                CWARN("%s: cannot allocate op_data to release open handle for "
@@ -2781,7 +2901,7 @@ void ll_open_cleanup(struct super_block *sb, struct ptlrpc_request *open_req)
        EXIT;
 }
 
-int ll_prep_inode(struct inode **inode, struct ptlrpc_request *req,
+int ll_prep_inode(struct inode **inode, struct req_capsule *pill,
                  struct super_block *sb, struct lookup_intent *it)
 {
        struct ll_sb_info *sbi = NULL;
@@ -2793,7 +2913,7 @@ int ll_prep_inode(struct inode **inode, struct ptlrpc_request *req,
 
        LASSERT(*inode || sb);
        sbi = sb ? ll_s2sbi(sb) : ll_i2sbi(*inode);
-       rc = md_get_lustre_md(sbi->ll_md_exp, req, sbi->ll_dt_exp,
+       rc = md_get_lustre_md(sbi->ll_md_exp, pill, sbi->ll_dt_exp,
                              sbi->ll_md_exp, &md);
        if (rc != 0)
                GOTO(out, rc);
@@ -2868,6 +2988,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:
@@ -2876,7 +3003,7 @@ out:
 
        if (rc != 0 && it != NULL && it->it_op & IT_OPEN) {
                ll_intent_drop_lock(it);
-               ll_open_cleanup(sb != NULL ? sb : (*inode)->i_sb, req);
+               ll_open_cleanup(sb != NULL ? sb : (*inode)->i_sb, pill);
        }
 
        return rc;
@@ -2884,44 +3011,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;
 }
 
@@ -3025,8 +3152,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);
 }
@@ -3072,6 +3199,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);
 }
 
@@ -3084,7 +3216,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);
@@ -3274,7 +3406,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);