Merge tag 'edac_for_4.14' of git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp
[sfrench/cifs-2.6.git] / drivers / staging / lustre / lustre / obdclass / linkea.c
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
18  * http://www.gnu.org/licenses/gpl-2.0.html
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (c) 2013, 2014, Intel Corporation.
24  * Use is subject to license terms.
25  *
26  * Author: Di Wang <di.wang@intel.com>
27  */
28
29 #include <uapi/linux/lustre/lustre_idl.h>
30 #include <obd.h>
31 #include <lustre_linkea.h>
32
33 int linkea_data_new(struct linkea_data *ldata, struct lu_buf *buf)
34 {
35         ldata->ld_buf = lu_buf_check_and_alloc(buf, PAGE_SIZE);
36         if (!ldata->ld_buf->lb_buf)
37                 return -ENOMEM;
38         ldata->ld_leh = ldata->ld_buf->lb_buf;
39         ldata->ld_leh->leh_magic = LINK_EA_MAGIC;
40         ldata->ld_leh->leh_len = sizeof(struct link_ea_header);
41         ldata->ld_leh->leh_reccount = 0;
42         ldata->ld_leh->leh_overflow_time = 0;
43         ldata->ld_leh->leh_padding = 0;
44         return 0;
45 }
46 EXPORT_SYMBOL(linkea_data_new);
47
48 int linkea_init(struct linkea_data *ldata)
49 {
50         struct link_ea_header *leh;
51
52         LASSERT(ldata->ld_buf);
53         leh = ldata->ld_buf->lb_buf;
54         if (leh->leh_magic == __swab32(LINK_EA_MAGIC)) {
55                 leh->leh_magic = LINK_EA_MAGIC;
56                 leh->leh_reccount = __swab32(leh->leh_reccount);
57                 leh->leh_len = __swab64(leh->leh_len);
58                 leh->leh_overflow_time = __swab32(leh->leh_overflow_time);
59                 leh->leh_padding = __swab32(leh->leh_padding);
60                 /* individual entries are swabbed by linkea_entry_unpack() */
61         }
62
63         if (leh->leh_magic != LINK_EA_MAGIC)
64                 return -EINVAL;
65
66         if (leh->leh_reccount == 0 && leh->leh_overflow_time == 0)
67                 return -ENODATA;
68
69         ldata->ld_leh = leh;
70         return 0;
71 }
72 EXPORT_SYMBOL(linkea_init);
73
74 int linkea_init_with_rec(struct linkea_data *ldata)
75 {
76         int rc;
77
78         rc = linkea_init(ldata);
79         if (!rc && ldata->ld_leh->leh_reccount == 0)
80                 rc = -ENODATA;
81
82         return rc;
83 }
84 EXPORT_SYMBOL(linkea_init_with_rec);
85
86 /**
87  * Pack a link_ea_entry.
88  * All elements are stored as chars to avoid alignment issues.
89  * Numbers are always big-endian
90  * \retval record length
91  */
92 int linkea_entry_pack(struct link_ea_entry *lee, const struct lu_name *lname,
93                       const struct lu_fid *pfid)
94 {
95         struct lu_fid   tmpfid;
96         int             reclen;
97
98         tmpfid = *pfid;
99         if (OBD_FAIL_CHECK(OBD_FAIL_LFSCK_LINKEA_CRASH))
100                 tmpfid.f_ver = ~0;
101         fid_cpu_to_be(&tmpfid, &tmpfid);
102         memcpy(&lee->lee_parent_fid, &tmpfid, sizeof(tmpfid));
103         memcpy(lee->lee_name, lname->ln_name, lname->ln_namelen);
104         reclen = sizeof(struct link_ea_entry) + lname->ln_namelen;
105
106         lee->lee_reclen[0] = (reclen >> 8) & 0xff;
107         lee->lee_reclen[1] = reclen & 0xff;
108         return reclen;
109 }
110 EXPORT_SYMBOL(linkea_entry_pack);
111
112 void linkea_entry_unpack(const struct link_ea_entry *lee, int *reclen,
113                          struct lu_name *lname, struct lu_fid *pfid)
114 {
115         LASSERT(lee);
116
117         *reclen = (lee->lee_reclen[0] << 8) | lee->lee_reclen[1];
118         memcpy(pfid, &lee->lee_parent_fid, sizeof(*pfid));
119         fid_be_to_cpu(pfid, pfid);
120         if (lname) {
121                 lname->ln_name = lee->lee_name;
122                 lname->ln_namelen = *reclen - sizeof(struct link_ea_entry);
123         }
124 }
125 EXPORT_SYMBOL(linkea_entry_unpack);
126
127 /**
128  * Add a record to the end of link ea buf
129  **/
130 int linkea_add_buf(struct linkea_data *ldata, const struct lu_name *lname,
131                    const struct lu_fid *pfid)
132 {
133         struct link_ea_header *leh = ldata->ld_leh;
134         int reclen;
135
136         LASSERT(leh);
137
138         if (!lname || !pfid)
139                 return -EINVAL;
140
141         reclen = lname->ln_namelen + sizeof(struct link_ea_entry);
142         if (unlikely(leh->leh_len + reclen > MAX_LINKEA_SIZE)) {
143                 /*
144                  * Use 32-bits to save the overflow time, although it will
145                  * shrink the ktime_get_real_seconds() returned 64-bits value
146                  * to 32-bits value, it is still quite large and can be used
147                  * for about 140 years. That is enough.
148                  */
149                 leh->leh_overflow_time = ktime_get_real_seconds();
150                 if (unlikely(leh->leh_overflow_time == 0))
151                         leh->leh_overflow_time++;
152
153                 CDEBUG(D_INODE, "No enough space to hold linkea entry '" DFID ": %.*s' at %u\n",
154                        PFID(pfid), lname->ln_namelen,
155                        lname->ln_name, leh->leh_overflow_time);
156                 return 0;
157         }
158
159         if (leh->leh_len + reclen > ldata->ld_buf->lb_len) {
160                 if (lu_buf_check_and_grow(ldata->ld_buf,
161                                           leh->leh_len + reclen) < 0)
162                         return -ENOMEM;
163
164                 leh = ldata->ld_leh = ldata->ld_buf->lb_buf;
165         }
166
167         ldata->ld_lee = ldata->ld_buf->lb_buf + leh->leh_len;
168         ldata->ld_reclen = linkea_entry_pack(ldata->ld_lee, lname, pfid);
169         leh->leh_len += ldata->ld_reclen;
170         leh->leh_reccount++;
171         CDEBUG(D_INODE, "New link_ea name '" DFID ":%.*s' is added\n",
172                PFID(pfid), lname->ln_namelen, lname->ln_name);
173         return 0;
174 }
175 EXPORT_SYMBOL(linkea_add_buf);
176
177 /** Del the current record from the link ea buf */
178 void linkea_del_buf(struct linkea_data *ldata, const struct lu_name *lname)
179 {
180         LASSERT(ldata->ld_leh && ldata->ld_lee);
181         LASSERT(ldata->ld_leh->leh_reccount > 0);
182
183         ldata->ld_leh->leh_reccount--;
184         ldata->ld_leh->leh_len -= ldata->ld_reclen;
185         memmove(ldata->ld_lee, (char *)ldata->ld_lee + ldata->ld_reclen,
186                 (char *)ldata->ld_leh + ldata->ld_leh->leh_len -
187                 (char *)ldata->ld_lee);
188         CDEBUG(D_INODE, "Old link_ea name '%.*s' is removed\n",
189                lname->ln_namelen, lname->ln_name);
190
191         if ((char *)ldata->ld_lee >= ((char *)ldata->ld_leh +
192                                       ldata->ld_leh->leh_len))
193                 ldata->ld_lee = NULL;
194 }
195 EXPORT_SYMBOL(linkea_del_buf);
196
197 /**
198  * Check if such a link exists in linkEA.
199  *
200  * \param ldata link data the search to be done on
201  * \param lname name in the parent's directory entry pointing to this object
202  * \param pfid parent fid the link to be found for
203  *
204  * \retval   0 success
205  * \retval -ENOENT link does not exist
206  * \retval -ve on error
207  */
208 int linkea_links_find(struct linkea_data *ldata, const struct lu_name *lname,
209                       const struct lu_fid  *pfid)
210 {
211         struct lu_name tmpname;
212         struct lu_fid  tmpfid;
213         int count;
214
215         LASSERT(ldata->ld_leh);
216
217         /* link #0, if leh_reccount == 0 we skip the loop and return -ENOENT */
218         if (likely(ldata->ld_leh->leh_reccount > 0))
219                 ldata->ld_lee = (struct link_ea_entry *)(ldata->ld_leh + 1);
220
221         for (count = 0; count < ldata->ld_leh->leh_reccount; count++) {
222                 linkea_entry_unpack(ldata->ld_lee, &ldata->ld_reclen,
223                                     &tmpname, &tmpfid);
224                 if (tmpname.ln_namelen == lname->ln_namelen &&
225                     lu_fid_eq(&tmpfid, pfid) &&
226                     (strncmp(tmpname.ln_name, lname->ln_name,
227                              tmpname.ln_namelen) == 0))
228                         break;
229                 ldata->ld_lee = (struct link_ea_entry *)((char *)ldata->ld_lee +
230                                                          ldata->ld_reclen);
231         }
232
233         if (count == ldata->ld_leh->leh_reccount) {
234                 CDEBUG(D_INODE, "Old link_ea name '%.*s' not found\n",
235                        lname->ln_namelen, lname->ln_name);
236                 ldata->ld_lee = NULL;
237                 ldata->ld_reclen = 0;
238                 return -ENOENT;
239         }
240         return 0;
241 }
242 EXPORT_SYMBOL(linkea_links_find);