@@ -1295,6 +1295,7 @@ int ll_rmfid(struct file *file, void __user *arg)
{
const struct fid_array __user *ufa = arg;
struct inode *inode = file_inode(file);
+ struct ll_sb_info *sbi = ll_i2sbi(inode);
struct fid_array *lfa = NULL;
size_t size;
unsigned int nr;
@@ -1325,8 +1326,91 @@ int ll_rmfid(struct file *file, void __user *arg)
goto free_rcs;
}
+ /* In case of subdirectory mount, we need to make sure all the files
+ * for which we want to remove FID are visible in the namespace.
+ */
+ if (!fid_is_root(&sbi->ll_root_fid)) {
+ struct fid_array *lfa_new = NULL;
+ int path_len = PATH_MAX, linkno;
+ struct getinfo_fid2path *gf;
+ int idx, last_idx = nr - 1;
+
+ lfa_new = kzalloc(size, GFP_NOFS);
+ if (!lfa_new) {
+ rc = -ENOMEM;
+ goto free_rcs;
+ }
+ lfa_new->fa_nr = 0;
+
+ gf = kmalloc(sizeof(*gf) + path_len + 1, GFP_NOFS);
+ if (!gf) {
+ rc = -ENOMEM;
+ goto free_rcs;
+ }
+
+ for (idx = 0; idx < nr; idx++) {
+ linkno = 0;
+ while (1) {
+ memset(gf, 0, sizeof(*gf) + path_len + 1);
+ gf->gf_fid = lfa->fa_fids[idx];
+ gf->gf_pathlen = path_len;
+ gf->gf_linkno = linkno;
+ rc = __ll_fid2path(inode, gf,
+ sizeof(*gf) + gf->gf_pathlen,
+ gf->gf_pathlen);
+ if (rc == -ENAMETOOLONG) {
+ struct getinfo_fid2path *tmpgf;
+
+ path_len += PATH_MAX;
+ tmpgf = krealloc(gf,
+ sizeof(*gf) + path_len + 1,
+ GFP_NOFS);
+ if (!tmpgf) {
+ kfree(gf);
+ kfree(lfa_new);
+ rc = -ENOMEM;
+ goto free_rcs;
+ }
+ gf = tmpgf;
+ continue;
+ }
+ if (rc)
+ break;
+ if (gf->gf_linkno == linkno)
+ break;
+ linkno = gf->gf_linkno;
+ }
+
+ if (!rc) {
+ /* All the links for this fid are visible in the
+ * mounted subdir. So add it to the list of fids
+ * to remove.
+ */
+ lfa_new->fa_fids[lfa_new->fa_nr++] =
+ lfa->fa_fids[idx];
+ } else {
+ /* At least one link for this fid is not visible
+ * in the mounted subdir. So add it at the end
+ * of the list that will be hidden to lower
+ * layers, and set -ENOENT as ret code.
+ */
+ lfa_new->fa_fids[last_idx] = lfa->fa_fids[idx];
+ rcs[last_idx--] = rc;
+ }
+ }
+ kfree(gf);
+ kfree(lfa);
+ lfa = lfa_new;
+ }
+
+ if (lfa->fa_nr == 0) {
+ rc = rcs[nr - 1];
+ goto free_rcs;
+ }
+
/* Call mdc_iocontrol */
rc = md_rmfid(ll_i2mdexp(file_inode(file)), lfa, rcs, NULL);
+ lfa->fa_nr = nr;
if (!rc) {
for (i = 0; i < nr; i++)
if (rcs[i])
@@ -2917,9 +2917,37 @@ static int fid2path_for_enc_file(struct inode *parent, char *gfpath,
return rc;
}
-int ll_fid2path(struct inode *inode, void __user *arg)
+int __ll_fid2path(struct inode *inode, struct getinfo_fid2path *gfout,
+ size_t outsize, __u32 pathlen_orig)
{
struct obd_export *exp = ll_i2mdexp(inode);
+ int rc;
+
+ /* Append root FID after gfout to let MDT know the root FID so that
+ * it can lookup the correct path, this is mainly for fileset.
+ * old server without fileset mount support will ignore this.
+ */
+ *gfout->gf_root_fid = *ll_inode2fid(inode);
+
+ /* Call mdc_iocontrol */
+ rc = obd_iocontrol(OBD_IOC_FID2PATH, exp, outsize, gfout, NULL);
+
+ if (!rc && gfout->gf_pathlen && gfout->gf_path[0] == '/') {
+ /* by convention, server side (mdt_path_current()) puts
+ * a leading '/' to tell client that we are dealing with
+ * an encrypted file
+ */
+ rc = fid2path_for_enc_file(inode, gfout->gf_path,
+ gfout->gf_pathlen);
+ if (!rc && strlen(gfout->gf_path) > pathlen_orig)
+ rc = -EOVERFLOW;
+ }
+
+ return rc;
+}
+
+int ll_fid2path(struct inode *inode, void __user *arg)
+{
const struct getinfo_fid2path __user *gfin = arg;
struct getinfo_fid2path *gfout;
u32 pathlen, pathlen_orig;
@@ -2950,34 +2978,11 @@ int ll_fid2path(struct inode *inode, void __user *arg)
goto gf_free;
}
- /*
- * append root FID after gfout to let MDT know the root FID so that it
- * can lookup the correct path, this is mainly for fileset.
- * old server without fileset mount support will ignore this.
- */
- *gfout->gf_root_fid = *ll_inode2fid(inode);
gfout->gf_pathlen = pathlen;
-
- /* Call mdc_iocontrol */
- rc = obd_iocontrol(OBD_IOC_FID2PATH, exp, outsize, gfout, NULL);
+ rc = __ll_fid2path(inode, gfout, outsize, pathlen_orig);
if (rc != 0)
goto gf_free;
- if (gfout->gf_pathlen && gfout->gf_path[0] == '/') {
- /* by convention, server side (mdt_path_current()) puts
- * a leading '/' to tell client that we are dealing with
- * an encrypted file
- */
- rc = fid2path_for_enc_file(inode, gfout->gf_path,
- gfout->gf_pathlen);
- if (rc)
- goto gf_free;
- if (strlen(gfout->gf_path) > gfin->gf_pathlen) {
- rc = -EOVERFLOW;
- goto gf_free;
- }
- }
-
if (copy_to_user(arg, gfout, sizeof(*gfout) + pathlen_orig))
rc = -EFAULT;
@@ -1245,6 +1245,8 @@ int ll_dir_getstripe(struct inode *inode, void **plmm, int *plmm_size,
int ll_fsync(struct file *file, loff_t start, loff_t end, int data);
int ll_merge_attr(const struct lu_env *env, struct inode *inode);
int ll_fid2path(struct inode *inode, void __user *arg);
+int __ll_fid2path(struct inode *inode, struct getinfo_fid2path *gfout,
+ size_t outsize, u32 pathlen_orig);
int ll_data_version(struct inode *inode, u64 *data_version, int flags);
int ll_hsm_release(struct inode *inode);
int ll_hsm_state_set(struct inode *inode, struct hsm_state_set *hss);