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 (lmd->lfm != NULL &&
119 lmd->lfm->lfm_magic == LMV_MAGIC_FOREIGN) {
120 ll_manage_foreign_dir(inode, lmd->lfm);
122 struct ll_inode_info *lli = ll_i2info(inode);
123 struct lmv_foreign_md *lfm;
125 down_read(&lli->lli_lsm_sem);
126 lfm = (struct lmv_foreign_md *)(lli->lli_lsm_md);
127 if (lfm && lfm->lfm_magic == LMV_MAGIC_FOREIGN)
128 ll_manage_foreign_dir(inode, lfm);
129 up_read(&lli->lli_lsm_sem);
136 /* dentry must be spliced to inode (dentry->d_inode != NULL) !!! */
137 bool ll_foreign_is_openable(struct dentry *dentry, unsigned int flags)
139 /* check for faked symlink here as they should not be opened (unless
140 * O_NOFOLLOW!) and thus wants ll_atomic_open() to return 1 from
141 * finish_no_open() in order to get follow_link() to be called in both
142 * path_lookupat() and path_openupat().
143 * This will not break regular symlink handling as they have
144 * been treated/filtered upstream.
146 if (d_is_symlink(dentry) && !S_ISLNK(dentry->d_inode->i_mode) &&
147 !(flags & O_NOFOLLOW))
153 static bool should_preserve_foreign_file(struct lov_foreign_md *lfm,
154 struct ll_inode_info *lli, bool unset)
156 /* for now, only avoid foreign fake symlink file removal */
159 if (lfm->lfm_type == LU_FOREIGN_TYPE_SYMLINK) {
160 set_bit(LLIF_FOREIGN_REMOVABLE, &lli->lli_flags);
166 return lfm->lfm_type == LU_FOREIGN_TYPE_SYMLINK &&
167 !test_bit(LLIF_FOREIGN_REMOVABLE, &lli->lli_flags);
170 static bool should_preserve_foreign_dir(struct lmv_foreign_md *lfm,
171 struct ll_inode_info *lli, bool unset)
173 /* for now, only avoid foreign fake symlink dir removal */
176 if (lfm->lfm_type == LU_FOREIGN_TYPE_SYMLINK) {
177 set_bit(LLIF_FOREIGN_REMOVABLE, &lli->lli_flags);
183 return lfm->lfm_type == LU_FOREIGN_TYPE_SYMLINK &&
184 !test_bit(LLIF_FOREIGN_REMOVABLE, &lli->lli_flags);
188 * instead of fetching type from foreign LOV/LMV, we may simply
189 * check (d_is_symlink(dentry) && !S_ISLNK(dentry->d_inode->i_mode))
190 * to identify a fake symlink
192 bool ll_foreign_is_removable(struct dentry *dentry, bool unset)
194 struct inode *inode = dentry->d_inode;
195 struct qstr *name = &dentry->d_name;
196 bool preserve_foreign = false;
203 /* some foreign types may not be allowed to be unlinked in order to
204 * keep references with external objects
206 if (S_ISREG(inode->i_mode)) {
207 struct ll_inode_info *lli = ll_i2info(inode);
208 struct cl_object *obj = lli->lli_clob;
211 struct lov_foreign_md lfm = {
212 .lfm_magic = LOV_MAGIC,
214 struct cl_layout cl = {
215 .cl_buf.lb_buf = &lfm,
216 .cl_buf.lb_len = sizeof(lfm),
221 env = cl_env_get(&refcheck);
223 GOTO(out, rc = PTR_ERR(env));
224 rc = cl_object_layout_get(env, obj, &cl);
225 /* error is likely to be -ERANGE because of the small
226 * buffer we use, only the content is significant here
228 if (rc < 0 && rc != -ERANGE) {
229 cl_env_put(env, &refcheck);
234 if (lfm.lfm_magic == LOV_MAGIC_FOREIGN)
236 should_preserve_foreign_file(&lfm, lli,
238 cl_env_put(env, &refcheck);
239 if (preserve_foreign) {
241 "%s unlink of foreign file (%.*s, "DFID")\n",
242 unset ? "allow" : "prevent",
243 name->len, name->name,
244 PFID(ll_inode2fid(inode)));
249 "unable to check if file (%.*s, "DFID") is foreign...\n",
250 name->len, name->name,
251 PFID(ll_inode2fid(inode)));
252 /* XXX should we prevent removal ?? */
254 } else if (S_ISDIR(inode->i_mode)) {
255 struct ll_inode_info *lli = ll_i2info(inode);
256 struct lmv_foreign_md *lfm;
258 down_read(&lli->lli_lsm_sem);
259 lfm = (struct lmv_foreign_md *)(lli->lli_lsm_md);
262 "unable to check if dir (%.*s, "DFID") is foreign...\n",
263 name->len, name->name,
264 PFID(ll_inode2fid(inode)));
265 else if (lfm->lfm_magic == LMV_MAGIC_FOREIGN)
266 preserve_foreign = should_preserve_foreign_dir(lfm, lli,
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)));