Merge tag 'platform-drivers-x86-v4.9-2' of git://git.infradead.org/users/dvhart/linux...
[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 "../include/lustre/lustre_idl.h"
30 #include "../include/obd.h"
31 #include "../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         return 0;
43 }
44 EXPORT_SYMBOL(linkea_data_new);
45
46 int linkea_init(struct linkea_data *ldata)
47 {
48         struct link_ea_header *leh;
49
50         LASSERT(ldata->ld_buf);
51         leh = ldata->ld_buf->lb_buf;
52         if (leh->leh_magic == __swab32(LINK_EA_MAGIC)) {
53                 leh->leh_magic = LINK_EA_MAGIC;
54                 leh->leh_reccount = __swab32(leh->leh_reccount);
55                 leh->leh_len = __swab64(leh->leh_len);
56                 /* entries are swabbed by linkea_entry_unpack */
57         }
58         if (leh->leh_magic != LINK_EA_MAGIC)
59                 return -EINVAL;
60         if (leh->leh_reccount == 0)
61                 return -ENODATA;
62
63         ldata->ld_leh = leh;
64         return 0;
65 }
66 EXPORT_SYMBOL(linkea_init);
67
68 /**
69  * Pack a link_ea_entry.
70  * All elements are stored as chars to avoid alignment issues.
71  * Numbers are always big-endian
72  * \retval record length
73  */
74 int linkea_entry_pack(struct link_ea_entry *lee, const struct lu_name *lname,
75                       const struct lu_fid *pfid)
76 {
77         struct lu_fid   tmpfid;
78         int             reclen;
79
80         tmpfid = *pfid;
81         if (OBD_FAIL_CHECK(OBD_FAIL_LFSCK_LINKEA_CRASH))
82                 tmpfid.f_ver = ~0;
83         fid_cpu_to_be(&tmpfid, &tmpfid);
84         memcpy(&lee->lee_parent_fid, &tmpfid, sizeof(tmpfid));
85         memcpy(lee->lee_name, lname->ln_name, lname->ln_namelen);
86         reclen = sizeof(struct link_ea_entry) + lname->ln_namelen;
87
88         lee->lee_reclen[0] = (reclen >> 8) & 0xff;
89         lee->lee_reclen[1] = reclen & 0xff;
90         return reclen;
91 }
92 EXPORT_SYMBOL(linkea_entry_pack);
93
94 void linkea_entry_unpack(const struct link_ea_entry *lee, int *reclen,
95                          struct lu_name *lname, struct lu_fid *pfid)
96 {
97         *reclen = (lee->lee_reclen[0] << 8) | lee->lee_reclen[1];
98         memcpy(pfid, &lee->lee_parent_fid, sizeof(*pfid));
99         fid_be_to_cpu(pfid, pfid);
100         if (lname) {
101                 lname->ln_name = lee->lee_name;
102                 lname->ln_namelen = *reclen - sizeof(struct link_ea_entry);
103         }
104 }
105 EXPORT_SYMBOL(linkea_entry_unpack);
106
107 /**
108  * Add a record to the end of link ea buf
109  **/
110 int linkea_add_buf(struct linkea_data *ldata, const struct lu_name *lname,
111                    const struct lu_fid *pfid)
112 {
113         LASSERT(ldata->ld_leh);
114
115         if (!lname || !pfid)
116                 return -EINVAL;
117
118         ldata->ld_reclen = lname->ln_namelen + sizeof(struct link_ea_entry);
119         if (ldata->ld_leh->leh_len + ldata->ld_reclen >
120             ldata->ld_buf->lb_len) {
121                 if (lu_buf_check_and_grow(ldata->ld_buf,
122                                           ldata->ld_leh->leh_len +
123                                           ldata->ld_reclen) < 0)
124                         return -ENOMEM;
125         }
126
127         ldata->ld_leh = ldata->ld_buf->lb_buf;
128         ldata->ld_lee = ldata->ld_buf->lb_buf + ldata->ld_leh->leh_len;
129         ldata->ld_reclen = linkea_entry_pack(ldata->ld_lee, lname, pfid);
130         ldata->ld_leh->leh_len += ldata->ld_reclen;
131         ldata->ld_leh->leh_reccount++;
132         CDEBUG(D_INODE, "New link_ea name '" DFID ":%.*s' is added\n",
133                PFID(pfid), lname->ln_namelen, lname->ln_name);
134         return 0;
135 }
136 EXPORT_SYMBOL(linkea_add_buf);
137
138 /** Del the current record from the link ea buf */
139 void linkea_del_buf(struct linkea_data *ldata, const struct lu_name *lname)
140 {
141         LASSERT(ldata->ld_leh && ldata->ld_lee);
142
143         ldata->ld_leh->leh_reccount--;
144         ldata->ld_leh->leh_len -= ldata->ld_reclen;
145         memmove(ldata->ld_lee, (char *)ldata->ld_lee + ldata->ld_reclen,
146                 (char *)ldata->ld_leh + ldata->ld_leh->leh_len -
147                 (char *)ldata->ld_lee);
148         CDEBUG(D_INODE, "Old link_ea name '%.*s' is removed\n",
149                lname->ln_namelen, lname->ln_name);
150
151         if ((char *)ldata->ld_lee >= ((char *)ldata->ld_leh +
152                                       ldata->ld_leh->leh_len))
153                 ldata->ld_lee = NULL;
154 }
155 EXPORT_SYMBOL(linkea_del_buf);
156
157 /**
158  * Check if such a link exists in linkEA.
159  *
160  * \param ldata link data the search to be done on
161  * \param lname name in the parent's directory entry pointing to this object
162  * \param pfid parent fid the link to be found for
163  *
164  * \retval   0 success
165  * \retval -ENOENT link does not exist
166  * \retval -ve on error
167  */
168 int linkea_links_find(struct linkea_data *ldata, const struct lu_name *lname,
169                       const struct lu_fid  *pfid)
170 {
171         struct lu_name tmpname;
172         struct lu_fid  tmpfid;
173         int count;
174
175         LASSERT(ldata->ld_leh);
176
177         /* link #0 */
178         ldata->ld_lee = (struct link_ea_entry *)(ldata->ld_leh + 1);
179
180         for (count = 0; count < ldata->ld_leh->leh_reccount; count++) {
181                 linkea_entry_unpack(ldata->ld_lee, &ldata->ld_reclen,
182                                     &tmpname, &tmpfid);
183                 if (tmpname.ln_namelen == lname->ln_namelen &&
184                     lu_fid_eq(&tmpfid, pfid) &&
185                     (strncmp(tmpname.ln_name, lname->ln_name,
186                              tmpname.ln_namelen) == 0))
187                         break;
188                 ldata->ld_lee = (struct link_ea_entry *)((char *)ldata->ld_lee +
189                                                          ldata->ld_reclen);
190         }
191
192         if (count == ldata->ld_leh->leh_reccount) {
193                 CDEBUG(D_INODE, "Old link_ea name '%.*s' not found\n",
194                        lname->ln_namelen, lname->ln_name);
195                 ldata->ld_lee = NULL;
196                 ldata->ld_reclen = 0;
197                 return -ENOENT;
198         }
199         return 0;
200 }
201 EXPORT_SYMBOL(linkea_links_find);