Whamcloud - gitweb
LU-5319 tests: testcases for multiple modify RPCs feature
[fs/lustre-release.git] / 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, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 021110-1307, USA
20  *
21  * GPL HEADER END
22  */
23 /*
24  * Copyright (c) 2013, 2014, Intel Corporation.
25  * Use is subject to license terms.
26  *
27  * Author: Di Wang <di.wang@intel.com>
28  */
29
30 #include <lustre/lustre_idl.h>
31 #include <obd.h>
32 #include <lustre_linkea.h>
33
34 int linkea_data_new(struct linkea_data *ldata, struct lu_buf *buf)
35 {
36         ldata->ld_buf = lu_buf_check_and_alloc(buf, PAGE_CACHE_SIZE);
37         if (ldata->ld_buf->lb_buf == NULL)
38                 return -ENOMEM;
39         ldata->ld_leh = ldata->ld_buf->lb_buf;
40         ldata->ld_leh->leh_magic = LINK_EA_MAGIC;
41         ldata->ld_leh->leh_len = sizeof(struct link_ea_header);
42         ldata->ld_leh->leh_reccount = 0;
43         return 0;
44 }
45 EXPORT_SYMBOL(linkea_data_new);
46
47 int linkea_init(struct linkea_data *ldata)
48 {
49         struct link_ea_header *leh;
50
51         LASSERT(ldata->ld_buf != NULL);
52         leh = ldata->ld_buf->lb_buf;
53         if (leh->leh_magic == __swab32(LINK_EA_MAGIC)) {
54                 leh->leh_magic = LINK_EA_MAGIC;
55                 leh->leh_reccount = __swab32(leh->leh_reccount);
56                 leh->leh_len = __swab64(leh->leh_len);
57                 /* entries are swabbed by linkea_entry_unpack */
58         }
59         if (leh->leh_magic != LINK_EA_MAGIC)
60                 return -EINVAL;
61         if (leh->leh_reccount == 0)
62                 return -ENODATA;
63
64         ldata->ld_leh = leh;
65         return 0;
66 }
67 EXPORT_SYMBOL(linkea_init);
68
69 /**
70  * Pack a link_ea_entry.
71  * All elements are stored as chars to avoid alignment issues.
72  * Numbers are always big-endian
73  * \retval record length
74  */
75 int linkea_entry_pack(struct link_ea_entry *lee, const struct lu_name *lname,
76                       const struct lu_fid *pfid)
77 {
78         struct lu_fid   tmpfid;
79         int             reclen;
80
81         tmpfid = *pfid;
82         if (OBD_FAIL_CHECK(OBD_FAIL_LFSCK_MUL_REF))
83                 tmpfid.f_oid--;
84         if (OBD_FAIL_CHECK(OBD_FAIL_LFSCK_LINKEA_CRASH))
85                 tmpfid.f_ver = ~0;
86         fid_cpu_to_be(&tmpfid, &tmpfid);
87         memcpy(&lee->lee_parent_fid, &tmpfid, sizeof(tmpfid));
88         memcpy(lee->lee_name, lname->ln_name, lname->ln_namelen);
89         reclen = sizeof(struct link_ea_entry) + lname->ln_namelen;
90
91         lee->lee_reclen[0] = (reclen >> 8) & 0xff;
92         lee->lee_reclen[1] = reclen & 0xff;
93         return reclen;
94 }
95 EXPORT_SYMBOL(linkea_entry_pack);
96
97 void linkea_entry_unpack(const struct link_ea_entry *lee, int *reclen,
98                          struct lu_name *lname, struct lu_fid *pfid)
99 {
100         *reclen = (lee->lee_reclen[0] << 8) | lee->lee_reclen[1];
101         memcpy(pfid, &lee->lee_parent_fid, sizeof(*pfid));
102         fid_be_to_cpu(pfid, pfid);
103         if (lname != NULL) {
104                 lname->ln_name = lee->lee_name;
105                 lname->ln_namelen = *reclen - sizeof(struct link_ea_entry);
106         }
107 }
108 EXPORT_SYMBOL(linkea_entry_unpack);
109
110 /**
111  * Add a record to the end of link ea buf
112  **/
113 int linkea_add_buf(struct linkea_data *ldata, const struct lu_name *lname,
114                    const struct lu_fid *pfid)
115 {
116         LASSERT(ldata->ld_leh != NULL);
117
118         if (lname == NULL || pfid == NULL)
119                 return -EINVAL;
120
121         ldata->ld_reclen = lname->ln_namelen + sizeof(struct link_ea_entry);
122         if (ldata->ld_leh->leh_len + ldata->ld_reclen >
123             ldata->ld_buf->lb_len) {
124                 if (lu_buf_check_and_grow(ldata->ld_buf,
125                                           ldata->ld_leh->leh_len +
126                                           ldata->ld_reclen) < 0)
127                         return -ENOMEM;
128         }
129
130         ldata->ld_leh = ldata->ld_buf->lb_buf;
131         ldata->ld_lee = ldata->ld_buf->lb_buf + ldata->ld_leh->leh_len;
132         ldata->ld_reclen = linkea_entry_pack(ldata->ld_lee, lname, pfid);
133         ldata->ld_leh->leh_len += ldata->ld_reclen;
134         ldata->ld_leh->leh_reccount++;
135         CDEBUG(D_INODE, "New link_ea name '%.*s' is added\n",
136                lname->ln_namelen, lname->ln_name);
137         return 0;
138 }
139 EXPORT_SYMBOL(linkea_add_buf);
140
141 /** Del the current record from the link ea buf */
142 void linkea_del_buf(struct linkea_data *ldata, const struct lu_name *lname)
143 {
144         LASSERT(ldata->ld_leh != NULL && ldata->ld_lee != NULL);
145
146         ldata->ld_leh->leh_reccount--;
147         ldata->ld_leh->leh_len -= ldata->ld_reclen;
148         memmove(ldata->ld_lee, (char *)ldata->ld_lee + ldata->ld_reclen,
149                 (char *)ldata->ld_leh + ldata->ld_leh->leh_len -
150                 (char *)ldata->ld_lee);
151         CDEBUG(D_INODE, "Old link_ea name '%.*s' is removed\n",
152                lname->ln_namelen, lname->ln_name);
153
154         if ((char *)ldata->ld_lee >= ((char *)ldata->ld_leh +
155                                       ldata->ld_leh->leh_len))
156                 ldata->ld_lee = NULL;
157 }
158 EXPORT_SYMBOL(linkea_del_buf);
159
160 /**
161  * Check if such a link exists in linkEA.
162  *
163  * \param ldata link data the search to be done on
164  * \param lname name in the parent's directory entry pointing to this object
165  * \param pfid parent fid the link to be found for
166  *
167  * \retval   0 success
168  * \retval -ENOENT link does not exist
169  * \retval -ve on error
170  */
171 int linkea_links_find(struct linkea_data *ldata, const struct lu_name *lname,
172                       const struct lu_fid  *pfid)
173 {
174         struct lu_name tmpname;
175         struct lu_fid  tmpfid;
176         int count;
177
178         LASSERT(ldata->ld_leh != NULL);
179
180         /* link #0 */
181         ldata->ld_lee = (struct link_ea_entry *)(ldata->ld_leh + 1);
182
183         for (count = 0; count < ldata->ld_leh->leh_reccount; count++) {
184                 linkea_entry_unpack(ldata->ld_lee, &ldata->ld_reclen,
185                                     &tmpname, &tmpfid);
186                 if (tmpname.ln_namelen == lname->ln_namelen &&
187                     lu_fid_eq(&tmpfid, pfid) &&
188                     (strncmp(tmpname.ln_name, lname->ln_name,
189                              tmpname.ln_namelen) == 0))
190                         break;
191                 ldata->ld_lee = (struct link_ea_entry *)((char *)ldata->ld_lee +
192                                                          ldata->ld_reclen);
193         }
194
195         if (count == ldata->ld_leh->leh_reccount) {
196                 CDEBUG(D_INODE, "Old link_ea name '%.*s' not found\n",
197                        lname->ln_namelen, lname->ln_name);
198                 ldata->ld_lee = NULL;
199                 ldata->ld_reclen = 0;
200                 return -ENOENT;
201         }
202         return 0;
203 }
204 EXPORT_SYMBOL(linkea_links_find);