Commit | Line | Data |
---|---|---|
d7e09d03 PT |
1 | /* |
2 | * GPL HEADER START | |
3 | * | |
4 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
5 | * | |
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. | |
9 | * | |
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). | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * version 2 along with this program; If not, see | |
6a5b99a4 | 18 | * http://www.gnu.org/licenses/gpl-2.0.html |
d7e09d03 | 19 | * |
d7e09d03 PT |
20 | * GPL HEADER END |
21 | */ | |
22 | /* | |
23 | * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. | |
24 | * Use is subject to license terms. | |
25 | * | |
26 | * Copyright (c) 2011, 2012, Intel Corporation. | |
27 | */ | |
28 | /* | |
29 | * This file is part of Lustre, http://www.lustre.org/ | |
30 | * Lustre is a trademark of Sun Microsystems, Inc. | |
31 | */ | |
32 | ||
33 | #include <linux/fs.h> | |
34 | #include <linux/mm.h> | |
35 | #include <linux/stat.h> | |
d7e09d03 PT |
36 | #define DEBUG_SUBSYSTEM S_LLITE |
37 | ||
67a235f5 | 38 | #include "../include/lustre_lite.h" |
d7e09d03 PT |
39 | #include "llite_internal.h" |
40 | ||
41 | static int ll_readlink_internal(struct inode *inode, | |
42 | struct ptlrpc_request **request, char **symname) | |
43 | { | |
44 | struct ll_inode_info *lli = ll_i2info(inode); | |
45 | struct ll_sb_info *sbi = ll_i2sbi(inode); | |
46 | int rc, symlen = i_size_read(inode) + 1; | |
47 | struct mdt_body *body; | |
48 | struct md_op_data *op_data; | |
d7e09d03 PT |
49 | |
50 | *request = NULL; | |
51 | ||
52 | if (lli->lli_symlink_name) { | |
53 | int print_limit = min_t(int, PAGE_SIZE - 128, symlen); | |
54 | ||
55 | *symname = lli->lli_symlink_name; | |
56 | /* If the total CDEBUG() size is larger than a page, it | |
57 | * will print a warning to the console, avoid this by | |
c0894c6c OD |
58 | * printing just the last part of the symlink. |
59 | */ | |
d7e09d03 PT |
60 | CDEBUG(D_INODE, "using cached symlink %s%.*s, len = %d\n", |
61 | print_limit < symlen ? "..." : "", print_limit, | |
62 | (*symname) + symlen - print_limit, symlen); | |
0a3bdb00 | 63 | return 0; |
d7e09d03 PT |
64 | } |
65 | ||
66 | op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL, 0, symlen, | |
67 | LUSTRE_OPC_ANY, NULL); | |
68 | if (IS_ERR(op_data)) | |
0a3bdb00 | 69 | return PTR_ERR(op_data); |
d7e09d03 PT |
70 | |
71 | op_data->op_valid = OBD_MD_LINKNAME; | |
72 | rc = md_getattr(sbi->ll_md_exp, op_data, request); | |
73 | ll_finish_md_op_data(op_data); | |
74 | if (rc) { | |
75 | if (rc != -ENOENT) | |
97a075cd JN |
76 | CERROR("%s: inode "DFID": rc = %d\n", |
77 | ll_get_fsname(inode->i_sb, NULL, 0), | |
78 | PFID(ll_inode2fid(inode)), rc); | |
34e1f2bb | 79 | goto failed; |
d7e09d03 PT |
80 | } |
81 | ||
82 | body = req_capsule_server_get(&(*request)->rq_pill, &RMF_MDT_BODY); | |
2e1b5b8b | 83 | if ((body->mbo_valid & OBD_MD_LINKNAME) == 0) { |
d7e09d03 | 84 | CERROR("OBD_MD_LINKNAME not set on reply\n"); |
34e1f2bb JL |
85 | rc = -EPROTO; |
86 | goto failed; | |
d7e09d03 PT |
87 | } |
88 | ||
89 | LASSERT(symlen != 0); | |
2e1b5b8b | 90 | if (body->mbo_eadatasize != symlen) { |
97a075cd JN |
91 | CERROR("%s: inode "DFID": symlink length %d not expected %d\n", |
92 | ll_get_fsname(inode->i_sb, NULL, 0), | |
2e1b5b8b | 93 | PFID(ll_inode2fid(inode)), body->mbo_eadatasize - 1, |
97a075cd | 94 | symlen - 1); |
34e1f2bb JL |
95 | rc = -EPROTO; |
96 | goto failed; | |
d7e09d03 PT |
97 | } |
98 | ||
99 | *symname = req_capsule_server_get(&(*request)->rq_pill, &RMF_MDT_MD); | |
6e16818b | 100 | if (!*symname || |
d7e09d03 PT |
101 | strnlen(*symname, symlen) != symlen - 1) { |
102 | /* not full/NULL terminated */ | |
2d00bd17 JP |
103 | CERROR("inode %lu: symlink not NULL terminated string of length %d\n", |
104 | inode->i_ino, symlen - 1); | |
34e1f2bb JL |
105 | rc = -EPROTO; |
106 | goto failed; | |
d7e09d03 PT |
107 | } |
108 | ||
496a51bd | 109 | lli->lli_symlink_name = kzalloc(symlen, GFP_NOFS); |
d7e09d03 PT |
110 | /* do not return an error if we cannot cache the symlink locally */ |
111 | if (lli->lli_symlink_name) { | |
112 | memcpy(lli->lli_symlink_name, *symname, symlen); | |
113 | *symname = lli->lli_symlink_name; | |
114 | } | |
0a3bdb00 | 115 | return 0; |
d7e09d03 PT |
116 | |
117 | failed: | |
0a3bdb00 | 118 | return rc; |
d7e09d03 PT |
119 | } |
120 | ||
fceef393 AV |
121 | static void ll_put_link(void *p) |
122 | { | |
123 | ptlrpc_req_finished(p); | |
124 | } | |
125 | ||
6b255391 | 126 | static const char *ll_get_link(struct dentry *dentry, |
fceef393 AV |
127 | struct inode *inode, |
128 | struct delayed_call *done) | |
d7e09d03 | 129 | { |
d7e09d03 PT |
130 | struct ptlrpc_request *request = NULL; |
131 | int rc; | |
1da4f83c | 132 | char *symname = NULL; |
6b255391 AV |
133 | if (!dentry) |
134 | return ERR_PTR(-ECHILD); | |
d7e09d03 PT |
135 | |
136 | CDEBUG(D_VFSTRACE, "VFS Op\n"); | |
44163f30 AV |
137 | ll_inode_size_lock(inode); |
138 | rc = ll_readlink_internal(inode, &request, &symname); | |
139 | ll_inode_size_unlock(inode); | |
d7e09d03 PT |
140 | if (rc) { |
141 | ptlrpc_req_finished(request); | |
680baacb | 142 | return ERR_PTR(rc); |
d7e09d03 PT |
143 | } |
144 | ||
d7e09d03 | 145 | /* symname may contain a pointer to the request message buffer, |
fceef393 | 146 | * we delay request releasing then. |
d7e09d03 | 147 | */ |
fceef393 | 148 | set_delayed_call(done, ll_put_link, request); |
680baacb | 149 | return symname; |
d7e09d03 PT |
150 | } |
151 | ||
42a561e5 | 152 | const struct inode_operations ll_fast_symlink_inode_operations = { |
4efcc9ff | 153 | .readlink = generic_readlink, |
d7e09d03 | 154 | .setattr = ll_setattr, |
6b255391 | 155 | .get_link = ll_get_link, |
d7e09d03 PT |
156 | .getattr = ll_getattr, |
157 | .permission = ll_inode_permission, | |
2c563880 JS |
158 | .setxattr = generic_setxattr, |
159 | .getxattr = generic_getxattr, | |
d7e09d03 | 160 | .listxattr = ll_listxattr, |
2c563880 | 161 | .removexattr = generic_removexattr, |
d7e09d03 | 162 | }; |