4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; If not, see
18 * http://www.gnu.org/licenses/gpl-2.0.html
23 * Copyright (c) 2020 Intel Corporation.
25 #define DEBUG_SUBSYSTEM S_LLITE
27 #include "llite_internal.h"
29 static void ll_manage_foreign_file(struct inode *inode,
30 struct lov_foreign_md *lfm)
32 struct ll_sb_info *sbi = ll_i2sbi(inode);
34 if (le32_to_cpu(lfm->lfm_type) == LU_FOREIGN_TYPE_SYMLINK) {
36 "%s: inode %p of fid "DFID": Foreign file of type symlink, faking a symlink\n",
37 sbi->ll_fsname, inode, PFID(ll_inode2fid(inode)));
38 /* change inode_operations to add symlink methods, and clear
39 * IOP_NOFOLLOW to ensure file will be treated as a symlink
40 * by Kernel (see in * d_flags_for_inode()).
42 inode->i_op = &ll_foreign_file_symlink_inode_operations;
43 inode->i_opflags &= ~IOP_NOFOLLOW;
46 "%s: inode %p of fid "DFID": Foreign file of type %ux, nothing special to do\n",
47 sbi->ll_fsname, inode, PFID(ll_inode2fid(inode)),
48 le32_to_cpu(lfm->lfm_type));
52 static void ll_manage_foreign_dir(struct inode *inode,
53 struct lmv_foreign_md *lfm)
55 struct ll_sb_info *sbi = ll_i2sbi(inode);
57 if (lfm->lfm_type == LU_FOREIGN_TYPE_SYMLINK) {
59 "%s: inode %p of fid "DFID": Foreign dir of type symlink, faking a symlink\n",
60 sbi->ll_fsname, inode, PFID(ll_inode2fid(inode)));
61 /* change inode_operations to add symlink methods
62 * IOP_NOFOLLOW should not be set for dirs
64 inode->i_op = &ll_foreign_dir_symlink_inode_operations;
67 "%s: inode %p of fid "DFID": Foreign dir of type %ux, nothing special to do\n",
68 sbi->ll_fsname, inode, PFID(ll_inode2fid(inode)),
69 le32_to_cpu(lfm->lfm_type));
73 int ll_manage_foreign(struct inode *inode, struct lustre_md *lmd)
78 /* apply any foreign file/dir policy */
79 if (S_ISREG((inode)->i_mode)) {
80 struct ll_inode_info *lli = ll_i2info(inode);
81 struct cl_object *obj = lli->lli_clob;
83 if (lmd->layout.lb_buf != NULL && lmd->layout.lb_len != 0) {
84 struct lov_foreign_md *lfm = lmd->layout.lb_buf;
86 if (lfm->lfm_magic == LOV_MAGIC_FOREIGN)
87 ll_manage_foreign_file(inode, lfm);
92 struct lov_foreign_md lfm = {
93 .lfm_magic = LOV_MAGIC,
95 struct cl_layout cl = {
96 .cl_buf.lb_buf = &lfm,
97 .cl_buf.lb_len = sizeof(lfm),
102 env = cl_env_get(&refcheck);
104 GOTO(out, rc = PTR_ERR(env));
105 rc = cl_object_layout_get(env, obj, &cl);
106 /* error is likely to be -ERANGE because of the small
107 * buffer we use, only the content is significant here
109 if (rc < 0 && rc != -ERANGE) {
110 cl_env_put(env, &refcheck);
113 if (lfm.lfm_magic == LOV_MAGIC_FOREIGN)
114 ll_manage_foreign_file(inode, &lfm);
115 cl_env_put(env, &refcheck);
117 } else if (S_ISDIR((inode)->i_mode)) {
118 if (lmv_dir_foreign(lmd->lsm_obj)) {
119 ll_manage_foreign_dir(inode, &lmd->lsm_obj->lso_lfm);
121 struct ll_inode_info *lli = ll_i2info(inode);
122 struct lmv_stripe_object *lsm_obj;
124 down_read(&lli->lli_lsm_sem);
125 lsm_obj = lli->lli_lsm_obj;
126 if (lmv_dir_foreign(lsm_obj))
127 ll_manage_foreign_dir(inode, &lsm_obj->lso_lfm);
128 up_read(&lli->lli_lsm_sem);
135 /* dentry must be spliced to inode (dentry->d_inode != NULL) !!! */
136 bool ll_foreign_is_openable(struct dentry *dentry, unsigned int flags)
138 /* check for faked symlink here as they should not be opened (unless
139 * O_NOFOLLOW!) and thus wants ll_atomic_open() to return 1 from
140 * finish_no_open() in order to get follow_link() to be called in both
141 * path_lookupat() and path_openupat().
142 * This will not break regular symlink handling as they have
143 * been treated/filtered upstream.
145 if (d_is_symlink(dentry) && !S_ISLNK(dentry->d_inode->i_mode) &&
146 !(flags & O_NOFOLLOW))
152 static bool should_preserve_foreign_file(struct lov_foreign_md *lfm,
153 struct ll_inode_info *lli, bool unset)
155 /* for now, only avoid foreign fake symlink file removal */
158 if (lfm->lfm_type == LU_FOREIGN_TYPE_SYMLINK) {
159 set_bit(LLIF_FOREIGN_REMOVABLE, &lli->lli_flags);
165 return lfm->lfm_type == LU_FOREIGN_TYPE_SYMLINK &&
166 !test_bit(LLIF_FOREIGN_REMOVABLE, &lli->lli_flags);
169 static bool should_preserve_foreign_dir(struct lmv_foreign_md *lfm,
170 struct ll_inode_info *lli, bool unset)
172 /* for now, only avoid foreign fake symlink dir removal */
175 if (lfm->lfm_type == LU_FOREIGN_TYPE_SYMLINK) {
176 set_bit(LLIF_FOREIGN_REMOVABLE, &lli->lli_flags);
182 return lfm->lfm_type == LU_FOREIGN_TYPE_SYMLINK &&
183 !test_bit(LLIF_FOREIGN_REMOVABLE, &lli->lli_flags);
187 * instead of fetching type from foreign LOV/LMV, we may simply
188 * check (d_is_symlink(dentry) && !S_ISLNK(dentry->d_inode->i_mode))
189 * to identify a fake symlink
191 bool ll_foreign_is_removable(struct dentry *dentry, bool unset)
193 struct inode *inode = dentry->d_inode;
194 struct qstr *name = &dentry->d_name;
195 bool preserve_foreign = false;
202 /* some foreign types may not be allowed to be unlinked in order to
203 * keep references with external objects
205 if (S_ISREG(inode->i_mode)) {
206 struct ll_inode_info *lli = ll_i2info(inode);
207 struct cl_object *obj = lli->lli_clob;
210 struct lov_foreign_md lfm = {
211 .lfm_magic = LOV_MAGIC,
213 struct cl_layout cl = {
214 .cl_buf.lb_buf = &lfm,
215 .cl_buf.lb_len = sizeof(lfm),
220 env = cl_env_get(&refcheck);
222 GOTO(out, rc = PTR_ERR(env));
223 rc = cl_object_layout_get(env, obj, &cl);
224 /* error is likely to be -ERANGE because of the small
225 * buffer we use, only the content is significant here
227 if (rc < 0 && rc != -ERANGE) {
228 cl_env_put(env, &refcheck);
233 if (lfm.lfm_magic == LOV_MAGIC_FOREIGN)
235 should_preserve_foreign_file(&lfm, lli,
237 cl_env_put(env, &refcheck);
238 if (preserve_foreign) {
240 "%s unlink of foreign file (%.*s, "DFID")\n",
241 unset ? "allow" : "prevent",
242 name->len, name->name,
243 PFID(ll_inode2fid(inode)));
248 "unable to check if file (%.*s, "DFID") is foreign...\n",
249 name->len, name->name,
250 PFID(ll_inode2fid(inode)));
251 /* XXX should we prevent removal ?? */
253 } else if (S_ISDIR(inode->i_mode)) {
254 struct ll_inode_info *lli = ll_i2info(inode);
255 struct lmv_stripe_object *lsm_obj;
257 down_read(&lli->lli_lsm_sem);
258 lsm_obj = lli->lli_lsm_obj;
261 "unable to check if dir (%.*s, "DFID") is foreign...\n",
262 name->len, name->name,
263 PFID(ll_inode2fid(inode)));
264 else if (lmv_dir_foreign(lsm_obj))
266 should_preserve_foreign_dir(&lsm_obj->lso_lfm,
268 up_read(&lli->lli_lsm_sem);
269 if (preserve_foreign) {
271 "%s unlink of foreign dir (%.*s, "DFID")\n",
272 unset ? "allow" : "prevent",
273 name->len, name->name,
274 PFID(ll_inode2fid(inode)));