2 * Copyright (c) 2010-2012 Semihalf
3 * Copyright (c) 2008, 2009 Reinoud Zandijk
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 * From: NetBSD: nilfs_subr.c,v 1.4 2009/07/29 17:06:57 reinoud
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/namei.h>
35 #include <sys/kernel.h>
40 #include <sys/mount.h>
41 #include <sys/vnode.h>
42 #include <sys/signalvar.h>
43 #include <sys/malloc.h>
44 #include <sys/dirent.h>
45 #include <sys/lockf.h>
48 #include <vm/vm_extern.h>
50 #include "nandfs_mount.h"
52 #include "nandfs_subr.h"
55 nandfs_add_dirent(struct vnode *dvp, uint64_t ino, char *nameptr, long namelen,
58 struct nandfs_node *dir_node = VTON(dvp);
59 struct nandfs_dir_entry *dirent, *pdirent;
60 uint32_t blocksize = dir_node->nn_nandfsdev->nd_blocksize;
61 uint64_t filesize = dir_node->nn_inode.i_size;
62 uint64_t inode_blks = dir_node->nn_inode.i_blocks;
71 error = nandfs_bread(dir_node, inode_blks - 1, NOCRED, 0, &bp);
79 while (off < blocksize) {
80 pdirent = (struct nandfs_dir_entry *) (pos + off);
81 if (!pdirent->rec_len) {
85 off += pdirent->rec_len;
89 rest = pdirent->rec_len -
90 NANDFS_DIR_REC_LEN(pdirent->name_len);
94 if (rest < NANDFS_DIR_REC_LEN(namelen)) {
95 /* Do not update pdirent as new block is created */
98 /* Set to NULL to create new */
104 /* If no bp found create new */
106 error = nandfs_bcreate(dir_node, inode_blks, NOCRED, 0, &bp);
113 /* Modify pdirent if exists */
115 DPRINTF(LOOKUP, ("modify pdirent %p\n", pdirent));
117 off -= pdirent->rec_len;
119 NANDFS_DIR_REC_LEN(pdirent->name_len);
120 off += pdirent->rec_len;
123 /* Create new dirent */
124 dirent = (struct nandfs_dir_entry *) (pos + off);
125 dirent->rec_len = blocksize - off;
127 dirent->name_len = namelen;
128 memset(dirent->name, 0, NANDFS_DIR_NAME_LEN(namelen));
129 memcpy(dirent->name, nameptr, namelen);
130 dirent->file_type = type;
132 filesize += NANDFS_DIR_REC_LEN(dirent->name_len);
134 DPRINTF(LOOKUP, ("create dir_entry '%.*s' at %p with size %x "
135 "new filesize: %jx\n",
136 (int)namelen, dirent->name, dirent, dirent->rec_len,
137 (uintmax_t)filesize));
139 error = nandfs_dirty_buf(bp, 0);
143 dir_node->nn_inode.i_size = filesize;
144 dir_node->nn_flags |= IN_CHANGE | IN_UPDATE;
145 vnode_pager_setsize(dvp, filesize);
151 nandfs_remove_dirent(struct vnode *dvp, struct nandfs_node *node,
152 struct componentname *cnp)
154 struct nandfs_node *dir_node;
155 struct nandfs_dir_entry *dirent, *pdirent;
157 uint64_t filesize, blocknr, ino, offset;
158 uint32_t blocksize, limit, off;
163 dir_node = VTON(dvp);
164 filesize = dir_node->nn_inode.i_size;
169 offset = node->nn_diroff;
172 offset = dir_node->nn_diroff;
173 ino = NANDFS_WHT_INO;
176 dirent = pdirent = NULL;
177 blocksize = dir_node->nn_nandfsdev->nd_blocksize;
178 blocknr = offset / blocksize;
180 DPRINTF(LOOKUP, ("rm direntry dvp %p node %p ino %#jx at off %#jx\n",
181 dvp, node, (uintmax_t)ino, (uintmax_t)offset));
183 error = nandfs_bread(dir_node, blocknr, NOCRED, 0, &bp);
192 limit = offset % blocksize;
193 pdirent = (struct nandfs_dir_entry *) bp->b_data;
194 while (off <= limit) {
195 dirent = (struct nandfs_dir_entry *) (pos + off);
197 if ((off == limit) &&
198 (dirent->inode == ino)) {
202 if (dirent->inode != 0)
204 off += dirent->rec_len;
208 nandfs_error("cannot find entry to remove");
213 ("rm dirent ino %#jx at %#x with size %#x\n",
214 (uintmax_t)dirent->inode, off, dirent->rec_len));
216 newsize = (uintptr_t)dirent - (uintptr_t)pdirent;
217 newsize += dirent->rec_len;
218 pdirent->rec_len = newsize;
220 error = nandfs_dirty_buf(bp, 0);
224 dir_node->nn_flags |= IN_CHANGE | IN_UPDATE;
225 /* If last one modify filesize */
226 if ((offset + NANDFS_DIR_REC_LEN(dirent->name_len)) == filesize) {
227 filesize = blocknr * blocksize +
228 ((uintptr_t)pdirent - (uintptr_t)pos) +
229 NANDFS_DIR_REC_LEN(pdirent->name_len);
230 dir_node->nn_inode.i_size = filesize;
237 nandfs_update_parent_dir(struct vnode *dvp, uint64_t newparent)
239 struct nandfs_dir_entry *dirent;
240 struct nandfs_node *dir_node;
244 dir_node = VTON(dvp);
245 error = nandfs_bread(dir_node, 0, NOCRED, 0, &bp);
250 dirent = (struct nandfs_dir_entry *)bp->b_data;
251 dirent->inode = newparent;
252 error = nandfs_dirty_buf(bp, 0);
260 nandfs_update_dirent(struct vnode *dvp, struct nandfs_node *fnode,
261 struct nandfs_node *tnode)
263 struct nandfs_node *dir_node;
264 struct nandfs_dir_entry *dirent;
266 uint64_t file_size, blocknr;
267 uint32_t blocksize, off;
271 dir_node = VTON(dvp);
272 file_size = dir_node->nn_inode.i_size;
277 ("chg direntry dvp %p ino %#jx to in %#jx at off %#jx\n",
278 dvp, (uintmax_t)tnode->nn_ino, (uintmax_t)fnode->nn_ino,
279 (uintmax_t)tnode->nn_diroff));
281 blocksize = dir_node->nn_nandfsdev->nd_blocksize;
282 blocknr = tnode->nn_diroff / blocksize;
283 off = tnode->nn_diroff % blocksize;
284 error = nandfs_bread(dir_node, blocknr, NOCRED, 0, &bp);
291 dirent = (struct nandfs_dir_entry *) (pos + off);
292 KASSERT((dirent->inode == tnode->nn_ino),
293 ("direntry mismatch"));
295 dirent->inode = fnode->nn_ino;
296 error = nandfs_dirty_buf(bp, 0);
304 nandfs_init_dir(struct vnode *dvp, uint64_t ino, uint64_t parent_ino)
307 if (nandfs_add_dirent(dvp, parent_ino, "..", 2, DT_DIR) ||
308 nandfs_add_dirent(dvp, ino, ".", 1, DT_DIR)) {
309 nandfs_error("%s: cannot initialize dir ino:%jd(pino:%jd)\n",
310 __func__, ino, parent_ino);