Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/fs/tmpfs/tmpfs_vnops.c
39507 views
1
/* $NetBSD: tmpfs_vnops.c,v 1.39 2007/07/23 15:41:01 jmmv Exp $ */
2
3
/*-
4
* SPDX-License-Identifier: BSD-2-Clause
5
*
6
* Copyright (c) 2005, 2006 The NetBSD Foundation, Inc.
7
* All rights reserved.
8
*
9
* This code is derived from software contributed to The NetBSD Foundation
10
* by Julio M. Merino Vidal, developed as part of Google's Summer of Code
11
* 2005 program.
12
*
13
* Redistribution and use in source and binary forms, with or without
14
* modification, are permitted provided that the following conditions
15
* are met:
16
* 1. Redistributions of source code must retain the above copyright
17
* notice, this list of conditions and the following disclaimer.
18
* 2. Redistributions in binary form must reproduce the above copyright
19
* notice, this list of conditions and the following disclaimer in the
20
* documentation and/or other materials provided with the distribution.
21
*
22
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
23
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
26
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
* POSSIBILITY OF SUCH DAMAGE.
33
*/
34
35
/*
36
* tmpfs vnode interface.
37
*/
38
39
#include <sys/param.h>
40
#include <sys/systm.h>
41
#include <sys/dirent.h>
42
#include <sys/extattr.h>
43
#include <sys/fcntl.h>
44
#include <sys/file.h>
45
#include <sys/filio.h>
46
#include <sys/limits.h>
47
#include <sys/lockf.h>
48
#include <sys/lock.h>
49
#include <sys/mount.h>
50
#include <sys/namei.h>
51
#include <sys/priv.h>
52
#include <sys/proc.h>
53
#include <sys/rwlock.h>
54
#include <sys/sched.h>
55
#include <sys/smr.h>
56
#include <sys/stat.h>
57
#include <sys/sysctl.h>
58
#include <sys/unistd.h>
59
#include <sys/vnode.h>
60
#include <security/audit/audit.h>
61
#include <security/mac/mac_framework.h>
62
63
#include <vm/vm.h>
64
#include <vm/vm_param.h>
65
#include <vm/vm_object.h>
66
#include <vm/vm_page.h>
67
#include <vm/vm_pager.h>
68
#include <vm/swap_pager.h>
69
70
#include <fs/tmpfs/tmpfs_vnops.h>
71
#include <fs/tmpfs/tmpfs.h>
72
73
SYSCTL_DECL(_vfs_tmpfs);
74
VFS_SMR_DECLARE;
75
76
static volatile int tmpfs_rename_restarts;
77
SYSCTL_INT(_vfs_tmpfs, OID_AUTO, rename_restarts, CTLFLAG_RD,
78
__DEVOLATILE(int *, &tmpfs_rename_restarts), 0,
79
"Times rename had to restart due to lock contention");
80
81
MALLOC_DEFINE(M_TMPFSEA, "tmpfs extattr", "tmpfs extattr structure");
82
83
static int
84
tmpfs_vn_get_ino_alloc(struct mount *mp, void *arg, int lkflags,
85
struct vnode **rvp)
86
{
87
88
return (tmpfs_alloc_vp(mp, arg, lkflags, rvp));
89
}
90
91
static int
92
tmpfs_lookup1(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp)
93
{
94
struct tmpfs_dirent *de;
95
struct tmpfs_node *dnode, *pnode;
96
struct tmpfs_mount *tm;
97
int error;
98
99
/* Caller assumes responsibility for ensuring access (VEXEC). */
100
dnode = VP_TO_TMPFS_DIR(dvp);
101
*vpp = NULL;
102
103
/* We cannot be requesting the parent directory of the root node. */
104
MPASS(IMPLIES(dnode->tn_type == VDIR &&
105
dnode->tn_dir.tn_parent == dnode,
106
!(cnp->cn_flags & ISDOTDOT)));
107
108
TMPFS_ASSERT_LOCKED(dnode);
109
if (dnode->tn_dir.tn_parent == NULL) {
110
error = ENOENT;
111
goto out;
112
}
113
if (cnp->cn_flags & ISDOTDOT) {
114
tm = VFS_TO_TMPFS(dvp->v_mount);
115
pnode = dnode->tn_dir.tn_parent;
116
tmpfs_ref_node(pnode);
117
error = vn_vget_ino_gen(dvp, tmpfs_vn_get_ino_alloc,
118
pnode, cnp->cn_lkflags, vpp);
119
tmpfs_free_node(tm, pnode);
120
if (error != 0)
121
goto out;
122
} else if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') {
123
vref(dvp);
124
*vpp = dvp;
125
error = 0;
126
} else {
127
de = tmpfs_dir_lookup(dnode, NULL, cnp);
128
if (de != NULL && de->td_node == NULL)
129
cnp->cn_flags |= ISWHITEOUT;
130
if (de == NULL || de->td_node == NULL) {
131
/*
132
* The entry was not found in the directory.
133
* This is OK if we are creating or renaming an
134
* entry and are working on the last component of
135
* the path name.
136
*/
137
if ((cnp->cn_flags & ISLASTCN) &&
138
(cnp->cn_nameiop == CREATE || \
139
cnp->cn_nameiop == RENAME ||
140
(cnp->cn_nameiop == DELETE &&
141
cnp->cn_flags & DOWHITEOUT &&
142
cnp->cn_flags & ISWHITEOUT))) {
143
error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred,
144
curthread);
145
if (error != 0)
146
goto out;
147
148
error = EJUSTRETURN;
149
} else
150
error = ENOENT;
151
} else {
152
struct tmpfs_node *tnode;
153
154
/*
155
* The entry was found, so get its associated
156
* tmpfs_node.
157
*/
158
tnode = de->td_node;
159
160
/*
161
* If we are not at the last path component and
162
* found a non-directory or non-link entry (which
163
* may itself be pointing to a directory), raise
164
* an error.
165
*/
166
if ((tnode->tn_type != VDIR &&
167
tnode->tn_type != VLNK) &&
168
!(cnp->cn_flags & ISLASTCN)) {
169
error = ENOTDIR;
170
goto out;
171
}
172
173
/*
174
* If we are deleting or renaming the entry, keep
175
* track of its tmpfs_dirent so that it can be
176
* easily deleted later.
177
*/
178
if ((cnp->cn_flags & ISLASTCN) &&
179
(cnp->cn_nameiop == DELETE ||
180
cnp->cn_nameiop == RENAME)) {
181
error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred,
182
curthread);
183
if (error != 0)
184
goto out;
185
186
/* Allocate a new vnode on the matching entry. */
187
error = tmpfs_alloc_vp(dvp->v_mount, tnode,
188
cnp->cn_lkflags, vpp);
189
if (error != 0)
190
goto out;
191
192
if ((dnode->tn_mode & S_ISTXT) &&
193
VOP_ACCESS(dvp, VADMIN, cnp->cn_cred,
194
curthread) && VOP_ACCESS(*vpp, VADMIN,
195
cnp->cn_cred, curthread)) {
196
error = EPERM;
197
vput(*vpp);
198
*vpp = NULL;
199
goto out;
200
}
201
} else {
202
error = tmpfs_alloc_vp(dvp->v_mount, tnode,
203
cnp->cn_lkflags, vpp);
204
if (error != 0)
205
goto out;
206
}
207
}
208
}
209
210
/*
211
* Store the result of this lookup in the cache. Avoid this if the
212
* request was for creation, as it does not improve timings on
213
* emprical tests.
214
*/
215
if ((cnp->cn_flags & MAKEENTRY) != 0 && tmpfs_use_nc(dvp))
216
cache_enter(dvp, *vpp, cnp);
217
218
out:
219
#ifdef INVARIANTS
220
/*
221
* If there were no errors, *vpp cannot be null and it must be
222
* locked.
223
*/
224
if (error == 0) {
225
MPASS(*vpp != NULL);
226
ASSERT_VOP_LOCKED(*vpp, __func__);
227
} else {
228
MPASS(*vpp == NULL);
229
}
230
#endif
231
232
return (error);
233
}
234
235
static int
236
tmpfs_cached_lookup(struct vop_cachedlookup_args *v)
237
{
238
239
return (tmpfs_lookup1(v->a_dvp, v->a_vpp, v->a_cnp));
240
}
241
242
static int
243
tmpfs_lookup(struct vop_lookup_args *v)
244
{
245
struct vnode *dvp = v->a_dvp;
246
struct vnode **vpp = v->a_vpp;
247
struct componentname *cnp = v->a_cnp;
248
int error;
249
250
/* Check accessibility of requested node as a first step. */
251
error = vn_dir_check_exec(dvp, cnp);
252
if (error != 0)
253
return (error);
254
255
return (tmpfs_lookup1(dvp, vpp, cnp));
256
}
257
258
static int
259
tmpfs_create(struct vop_create_args *v)
260
{
261
struct vnode *dvp = v->a_dvp;
262
struct vnode **vpp = v->a_vpp;
263
struct componentname *cnp = v->a_cnp;
264
struct vattr *vap = v->a_vap;
265
int error;
266
267
MPASS(vap->va_type == VREG || vap->va_type == VSOCK);
268
269
error = tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL);
270
if (error == 0 && (cnp->cn_flags & MAKEENTRY) != 0 && tmpfs_use_nc(dvp))
271
cache_enter(dvp, *vpp, cnp);
272
return (error);
273
}
274
275
static int
276
tmpfs_mknod(struct vop_mknod_args *v)
277
{
278
struct vnode *dvp = v->a_dvp;
279
struct vnode **vpp = v->a_vpp;
280
struct componentname *cnp = v->a_cnp;
281
struct vattr *vap = v->a_vap;
282
283
if (!VATTR_ISDEV(vap) && vap->va_type != VFIFO)
284
return (EINVAL);
285
286
return (tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL));
287
}
288
289
struct fileops tmpfs_fnops;
290
291
static int
292
tmpfs_open(struct vop_open_args *v)
293
{
294
struct vnode *vp;
295
struct tmpfs_node *node;
296
struct file *fp;
297
int error, mode;
298
299
vp = v->a_vp;
300
mode = v->a_mode;
301
node = VP_TO_TMPFS_NODE(vp);
302
303
/*
304
* The file is still active but all its names have been removed
305
* (e.g. by a "rmdir $(pwd)"). It cannot be opened any more as
306
* it is about to die.
307
*/
308
if (node->tn_links < 1)
309
return (ENOENT);
310
311
/* If the file is marked append-only, deny write requests. */
312
if (node->tn_flags & APPEND && (mode & (FWRITE | O_APPEND)) == FWRITE)
313
error = EPERM;
314
else {
315
error = 0;
316
/* For regular files, the call below is nop. */
317
KASSERT(vp->v_type != VREG || (node->tn_reg.tn_aobj->flags &
318
OBJ_DEAD) == 0, ("dead object"));
319
vnode_create_vobject(vp, node->tn_size, v->a_td);
320
}
321
322
fp = v->a_fp;
323
MPASS(fp == NULL || fp->f_data == NULL);
324
if (error == 0 && fp != NULL && vp->v_type == VREG) {
325
tmpfs_ref_node(node);
326
finit_vnode(fp, mode, node, &tmpfs_fnops);
327
}
328
329
return (error);
330
}
331
332
static int
333
tmpfs_close(struct vop_close_args *v)
334
{
335
struct vnode *vp = v->a_vp;
336
337
/* Update node times. */
338
tmpfs_update(vp);
339
340
return (0);
341
}
342
343
int
344
tmpfs_fo_close(struct file *fp, struct thread *td)
345
{
346
struct tmpfs_node *node;
347
348
node = fp->f_data;
349
if (node != NULL) {
350
MPASS(node->tn_type == VREG);
351
tmpfs_free_node(node->tn_reg.tn_tmp, node);
352
}
353
return (vnops.fo_close(fp, td));
354
}
355
356
/*
357
* VOP_FPLOOKUP_VEXEC routines are subject to special circumstances, see
358
* the comment above cache_fplookup for details.
359
*/
360
int
361
tmpfs_fplookup_vexec(struct vop_fplookup_vexec_args *v)
362
{
363
struct vnode *vp;
364
struct tmpfs_node *node;
365
struct ucred *cred;
366
mode_t all_x, mode;
367
368
vp = v->a_vp;
369
node = VP_TO_TMPFS_NODE_SMR(vp);
370
if (__predict_false(node == NULL))
371
return (EAGAIN);
372
373
all_x = S_IXUSR | S_IXGRP | S_IXOTH;
374
mode = atomic_load_short(&node->tn_mode);
375
if (__predict_true((mode & all_x) == all_x))
376
return (0);
377
378
cred = v->a_cred;
379
return (vaccess_vexec_smr(mode, node->tn_uid, node->tn_gid, cred));
380
}
381
382
static int
383
tmpfs_access_locked(struct vnode *vp, struct tmpfs_node *node,
384
accmode_t accmode, struct ucred *cred)
385
{
386
#ifdef INVARIANTS
387
if (!mtx_owned(TMPFS_NODE_MTX(node))) {
388
ASSERT_VOP_LOCKED(vp,
389
"tmpfs_access_locked needs locked vnode or node");
390
}
391
#endif
392
393
if ((accmode & VWRITE) != 0 && (node->tn_flags & IMMUTABLE) != 0)
394
return (EPERM);
395
return (vaccess(vp->v_type, node->tn_mode, node->tn_uid, node->tn_gid,
396
accmode, cred));
397
}
398
399
int
400
tmpfs_access(struct vop_access_args *v)
401
{
402
struct vnode *vp = v->a_vp;
403
struct ucred *cred = v->a_cred;
404
struct tmpfs_node *node = VP_TO_TMPFS_NODE(vp);
405
mode_t all_x = S_IXUSR | S_IXGRP | S_IXOTH;
406
accmode_t accmode = v->a_accmode;
407
408
/*
409
* Common case path lookup.
410
*/
411
if (__predict_true(accmode == VEXEC &&
412
(node->tn_mode & all_x) == all_x))
413
return (0);
414
415
switch (vp->v_type) {
416
case VDIR:
417
/* FALLTHROUGH */
418
case VLNK:
419
/* FALLTHROUGH */
420
case VREG:
421
if ((accmode & VWRITE) != 0 &&
422
(vp->v_mount->mnt_flag & MNT_RDONLY) != 0)
423
return (EROFS);
424
break;
425
426
case VBLK:
427
/* FALLTHROUGH */
428
case VCHR:
429
/* FALLTHROUGH */
430
case VSOCK:
431
/* FALLTHROUGH */
432
case VFIFO:
433
break;
434
435
default:
436
return (EINVAL);
437
}
438
439
return (tmpfs_access_locked(vp, node, accmode, cred));
440
}
441
442
int
443
tmpfs_stat(struct vop_stat_args *v)
444
{
445
struct vnode *vp = v->a_vp;
446
struct stat *sb = v->a_sb;
447
struct tmpfs_node *node;
448
int error;
449
450
node = VP_TO_TMPFS_NODE(vp);
451
452
tmpfs_update_getattr(vp);
453
454
error = vop_stat_helper_pre(v);
455
if (__predict_false(error))
456
return (error);
457
458
sb->st_dev = vp->v_mount->mnt_stat.f_fsid.val[0];
459
sb->st_ino = node->tn_id;
460
sb->st_mode = node->tn_mode | VTTOIF(vp->v_type);
461
sb->st_nlink = node->tn_links;
462
sb->st_uid = node->tn_uid;
463
sb->st_gid = node->tn_gid;
464
sb->st_rdev = VN_ISDEV(vp) ? node->tn_rdev : NODEV;
465
sb->st_size = node->tn_size;
466
sb->st_atim.tv_sec = node->tn_atime.tv_sec;
467
sb->st_atim.tv_nsec = node->tn_atime.tv_nsec;
468
sb->st_mtim.tv_sec = node->tn_mtime.tv_sec;
469
sb->st_mtim.tv_nsec = node->tn_mtime.tv_nsec;
470
sb->st_ctim.tv_sec = node->tn_ctime.tv_sec;
471
sb->st_ctim.tv_nsec = node->tn_ctime.tv_nsec;
472
sb->st_birthtim.tv_sec = node->tn_birthtime.tv_sec;
473
sb->st_birthtim.tv_nsec = node->tn_birthtime.tv_nsec;
474
sb->st_blksize = PAGE_SIZE;
475
sb->st_flags = node->tn_flags;
476
sb->st_gen = node->tn_gen;
477
sb->st_filerev = 0;
478
if (vp->v_type == VREG) {
479
#ifdef __ILP32__
480
vm_object_t obj = node->tn_reg.tn_aobj;
481
482
/* Handle torn read */
483
VM_OBJECT_RLOCK(obj);
484
#endif
485
sb->st_blocks = ptoa(node->tn_reg.tn_pages);
486
#ifdef __ILP32__
487
VM_OBJECT_RUNLOCK(obj);
488
#endif
489
} else {
490
sb->st_blocks = node->tn_size;
491
}
492
sb->st_blocks /= S_BLKSIZE;
493
return (vop_stat_helper_post(v, error));
494
}
495
496
int
497
tmpfs_getattr(struct vop_getattr_args *v)
498
{
499
struct vnode *vp = v->a_vp;
500
struct vattr *vap = v->a_vap;
501
struct tmpfs_node *node;
502
503
node = VP_TO_TMPFS_NODE(vp);
504
505
tmpfs_update_getattr(vp);
506
507
vap->va_type = vp->v_type;
508
vap->va_mode = node->tn_mode;
509
vap->va_nlink = node->tn_links;
510
vap->va_uid = node->tn_uid;
511
vap->va_gid = node->tn_gid;
512
vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
513
vap->va_fileid = node->tn_id;
514
vap->va_size = node->tn_size;
515
vap->va_blocksize = PAGE_SIZE;
516
vap->va_atime = node->tn_atime;
517
vap->va_mtime = node->tn_mtime;
518
vap->va_ctime = node->tn_ctime;
519
vap->va_birthtime = node->tn_birthtime;
520
vap->va_gen = node->tn_gen;
521
vap->va_flags = node->tn_flags;
522
vap->va_rdev = VN_ISDEV(vp) ? node->tn_rdev : NODEV;
523
if (vp->v_type == VREG) {
524
#ifdef __ILP32__
525
vm_object_t obj = node->tn_reg.tn_aobj;
526
527
VM_OBJECT_RLOCK(obj);
528
#endif
529
vap->va_bytes = ptoa(node->tn_reg.tn_pages);
530
#ifdef __ILP32__
531
VM_OBJECT_RUNLOCK(obj);
532
#endif
533
} else {
534
vap->va_bytes = node->tn_size;
535
}
536
vap->va_filerev = 0;
537
538
return (0);
539
}
540
541
int
542
tmpfs_setattr(struct vop_setattr_args *v)
543
{
544
struct vnode *vp = v->a_vp;
545
struct vattr *vap = v->a_vap;
546
struct ucred *cred = v->a_cred;
547
struct thread *td = curthread;
548
549
int error;
550
551
ASSERT_VOP_IN_SEQC(vp);
552
553
error = 0;
554
555
/* Abort if any unsettable attribute is given. */
556
if (vap->va_type != VNON ||
557
vap->va_nlink != VNOVAL ||
558
vap->va_fsid != VNOVAL ||
559
vap->va_fileid != VNOVAL ||
560
vap->va_blocksize != VNOVAL ||
561
vap->va_gen != VNOVAL ||
562
vap->va_rdev != VNOVAL ||
563
vap->va_bytes != VNOVAL)
564
error = EINVAL;
565
566
if (error == 0 && (vap->va_flags != VNOVAL))
567
error = tmpfs_chflags(vp, vap->va_flags, cred, td);
568
569
if (error == 0 && (vap->va_size != VNOVAL))
570
error = tmpfs_chsize(vp, vap->va_size, cred, td);
571
572
if (error == 0 && (vap->va_uid != VNOVAL || vap->va_gid != VNOVAL))
573
error = tmpfs_chown(vp, vap->va_uid, vap->va_gid, cred, td);
574
575
if (error == 0 && (vap->va_mode != (mode_t)VNOVAL))
576
error = tmpfs_chmod(vp, vap->va_mode, cred, td);
577
578
if (error == 0 && ((vap->va_atime.tv_sec != VNOVAL &&
579
vap->va_atime.tv_nsec != VNOVAL) ||
580
(vap->va_mtime.tv_sec != VNOVAL &&
581
vap->va_mtime.tv_nsec != VNOVAL) ||
582
(vap->va_birthtime.tv_sec != VNOVAL &&
583
vap->va_birthtime.tv_nsec != VNOVAL)))
584
error = tmpfs_chtimes(vp, vap, cred, td);
585
586
/*
587
* Update the node times. We give preference to the error codes
588
* generated by this function rather than the ones that may arise
589
* from tmpfs_update.
590
*/
591
tmpfs_update(vp);
592
593
return (error);
594
}
595
596
static int
597
tmpfs_read(struct vop_read_args *v)
598
{
599
struct vnode *vp;
600
struct uio *uio;
601
struct tmpfs_node *node;
602
603
vp = v->a_vp;
604
if (vp->v_type != VREG)
605
return (EISDIR);
606
uio = v->a_uio;
607
if (uio->uio_offset < 0)
608
return (EINVAL);
609
node = VP_TO_TMPFS_NODE(vp);
610
tmpfs_set_accessed(VFS_TO_TMPFS(vp->v_mount), node);
611
return (uiomove_object(node->tn_reg.tn_aobj, node->tn_size, uio));
612
}
613
614
static int
615
tmpfs_read_pgcache(struct vop_read_pgcache_args *v)
616
{
617
struct vnode *vp;
618
struct tmpfs_node *node;
619
vm_object_t object;
620
off_t size;
621
int error;
622
623
vp = v->a_vp;
624
VNPASS((vn_irflag_read(vp) & VIRF_PGREAD) != 0, vp);
625
626
if (v->a_uio->uio_offset < 0)
627
return (EINVAL);
628
629
error = EJUSTRETURN;
630
vfs_smr_enter();
631
632
node = VP_TO_TMPFS_NODE_SMR(vp);
633
if (node == NULL)
634
goto out_smr;
635
MPASS(node->tn_type == VREG);
636
MPASS(node->tn_refcount >= 1);
637
object = node->tn_reg.tn_aobj;
638
if (object == NULL)
639
goto out_smr;
640
641
MPASS(object->type == tmpfs_pager_type);
642
MPASS((object->flags & (OBJ_ANON | OBJ_DEAD | OBJ_SWAP)) ==
643
OBJ_SWAP);
644
if (!VN_IS_DOOMED(vp)) {
645
/* size cannot become shorter due to rangelock. */
646
size = node->tn_size;
647
tmpfs_set_accessed(node->tn_reg.tn_tmp, node);
648
vfs_smr_exit();
649
error = uiomove_object(object, size, v->a_uio);
650
return (error);
651
}
652
out_smr:
653
vfs_smr_exit();
654
return (error);
655
}
656
657
static int
658
tmpfs_write(struct vop_write_args *v)
659
{
660
struct vnode *vp;
661
struct uio *uio;
662
struct tmpfs_node *node;
663
off_t oldsize;
664
ssize_t r;
665
int error, ioflag;
666
mode_t newmode;
667
668
vp = v->a_vp;
669
uio = v->a_uio;
670
ioflag = v->a_ioflag;
671
error = 0;
672
node = VP_TO_TMPFS_NODE(vp);
673
oldsize = node->tn_size;
674
675
if (uio->uio_offset < 0 || vp->v_type != VREG)
676
return (EINVAL);
677
if (uio->uio_resid == 0)
678
return (0);
679
if (ioflag & IO_APPEND)
680
uio->uio_offset = node->tn_size;
681
error = vn_rlimit_fsizex(vp, uio, VFS_TO_TMPFS(vp->v_mount)->
682
tm_maxfilesize, &r, uio->uio_td);
683
if (error != 0) {
684
vn_rlimit_fsizex_res(uio, r);
685
return (error);
686
}
687
688
if (uio->uio_offset + uio->uio_resid > node->tn_size) {
689
error = tmpfs_reg_resize(vp, uio->uio_offset + uio->uio_resid,
690
FALSE);
691
if (error != 0)
692
goto out;
693
}
694
695
error = uiomove_object(node->tn_reg.tn_aobj, node->tn_size, uio);
696
node->tn_status |= TMPFS_NODE_MODIFIED | TMPFS_NODE_CHANGED;
697
node->tn_accessed = true;
698
if (node->tn_mode & (S_ISUID | S_ISGID)) {
699
if (priv_check_cred(v->a_cred, PRIV_VFS_RETAINSUGID)) {
700
newmode = node->tn_mode & ~(S_ISUID | S_ISGID);
701
vn_seqc_write_begin(vp);
702
atomic_store_short(&node->tn_mode, newmode);
703
vn_seqc_write_end(vp);
704
}
705
}
706
if (error != 0)
707
(void)tmpfs_reg_resize(vp, oldsize, TRUE);
708
709
out:
710
MPASS(IMPLIES(error == 0, uio->uio_resid == 0));
711
MPASS(IMPLIES(error != 0, oldsize == node->tn_size));
712
713
vn_rlimit_fsizex_res(uio, r);
714
return (error);
715
}
716
717
static int
718
tmpfs_deallocate(struct vop_deallocate_args *v)
719
{
720
return (tmpfs_reg_punch_hole(v->a_vp, v->a_offset, v->a_len));
721
}
722
723
static int
724
tmpfs_fsync(struct vop_fsync_args *v)
725
{
726
struct vnode *vp = v->a_vp;
727
728
tmpfs_check_mtime(vp);
729
tmpfs_update(vp);
730
731
return (0);
732
}
733
734
static int
735
tmpfs_remove(struct vop_remove_args *v)
736
{
737
struct vnode *dvp = v->a_dvp;
738
struct vnode *vp = v->a_vp;
739
740
int error;
741
struct tmpfs_dirent *de;
742
struct tmpfs_mount *tmp;
743
struct tmpfs_node *dnode;
744
struct tmpfs_node *node;
745
746
if (vp->v_type == VDIR) {
747
error = EISDIR;
748
goto out;
749
}
750
751
dnode = VP_TO_TMPFS_DIR(dvp);
752
node = VP_TO_TMPFS_NODE(vp);
753
tmp = VFS_TO_TMPFS(vp->v_mount);
754
de = tmpfs_dir_lookup(dnode, node, v->a_cnp);
755
MPASS(de != NULL);
756
757
/* Files marked as immutable or append-only cannot be deleted. */
758
if ((node->tn_flags & (IMMUTABLE | APPEND | NOUNLINK)) ||
759
(dnode->tn_flags & APPEND)) {
760
error = EPERM;
761
goto out;
762
}
763
764
/* Remove the entry from the directory; as it is a file, we do not
765
* have to change the number of hard links of the directory. */
766
tmpfs_dir_detach(dvp, de);
767
if (v->a_cnp->cn_flags & DOWHITEOUT)
768
tmpfs_dir_whiteout_add(dvp, v->a_cnp);
769
770
/* Free the directory entry we just deleted. Note that the node
771
* referred by it will not be removed until the vnode is really
772
* reclaimed. */
773
tmpfs_free_dirent(tmp, de);
774
775
node->tn_status |= TMPFS_NODE_CHANGED;
776
node->tn_accessed = true;
777
error = 0;
778
779
out:
780
return (error);
781
}
782
783
static int
784
tmpfs_link(struct vop_link_args *v)
785
{
786
struct vnode *dvp = v->a_tdvp;
787
struct vnode *vp = v->a_vp;
788
struct componentname *cnp = v->a_cnp;
789
790
int error;
791
struct tmpfs_dirent *de;
792
struct tmpfs_node *node;
793
794
MPASS(dvp != vp); /* XXX When can this be false? */
795
node = VP_TO_TMPFS_NODE(vp);
796
797
/* Ensure that we do not overflow the maximum number of links imposed
798
* by the system. */
799
MPASS(node->tn_links <= TMPFS_LINK_MAX);
800
if (node->tn_links == TMPFS_LINK_MAX) {
801
error = EMLINK;
802
goto out;
803
}
804
805
/* We cannot create links of files marked immutable or append-only. */
806
if (node->tn_flags & (IMMUTABLE | APPEND)) {
807
error = EPERM;
808
goto out;
809
}
810
811
/* Allocate a new directory entry to represent the node. */
812
error = tmpfs_alloc_dirent(VFS_TO_TMPFS(vp->v_mount), node,
813
cnp->cn_nameptr, cnp->cn_namelen, &de);
814
if (error != 0)
815
goto out;
816
817
/* Insert the new directory entry into the appropriate directory. */
818
if (cnp->cn_flags & ISWHITEOUT)
819
tmpfs_dir_whiteout_remove(dvp, cnp);
820
tmpfs_dir_attach(dvp, de);
821
822
/* vp link count has changed, so update node times. */
823
node->tn_status |= TMPFS_NODE_CHANGED;
824
tmpfs_update(vp);
825
826
error = 0;
827
828
out:
829
return (error);
830
}
831
832
/*
833
* We acquire all but fdvp locks using non-blocking acquisitions. If we
834
* fail to acquire any lock in the path we will drop all held locks,
835
* acquire the new lock in a blocking fashion, and then release it and
836
* restart the rename. This acquire/release step ensures that we do not
837
* spin on a lock waiting for release. On error release all vnode locks
838
* and decrement references the way tmpfs_rename() would do.
839
*/
840
static int
841
tmpfs_rename_relock(struct vnode *fdvp, struct vnode **fvpp,
842
struct vnode *tdvp, struct vnode **tvpp,
843
struct componentname *fcnp, struct componentname *tcnp)
844
{
845
struct vnode *nvp;
846
struct mount *mp;
847
struct tmpfs_dirent *de;
848
int error, restarts = 0;
849
850
VOP_UNLOCK(tdvp);
851
if (*tvpp != NULL && *tvpp != tdvp)
852
VOP_UNLOCK(*tvpp);
853
mp = fdvp->v_mount;
854
855
relock:
856
restarts += 1;
857
error = vn_lock(fdvp, LK_EXCLUSIVE);
858
if (error)
859
goto releout;
860
if (vn_lock(tdvp, LK_EXCLUSIVE | LK_NOWAIT) != 0) {
861
VOP_UNLOCK(fdvp);
862
error = vn_lock(tdvp, LK_EXCLUSIVE);
863
if (error)
864
goto releout;
865
VOP_UNLOCK(tdvp);
866
goto relock;
867
}
868
/*
869
* Re-resolve fvp to be certain it still exists and fetch the
870
* correct vnode.
871
*/
872
de = tmpfs_dir_lookup(VP_TO_TMPFS_DIR(fdvp), NULL, fcnp);
873
if (de == NULL) {
874
VOP_UNLOCK(fdvp);
875
VOP_UNLOCK(tdvp);
876
if ((fcnp->cn_flags & ISDOTDOT) != 0 ||
877
(fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.'))
878
error = EINVAL;
879
else
880
error = ENOENT;
881
goto releout;
882
}
883
error = tmpfs_alloc_vp(mp, de->td_node, LK_EXCLUSIVE | LK_NOWAIT, &nvp);
884
if (error != 0) {
885
VOP_UNLOCK(fdvp);
886
VOP_UNLOCK(tdvp);
887
if (error != EBUSY)
888
goto releout;
889
error = tmpfs_alloc_vp(mp, de->td_node, LK_EXCLUSIVE, &nvp);
890
if (error != 0)
891
goto releout;
892
VOP_UNLOCK(nvp);
893
/*
894
* Concurrent rename race.
895
*/
896
if (nvp == tdvp) {
897
vrele(nvp);
898
error = EINVAL;
899
goto releout;
900
}
901
vrele(*fvpp);
902
*fvpp = nvp;
903
goto relock;
904
}
905
vrele(*fvpp);
906
*fvpp = nvp;
907
VOP_UNLOCK(*fvpp);
908
/*
909
* Re-resolve tvp and acquire the vnode lock if present.
910
*/
911
de = tmpfs_dir_lookup(VP_TO_TMPFS_DIR(tdvp), NULL, tcnp);
912
/*
913
* If tvp disappeared we just carry on.
914
*/
915
if (de == NULL && *tvpp != NULL) {
916
vrele(*tvpp);
917
*tvpp = NULL;
918
}
919
/*
920
* Get the tvp ino if the lookup succeeded. We may have to restart
921
* if the non-blocking acquire fails.
922
*/
923
if (de != NULL) {
924
nvp = NULL;
925
error = tmpfs_alloc_vp(mp, de->td_node,
926
LK_EXCLUSIVE | LK_NOWAIT, &nvp);
927
if (*tvpp != NULL)
928
vrele(*tvpp);
929
*tvpp = nvp;
930
if (error != 0) {
931
VOP_UNLOCK(fdvp);
932
VOP_UNLOCK(tdvp);
933
if (error != EBUSY)
934
goto releout;
935
error = tmpfs_alloc_vp(mp, de->td_node, LK_EXCLUSIVE,
936
&nvp);
937
if (error != 0)
938
goto releout;
939
VOP_UNLOCK(nvp);
940
/*
941
* fdvp contains fvp, thus tvp (=fdvp) is not empty.
942
*/
943
if (nvp == fdvp) {
944
error = ENOTEMPTY;
945
goto releout;
946
}
947
goto relock;
948
}
949
}
950
tmpfs_rename_restarts += restarts;
951
952
return (0);
953
954
releout:
955
vrele(fdvp);
956
vrele(*fvpp);
957
vrele(tdvp);
958
if (*tvpp != NULL)
959
vrele(*tvpp);
960
tmpfs_rename_restarts += restarts;
961
962
return (error);
963
}
964
965
static int
966
tmpfs_rename(struct vop_rename_args *v)
967
{
968
struct vnode *fdvp = v->a_fdvp;
969
struct vnode *fvp = v->a_fvp;
970
struct componentname *fcnp = v->a_fcnp;
971
struct vnode *tdvp = v->a_tdvp;
972
struct vnode *tvp = v->a_tvp;
973
struct componentname *tcnp = v->a_tcnp;
974
char *newname;
975
struct tmpfs_dirent *de;
976
struct tmpfs_mount *tmp;
977
struct tmpfs_node *fdnode;
978
struct tmpfs_node *fnode;
979
struct tmpfs_node *tnode;
980
struct tmpfs_node *tdnode;
981
int error;
982
bool want_seqc_end;
983
984
want_seqc_end = false;
985
986
/*
987
* Disallow cross-device renames.
988
* XXX Why isn't this done by the caller?
989
*/
990
if (fvp->v_mount != tdvp->v_mount ||
991
(tvp != NULL && fvp->v_mount != tvp->v_mount)) {
992
error = EXDEV;
993
goto out;
994
}
995
996
/* If source and target are the same file, there is nothing to do. */
997
if (fvp == tvp) {
998
error = 0;
999
goto out;
1000
}
1001
1002
/*
1003
* If we need to move the directory between entries, lock the
1004
* source so that we can safely operate on it.
1005
*/
1006
if (fdvp != tdvp && fdvp != tvp) {
1007
if (vn_lock(fdvp, LK_EXCLUSIVE | LK_NOWAIT) != 0) {
1008
error = tmpfs_rename_relock(fdvp, &fvp, tdvp, &tvp,
1009
fcnp, tcnp);
1010
if (error != 0)
1011
return (error);
1012
ASSERT_VOP_ELOCKED(fdvp,
1013
"tmpfs_rename: fdvp not locked");
1014
ASSERT_VOP_ELOCKED(tdvp,
1015
"tmpfs_rename: tdvp not locked");
1016
if (tvp != NULL)
1017
ASSERT_VOP_ELOCKED(tvp,
1018
"tmpfs_rename: tvp not locked");
1019
if (fvp == tvp) {
1020
error = 0;
1021
goto out_locked;
1022
}
1023
}
1024
}
1025
1026
/*
1027
* Avoid manipulating '.' and '..' entries.
1028
*/
1029
if ((fcnp->cn_flags & ISDOTDOT) != 0 ||
1030
(fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.')) {
1031
error = EINVAL;
1032
goto out_locked;
1033
}
1034
1035
if (tvp != NULL)
1036
vn_seqc_write_begin(tvp);
1037
vn_seqc_write_begin(tdvp);
1038
vn_seqc_write_begin(fvp);
1039
vn_seqc_write_begin(fdvp);
1040
want_seqc_end = true;
1041
1042
tmp = VFS_TO_TMPFS(tdvp->v_mount);
1043
tdnode = VP_TO_TMPFS_DIR(tdvp);
1044
tnode = (tvp == NULL) ? NULL : VP_TO_TMPFS_NODE(tvp);
1045
fdnode = VP_TO_TMPFS_DIR(fdvp);
1046
fnode = VP_TO_TMPFS_NODE(fvp);
1047
de = tmpfs_dir_lookup(fdnode, fnode, fcnp);
1048
1049
/*
1050
* Entry can disappear before we lock fdvp.
1051
*/
1052
if (de == NULL) {
1053
if ((fcnp->cn_flags & ISDOTDOT) != 0 ||
1054
(fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.'))
1055
error = EINVAL;
1056
else
1057
error = ENOENT;
1058
goto out_locked;
1059
}
1060
MPASS(de->td_node == fnode);
1061
1062
/*
1063
* If re-naming a directory to another preexisting directory
1064
* ensure that the target directory is empty so that its
1065
* removal causes no side effects.
1066
* Kern_rename guarantees the destination to be a directory
1067
* if the source is one.
1068
*/
1069
if (tvp != NULL) {
1070
MPASS(tnode != NULL);
1071
1072
if ((tnode->tn_flags & (NOUNLINK | IMMUTABLE | APPEND)) ||
1073
(tdnode->tn_flags & (APPEND | IMMUTABLE))) {
1074
error = EPERM;
1075
goto out_locked;
1076
}
1077
1078
if (fnode->tn_type == VDIR && tnode->tn_type == VDIR) {
1079
if (tnode->tn_size != 0 &&
1080
((tcnp->cn_flags & IGNOREWHITEOUT) == 0 ||
1081
tnode->tn_size > tnode->tn_dir.tn_wht_size)) {
1082
error = ENOTEMPTY;
1083
goto out_locked;
1084
}
1085
} else if (fnode->tn_type == VDIR && tnode->tn_type != VDIR) {
1086
error = ENOTDIR;
1087
goto out_locked;
1088
} else if (fnode->tn_type != VDIR && tnode->tn_type == VDIR) {
1089
error = EISDIR;
1090
goto out_locked;
1091
} else {
1092
MPASS(fnode->tn_type != VDIR &&
1093
tnode->tn_type != VDIR);
1094
}
1095
}
1096
1097
if ((fnode->tn_flags & (NOUNLINK | IMMUTABLE | APPEND))
1098
|| (fdnode->tn_flags & (APPEND | IMMUTABLE))) {
1099
error = EPERM;
1100
goto out_locked;
1101
}
1102
1103
/*
1104
* Ensure that we have enough memory to hold the new name, if it
1105
* has to be changed.
1106
*/
1107
if (fcnp->cn_namelen != tcnp->cn_namelen ||
1108
bcmp(fcnp->cn_nameptr, tcnp->cn_nameptr, fcnp->cn_namelen) != 0) {
1109
newname = malloc(tcnp->cn_namelen, M_TMPFSNAME, M_WAITOK);
1110
} else
1111
newname = NULL;
1112
1113
/*
1114
* If the node is being moved to another directory, we have to do
1115
* the move.
1116
*/
1117
if (fdnode != tdnode) {
1118
/*
1119
* In case we are moving a directory, we have to adjust its
1120
* parent to point to the new parent.
1121
*/
1122
if (de->td_node->tn_type == VDIR) {
1123
struct tmpfs_node *n;
1124
1125
TMPFS_NODE_LOCK(fnode);
1126
error = tmpfs_access_locked(fvp, fnode, VWRITE,
1127
tcnp->cn_cred);
1128
TMPFS_NODE_UNLOCK(fnode);
1129
if (error) {
1130
if (newname != NULL)
1131
free(newname, M_TMPFSNAME);
1132
goto out_locked;
1133
}
1134
1135
/*
1136
* Ensure the target directory is not a child of the
1137
* directory being moved. Otherwise, we'd end up
1138
* with stale nodes.
1139
*/
1140
n = tdnode;
1141
/*
1142
* TMPFS_LOCK guaranties that no nodes are freed while
1143
* traversing the list. Nodes can only be marked as
1144
* removed: tn_parent == NULL.
1145
*/
1146
TMPFS_LOCK(tmp);
1147
TMPFS_NODE_LOCK(n);
1148
while (n != n->tn_dir.tn_parent) {
1149
struct tmpfs_node *parent;
1150
1151
if (n == fnode) {
1152
TMPFS_NODE_UNLOCK(n);
1153
TMPFS_UNLOCK(tmp);
1154
error = EINVAL;
1155
if (newname != NULL)
1156
free(newname, M_TMPFSNAME);
1157
goto out_locked;
1158
}
1159
parent = n->tn_dir.tn_parent;
1160
TMPFS_NODE_UNLOCK(n);
1161
if (parent == NULL) {
1162
n = NULL;
1163
break;
1164
}
1165
TMPFS_NODE_LOCK(parent);
1166
if (parent->tn_dir.tn_parent == NULL) {
1167
TMPFS_NODE_UNLOCK(parent);
1168
n = NULL;
1169
break;
1170
}
1171
n = parent;
1172
}
1173
TMPFS_UNLOCK(tmp);
1174
if (n == NULL) {
1175
error = EINVAL;
1176
if (newname != NULL)
1177
free(newname, M_TMPFSNAME);
1178
goto out_locked;
1179
}
1180
TMPFS_NODE_UNLOCK(n);
1181
1182
/* Adjust the parent pointer. */
1183
TMPFS_VALIDATE_DIR(fnode);
1184
TMPFS_NODE_LOCK(de->td_node);
1185
de->td_node->tn_dir.tn_parent = tdnode;
1186
TMPFS_NODE_UNLOCK(de->td_node);
1187
1188
/*
1189
* As a result of changing the target of the '..'
1190
* entry, the link count of the source and target
1191
* directories has to be adjusted.
1192
*/
1193
TMPFS_NODE_LOCK(tdnode);
1194
TMPFS_ASSERT_LOCKED(tdnode);
1195
tdnode->tn_links++;
1196
TMPFS_NODE_UNLOCK(tdnode);
1197
1198
TMPFS_NODE_LOCK(fdnode);
1199
TMPFS_ASSERT_LOCKED(fdnode);
1200
fdnode->tn_links--;
1201
TMPFS_NODE_UNLOCK(fdnode);
1202
}
1203
}
1204
1205
/*
1206
* Do the move: just remove the entry from the source directory
1207
* and insert it into the target one.
1208
*/
1209
tmpfs_dir_detach(fdvp, de);
1210
1211
if (fcnp->cn_flags & DOWHITEOUT)
1212
tmpfs_dir_whiteout_add(fdvp, fcnp);
1213
if (tcnp->cn_flags & ISWHITEOUT)
1214
tmpfs_dir_whiteout_remove(tdvp, tcnp);
1215
1216
/*
1217
* If the name has changed, we need to make it effective by changing
1218
* it in the directory entry.
1219
*/
1220
if (newname != NULL) {
1221
MPASS(tcnp->cn_namelen <= MAXNAMLEN);
1222
1223
free(de->ud.td_name, M_TMPFSNAME);
1224
de->ud.td_name = newname;
1225
tmpfs_dirent_init(de, tcnp->cn_nameptr, tcnp->cn_namelen);
1226
1227
fnode->tn_status |= TMPFS_NODE_CHANGED;
1228
tdnode->tn_status |= TMPFS_NODE_MODIFIED;
1229
}
1230
1231
/*
1232
* If we are overwriting an entry, we have to remove the old one
1233
* from the target directory.
1234
*/
1235
if (tvp != NULL) {
1236
struct tmpfs_dirent *tde;
1237
1238
/* Remove the old entry from the target directory. */
1239
tde = tmpfs_dir_lookup(tdnode, tnode, tcnp);
1240
tmpfs_dir_detach(tdvp, tde);
1241
1242
/*
1243
* If we are overwriting a directory, per the ENOTEMPTY check
1244
* above it must either be empty or contain only whiteout
1245
* entries. In the latter case (which can only happen if
1246
* IGNOREWHITEOUT was passed in tcnp->cn_flags), clear the
1247
* whiteout entries to avoid leaking memory.
1248
*/
1249
if (tnode->tn_type == VDIR && tnode->tn_size > 0)
1250
tmpfs_dir_clear_whiteouts(tvp);
1251
1252
/* Update node's ctime because of possible hardlinks. */
1253
tnode->tn_status |= TMPFS_NODE_CHANGED;
1254
tmpfs_update(tvp);
1255
1256
/*
1257
* Free the directory entry we just deleted. Note that the
1258
* node referred by it will not be removed until the vnode is
1259
* really reclaimed.
1260
*/
1261
tmpfs_free_dirent(VFS_TO_TMPFS(tvp->v_mount), tde);
1262
}
1263
1264
tmpfs_dir_attach(tdvp, de);
1265
1266
if (tmpfs_use_nc(fvp)) {
1267
cache_vop_rename(fdvp, fvp, tdvp, tvp, fcnp, tcnp);
1268
}
1269
1270
error = 0;
1271
1272
out_locked:
1273
if (fdvp != tdvp && fdvp != tvp)
1274
VOP_UNLOCK(fdvp);
1275
1276
out:
1277
if (want_seqc_end) {
1278
if (tvp != NULL)
1279
vn_seqc_write_end(tvp);
1280
vn_seqc_write_end(tdvp);
1281
vn_seqc_write_end(fvp);
1282
vn_seqc_write_end(fdvp);
1283
}
1284
1285
/*
1286
* Release target nodes.
1287
* XXX: I don't understand when tdvp can be the same as tvp, but
1288
* other code takes care of this...
1289
*/
1290
if (tdvp == tvp)
1291
vrele(tdvp);
1292
else
1293
vput(tdvp);
1294
if (tvp != NULL)
1295
vput(tvp);
1296
1297
/* Release source nodes. */
1298
vrele(fdvp);
1299
vrele(fvp);
1300
1301
return (error);
1302
}
1303
1304
static int
1305
tmpfs_mkdir(struct vop_mkdir_args *v)
1306
{
1307
struct vnode *dvp = v->a_dvp;
1308
struct vnode **vpp = v->a_vpp;
1309
struct componentname *cnp = v->a_cnp;
1310
struct vattr *vap = v->a_vap;
1311
1312
MPASS(vap->va_type == VDIR);
1313
1314
return (tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL));
1315
}
1316
1317
static int
1318
tmpfs_rmdir(struct vop_rmdir_args *v)
1319
{
1320
struct vnode *dvp = v->a_dvp;
1321
struct vnode *vp = v->a_vp;
1322
struct componentname *cnp = v->a_cnp;
1323
1324
int error;
1325
struct tmpfs_dirent *de;
1326
struct tmpfs_mount *tmp;
1327
struct tmpfs_node *dnode;
1328
struct tmpfs_node *node;
1329
1330
tmp = VFS_TO_TMPFS(dvp->v_mount);
1331
dnode = VP_TO_TMPFS_DIR(dvp);
1332
node = VP_TO_TMPFS_DIR(vp);
1333
1334
/*
1335
* Directories with more than two non-whiteout entries ('.' and '..')
1336
* cannot be removed.
1337
*/
1338
if (node->tn_size != 0 &&
1339
((cnp->cn_flags & IGNOREWHITEOUT) == 0 ||
1340
node->tn_size > node->tn_dir.tn_wht_size)) {
1341
error = ENOTEMPTY;
1342
goto out;
1343
}
1344
1345
/* Check flags to see if we are allowed to remove the directory. */
1346
if ((dnode->tn_flags & APPEND)
1347
|| (node->tn_flags & (NOUNLINK | IMMUTABLE | APPEND))) {
1348
error = EPERM;
1349
goto out;
1350
}
1351
1352
/* This invariant holds only if we are not trying to remove "..".
1353
* We checked for that above so this is safe now. */
1354
MPASS(node->tn_dir.tn_parent == dnode);
1355
1356
/* Get the directory entry associated with node (vp). This was
1357
* filled by tmpfs_lookup while looking up the entry. */
1358
de = tmpfs_dir_lookup(dnode, node, cnp);
1359
MPASS(TMPFS_DIRENT_MATCHES(de,
1360
cnp->cn_nameptr,
1361
cnp->cn_namelen));
1362
1363
/* Detach the directory entry from the directory (dnode). */
1364
tmpfs_dir_detach(dvp, de);
1365
1366
/*
1367
* If we are removing a directory, per the ENOTEMPTY check above it
1368
* must either be empty or contain only whiteout entries. In the
1369
* latter case (which can only happen if IGNOREWHITEOUT was passed
1370
* in cnp->cn_flags), clear the whiteout entries to avoid leaking
1371
* memory.
1372
*/
1373
if (node->tn_size > 0)
1374
tmpfs_dir_clear_whiteouts(vp);
1375
1376
if (cnp->cn_flags & DOWHITEOUT)
1377
tmpfs_dir_whiteout_add(dvp, cnp);
1378
1379
/* No vnode should be allocated for this entry from this point */
1380
TMPFS_NODE_LOCK(node);
1381
node->tn_links--;
1382
node->tn_dir.tn_parent = NULL;
1383
node->tn_status |= TMPFS_NODE_CHANGED | TMPFS_NODE_MODIFIED;
1384
node->tn_accessed = true;
1385
1386
TMPFS_NODE_UNLOCK(node);
1387
1388
TMPFS_NODE_LOCK(dnode);
1389
dnode->tn_links--;
1390
dnode->tn_status |= TMPFS_NODE_CHANGED | TMPFS_NODE_MODIFIED;
1391
dnode->tn_accessed = true;
1392
TMPFS_NODE_UNLOCK(dnode);
1393
1394
if (tmpfs_use_nc(dvp)) {
1395
cache_vop_rmdir(dvp, vp);
1396
}
1397
1398
/* Free the directory entry we just deleted. Note that the node
1399
* referred by it will not be removed until the vnode is really
1400
* reclaimed. */
1401
tmpfs_free_dirent(tmp, de);
1402
1403
/* Release the deleted vnode (will destroy the node, notify
1404
* interested parties and clean it from the cache). */
1405
1406
dnode->tn_status |= TMPFS_NODE_CHANGED;
1407
tmpfs_update(dvp);
1408
1409
error = 0;
1410
1411
out:
1412
return (error);
1413
}
1414
1415
static int
1416
tmpfs_symlink(struct vop_symlink_args *v)
1417
{
1418
struct vnode *dvp = v->a_dvp;
1419
struct vnode **vpp = v->a_vpp;
1420
struct componentname *cnp = v->a_cnp;
1421
struct vattr *vap = v->a_vap;
1422
const char *target = v->a_target;
1423
1424
#ifdef notyet /* XXX FreeBSD BUG: kern_symlink is not setting VLNK */
1425
MPASS(vap->va_type == VLNK);
1426
#else
1427
vap->va_type = VLNK;
1428
#endif
1429
1430
return (tmpfs_alloc_file(dvp, vpp, vap, cnp, target));
1431
}
1432
1433
static int
1434
tmpfs_readdir(struct vop_readdir_args *va)
1435
{
1436
struct vnode *vp;
1437
struct uio *uio;
1438
struct tmpfs_mount *tm;
1439
struct tmpfs_node *node;
1440
uint64_t **cookies;
1441
int *eofflag, *ncookies;
1442
ssize_t startresid;
1443
int error, maxcookies;
1444
1445
vp = va->a_vp;
1446
uio = va->a_uio;
1447
eofflag = va->a_eofflag;
1448
cookies = va->a_cookies;
1449
ncookies = va->a_ncookies;
1450
1451
/* This operation only makes sense on directory nodes. */
1452
if (vp->v_type != VDIR)
1453
return (ENOTDIR);
1454
1455
maxcookies = 0;
1456
node = VP_TO_TMPFS_DIR(vp);
1457
tm = VFS_TO_TMPFS(vp->v_mount);
1458
1459
startresid = uio->uio_resid;
1460
1461
/* Allocate cookies for NFS and compat modules. */
1462
if (cookies != NULL && ncookies != NULL) {
1463
maxcookies = howmany(node->tn_size,
1464
sizeof(struct tmpfs_dirent)) + 2;
1465
*cookies = malloc(maxcookies * sizeof(**cookies), M_TEMP,
1466
M_WAITOK);
1467
*ncookies = 0;
1468
}
1469
1470
if (cookies == NULL)
1471
error = tmpfs_dir_getdents(tm, node, uio, 0, NULL, NULL);
1472
else
1473
error = tmpfs_dir_getdents(tm, node, uio, maxcookies, *cookies,
1474
ncookies);
1475
1476
/* Buffer was filled without hitting EOF. */
1477
if (error == EJUSTRETURN)
1478
error = (uio->uio_resid != startresid) ? 0 : EINVAL;
1479
1480
if (error != 0 && cookies != NULL && ncookies != NULL) {
1481
free(*cookies, M_TEMP);
1482
*cookies = NULL;
1483
*ncookies = 0;
1484
}
1485
1486
if (eofflag != NULL)
1487
*eofflag =
1488
(error == 0 && uio->uio_offset == TMPFS_DIRCOOKIE_EOF);
1489
1490
return (error);
1491
}
1492
1493
static int
1494
tmpfs_readlink(struct vop_readlink_args *v)
1495
{
1496
struct vnode *vp = v->a_vp;
1497
struct uio *uio = v->a_uio;
1498
1499
int error;
1500
struct tmpfs_node *node;
1501
1502
MPASS(uio->uio_offset == 0);
1503
MPASS(vp->v_type == VLNK);
1504
1505
node = VP_TO_TMPFS_NODE(vp);
1506
1507
error = uiomove(node->tn_link_target, MIN(node->tn_size, uio->uio_resid),
1508
uio);
1509
tmpfs_set_accessed(VFS_TO_TMPFS(vp->v_mount), node);
1510
1511
return (error);
1512
}
1513
1514
/*
1515
* VOP_FPLOOKUP_SYMLINK routines are subject to special circumstances, see
1516
* the comment above cache_fplookup for details.
1517
*
1518
* Check tmpfs_alloc_node for tmpfs-specific synchronisation notes.
1519
*/
1520
static int
1521
tmpfs_fplookup_symlink(struct vop_fplookup_symlink_args *v)
1522
{
1523
struct vnode *vp;
1524
struct tmpfs_node *node;
1525
char *symlink;
1526
1527
vp = v->a_vp;
1528
node = VP_TO_TMPFS_NODE_SMR(vp);
1529
if (__predict_false(node == NULL))
1530
return (EAGAIN);
1531
if (!atomic_load_char(&node->tn_link_smr))
1532
return (EAGAIN);
1533
symlink = atomic_load_ptr(&node->tn_link_target);
1534
if (symlink == NULL)
1535
return (EAGAIN);
1536
1537
return (cache_symlink_resolve(v->a_fpl, symlink, node->tn_size));
1538
}
1539
1540
static int
1541
tmpfs_inactive(struct vop_inactive_args *v)
1542
{
1543
struct vnode *vp;
1544
struct tmpfs_node *node;
1545
1546
vp = v->a_vp;
1547
node = VP_TO_TMPFS_NODE(vp);
1548
if (node->tn_links == 0)
1549
vrecycle(vp);
1550
else
1551
tmpfs_check_mtime(vp);
1552
return (0);
1553
}
1554
1555
static int
1556
tmpfs_need_inactive(struct vop_need_inactive_args *ap)
1557
{
1558
struct vnode *vp;
1559
struct tmpfs_node *node;
1560
struct vm_object *obj;
1561
1562
vp = ap->a_vp;
1563
node = VP_TO_TMPFS_NODE(vp);
1564
if (node->tn_links == 0)
1565
goto need;
1566
if (vp->v_type == VREG) {
1567
obj = vp->v_object;
1568
if (obj->generation != obj->cleangeneration)
1569
goto need;
1570
}
1571
return (0);
1572
need:
1573
return (1);
1574
}
1575
1576
int
1577
tmpfs_reclaim(struct vop_reclaim_args *v)
1578
{
1579
struct vnode *vp;
1580
struct tmpfs_mount *tmp;
1581
struct tmpfs_node *node;
1582
bool unlock;
1583
1584
vp = v->a_vp;
1585
node = VP_TO_TMPFS_NODE(vp);
1586
tmp = VFS_TO_TMPFS(vp->v_mount);
1587
1588
if (vp->v_type == VREG)
1589
tmpfs_destroy_vobject(vp, node->tn_reg.tn_aobj);
1590
vp->v_object = NULL;
1591
1592
TMPFS_LOCK(tmp);
1593
TMPFS_NODE_LOCK(node);
1594
tmpfs_free_vp(vp);
1595
1596
/*
1597
* If the node referenced by this vnode was deleted by the user,
1598
* we must free its associated data structures (now that the vnode
1599
* is being reclaimed).
1600
*/
1601
unlock = true;
1602
if (node->tn_links == 0 &&
1603
(node->tn_vpstate & TMPFS_VNODE_ALLOCATING) == 0) {
1604
node->tn_vpstate = TMPFS_VNODE_DOOMED;
1605
unlock = !tmpfs_free_node_locked(tmp, node, true);
1606
}
1607
1608
if (unlock) {
1609
TMPFS_NODE_UNLOCK(node);
1610
TMPFS_UNLOCK(tmp);
1611
}
1612
1613
MPASS(vp->v_data == NULL);
1614
return (0);
1615
}
1616
1617
int
1618
tmpfs_print(struct vop_print_args *v)
1619
{
1620
struct vnode *vp = v->a_vp;
1621
1622
struct tmpfs_node *node;
1623
1624
node = VP_TO_TMPFS_NODE(vp);
1625
1626
printf("tag VT_TMPFS, tmpfs_node %p, flags 0x%lx, links %jd\n",
1627
node, node->tn_flags, (uintmax_t)node->tn_links);
1628
printf("\tmode 0%o, owner %d, group %d, size %jd, status 0x%x\n",
1629
node->tn_mode, node->tn_uid, node->tn_gid,
1630
(intmax_t)node->tn_size, node->tn_status);
1631
1632
if (vp->v_type == VFIFO)
1633
fifo_printinfo(vp);
1634
1635
printf("\n");
1636
1637
return (0);
1638
}
1639
1640
int
1641
tmpfs_pathconf(struct vop_pathconf_args *v)
1642
{
1643
struct vnode *vp = v->a_vp;
1644
int name = v->a_name;
1645
long *retval = v->a_retval;
1646
1647
int error;
1648
1649
error = 0;
1650
1651
switch (name) {
1652
case _PC_LINK_MAX:
1653
*retval = TMPFS_LINK_MAX;
1654
break;
1655
1656
case _PC_SYMLINK_MAX:
1657
*retval = MAXPATHLEN;
1658
break;
1659
1660
case _PC_NAME_MAX:
1661
*retval = NAME_MAX;
1662
break;
1663
1664
case _PC_PIPE_BUF:
1665
if (vp->v_type == VDIR || vp->v_type == VFIFO)
1666
*retval = PIPE_BUF;
1667
else
1668
error = EINVAL;
1669
break;
1670
1671
case _PC_CHOWN_RESTRICTED:
1672
*retval = 1;
1673
break;
1674
1675
case _PC_NO_TRUNC:
1676
*retval = 1;
1677
break;
1678
1679
case _PC_SYNC_IO:
1680
*retval = 1;
1681
break;
1682
1683
case _PC_FILESIZEBITS:
1684
*retval = 64;
1685
break;
1686
1687
case _PC_MIN_HOLE_SIZE:
1688
*retval = PAGE_SIZE;
1689
break;
1690
1691
case _PC_HAS_HIDDENSYSTEM:
1692
*retval = 1;
1693
break;
1694
1695
default:
1696
error = vop_stdpathconf(v);
1697
}
1698
1699
return (error);
1700
}
1701
1702
static int
1703
tmpfs_vptofh(struct vop_vptofh_args *ap)
1704
/*
1705
vop_vptofh {
1706
IN struct vnode *a_vp;
1707
IN struct fid *a_fhp;
1708
};
1709
*/
1710
{
1711
struct tmpfs_fid_data *const tfd = (struct tmpfs_fid_data *)ap->a_fhp;
1712
struct tmpfs_node *node;
1713
_Static_assert(sizeof(struct tmpfs_fid_data) <= sizeof(struct fid),
1714
"struct tmpfs_fid_data cannot be larger than struct fid");
1715
1716
node = VP_TO_TMPFS_NODE(ap->a_vp);
1717
tfd->tfd_len = sizeof(*tfd);
1718
tfd->tfd_gen = node->tn_gen;
1719
tfd->tfd_id = node->tn_id;
1720
1721
return (0);
1722
}
1723
1724
static int
1725
tmpfs_whiteout(struct vop_whiteout_args *ap)
1726
{
1727
struct vnode *dvp = ap->a_dvp;
1728
struct componentname *cnp = ap->a_cnp;
1729
struct tmpfs_dirent *de;
1730
1731
switch (ap->a_flags) {
1732
case LOOKUP:
1733
return (0);
1734
case CREATE:
1735
de = tmpfs_dir_lookup(VP_TO_TMPFS_DIR(dvp), NULL, cnp);
1736
if (de != NULL)
1737
return (de->td_node == NULL ? 0 : EEXIST);
1738
return (tmpfs_dir_whiteout_add(dvp, cnp));
1739
case DELETE:
1740
tmpfs_dir_whiteout_remove(dvp, cnp);
1741
return (0);
1742
default:
1743
panic("tmpfs_whiteout: unknown op");
1744
}
1745
}
1746
1747
static int
1748
tmpfs_vptocnp_dir(struct tmpfs_node *tn, struct tmpfs_node *tnp,
1749
struct tmpfs_dirent **pde)
1750
{
1751
struct tmpfs_dir_cursor dc;
1752
struct tmpfs_dirent *de;
1753
1754
for (de = tmpfs_dir_first(tnp, &dc); de != NULL;
1755
de = tmpfs_dir_next(tnp, &dc)) {
1756
if (de->td_node == tn) {
1757
*pde = de;
1758
return (0);
1759
}
1760
}
1761
return (ENOENT);
1762
}
1763
1764
static int
1765
tmpfs_vptocnp_fill(struct vnode *vp, struct tmpfs_node *tn,
1766
struct tmpfs_node *tnp, char *buf, size_t *buflen, struct vnode **dvp)
1767
{
1768
struct tmpfs_dirent *de;
1769
int error, i;
1770
1771
error = vn_vget_ino_gen(vp, tmpfs_vn_get_ino_alloc, tnp, LK_SHARED,
1772
dvp);
1773
if (error != 0)
1774
return (error);
1775
error = tmpfs_vptocnp_dir(tn, tnp, &de);
1776
if (error == 0) {
1777
i = *buflen;
1778
i -= de->td_namelen;
1779
if (i < 0) {
1780
error = ENOMEM;
1781
} else {
1782
bcopy(de->ud.td_name, buf + i, de->td_namelen);
1783
*buflen = i;
1784
}
1785
}
1786
if (error == 0) {
1787
if (vp != *dvp)
1788
VOP_UNLOCK(*dvp);
1789
} else {
1790
if (vp != *dvp)
1791
vput(*dvp);
1792
else
1793
vrele(vp);
1794
}
1795
return (error);
1796
}
1797
1798
static int
1799
tmpfs_vptocnp(struct vop_vptocnp_args *ap)
1800
{
1801
struct vnode *vp, **dvp;
1802
struct tmpfs_node *tn, *tnp, *tnp1;
1803
struct tmpfs_dirent *de;
1804
struct tmpfs_mount *tm;
1805
char *buf;
1806
size_t *buflen;
1807
int error;
1808
1809
vp = ap->a_vp;
1810
dvp = ap->a_vpp;
1811
buf = ap->a_buf;
1812
buflen = ap->a_buflen;
1813
1814
tm = VFS_TO_TMPFS(vp->v_mount);
1815
tn = VP_TO_TMPFS_NODE(vp);
1816
if (tn->tn_type == VDIR) {
1817
tnp = tn->tn_dir.tn_parent;
1818
if (tnp == NULL)
1819
return (ENOENT);
1820
tmpfs_ref_node(tnp);
1821
error = tmpfs_vptocnp_fill(vp, tn, tn->tn_dir.tn_parent, buf,
1822
buflen, dvp);
1823
tmpfs_free_node(tm, tnp);
1824
return (error);
1825
}
1826
restart:
1827
TMPFS_LOCK(tm);
1828
restart_locked:
1829
LIST_FOREACH_SAFE(tnp, &tm->tm_nodes_used, tn_entries, tnp1) {
1830
if (tnp->tn_type != VDIR)
1831
continue;
1832
TMPFS_NODE_LOCK(tnp);
1833
tmpfs_ref_node(tnp);
1834
1835
/*
1836
* tn_vnode cannot be instantiated while we hold the
1837
* node lock, so the directory cannot be changed while
1838
* we iterate over it. Do this to avoid instantiating
1839
* vnode for directories which cannot point to our
1840
* node.
1841
*/
1842
error = tnp->tn_vnode == NULL ? tmpfs_vptocnp_dir(tn, tnp,
1843
&de) : 0;
1844
1845
if (error == 0) {
1846
TMPFS_NODE_UNLOCK(tnp);
1847
TMPFS_UNLOCK(tm);
1848
error = tmpfs_vptocnp_fill(vp, tn, tnp, buf, buflen,
1849
dvp);
1850
if (error == 0) {
1851
tmpfs_free_node(tm, tnp);
1852
return (0);
1853
}
1854
if (VN_IS_DOOMED(vp)) {
1855
tmpfs_free_node(tm, tnp);
1856
return (ENOENT);
1857
}
1858
TMPFS_LOCK(tm);
1859
TMPFS_NODE_LOCK(tnp);
1860
}
1861
if (tmpfs_free_node_locked(tm, tnp, false)) {
1862
goto restart;
1863
} else {
1864
KASSERT(tnp->tn_refcount > 0,
1865
("node %p refcount zero", tnp));
1866
if (tnp->tn_attached) {
1867
tnp1 = LIST_NEXT(tnp, tn_entries);
1868
TMPFS_NODE_UNLOCK(tnp);
1869
} else {
1870
TMPFS_NODE_UNLOCK(tnp);
1871
goto restart_locked;
1872
}
1873
}
1874
}
1875
TMPFS_UNLOCK(tm);
1876
return (ENOENT);
1877
}
1878
1879
void
1880
tmpfs_extattr_free(struct tmpfs_extattr *ea)
1881
{
1882
free(ea->ea_name, M_TMPFSEA);
1883
free(ea->ea_value, M_TMPFSEA);
1884
free(ea, M_TMPFSEA);
1885
}
1886
1887
static bool
1888
tmpfs_extattr_update_mem(struct tmpfs_mount *tmp, ssize_t size)
1889
{
1890
TMPFS_LOCK(tmp);
1891
if (size > 0 &&
1892
!tmpfs_pages_check_avail(tmp, howmany(size, PAGE_SIZE))) {
1893
TMPFS_UNLOCK(tmp);
1894
return (false);
1895
}
1896
if (tmp->tm_ea_memory_inuse + size > tmp->tm_ea_memory_max) {
1897
TMPFS_UNLOCK(tmp);
1898
return (false);
1899
}
1900
tmp->tm_ea_memory_inuse += size;
1901
TMPFS_UNLOCK(tmp);
1902
return (true);
1903
}
1904
1905
static int
1906
tmpfs_deleteextattr(struct vop_deleteextattr_args *ap)
1907
{
1908
struct vnode *vp = ap->a_vp;
1909
struct tmpfs_mount *tmp;
1910
struct tmpfs_node *node;
1911
struct tmpfs_extattr *ea;
1912
size_t namelen;
1913
ssize_t diff;
1914
int error;
1915
1916
node = VP_TO_TMPFS_NODE(vp);
1917
tmp = VFS_TO_TMPFS(vp->v_mount);
1918
if (VN_ISDEV(ap->a_vp))
1919
return (EOPNOTSUPP);
1920
error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace,
1921
ap->a_cred, ap->a_td, VWRITE);
1922
if (error != 0)
1923
return (error);
1924
if (ap->a_name == NULL || ap->a_name[0] == '\0')
1925
return (EINVAL);
1926
namelen = strlen(ap->a_name);
1927
if (namelen > EXTATTR_MAXNAMELEN)
1928
return (EINVAL);
1929
1930
LIST_FOREACH(ea, &node->tn_extattrs, ea_extattrs) {
1931
if (ea->ea_namespace == ap->a_attrnamespace &&
1932
namelen == ea->ea_namelen &&
1933
memcmp(ap->a_name, ea->ea_name, namelen) == 0)
1934
break;
1935
}
1936
1937
if (ea == NULL)
1938
return (ENOATTR);
1939
LIST_REMOVE(ea, ea_extattrs);
1940
diff = -(sizeof(struct tmpfs_extattr) + namelen + ea->ea_size);
1941
tmpfs_extattr_update_mem(tmp, diff);
1942
tmpfs_extattr_free(ea);
1943
return (0);
1944
}
1945
1946
static int
1947
tmpfs_getextattr(struct vop_getextattr_args *ap)
1948
{
1949
struct vnode *vp = ap->a_vp;
1950
struct tmpfs_node *node;
1951
struct tmpfs_extattr *ea;
1952
size_t namelen;
1953
int error;
1954
1955
node = VP_TO_TMPFS_NODE(vp);
1956
if (VN_ISDEV(ap->a_vp))
1957
return (EOPNOTSUPP);
1958
error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace,
1959
ap->a_cred, ap->a_td, VREAD);
1960
if (error != 0)
1961
return (error);
1962
if (ap->a_name == NULL || ap->a_name[0] == '\0')
1963
return (EINVAL);
1964
namelen = strlen(ap->a_name);
1965
if (namelen > EXTATTR_MAXNAMELEN)
1966
return (EINVAL);
1967
1968
LIST_FOREACH(ea, &node->tn_extattrs, ea_extattrs) {
1969
if (ea->ea_namespace == ap->a_attrnamespace &&
1970
namelen == ea->ea_namelen &&
1971
memcmp(ap->a_name, ea->ea_name, namelen) == 0)
1972
break;
1973
}
1974
1975
if (ea == NULL)
1976
return (ENOATTR);
1977
if (ap->a_size != NULL)
1978
*ap->a_size = ea->ea_size;
1979
if (ap->a_uio != NULL && ea->ea_size != 0)
1980
error = uiomove(ea->ea_value, ea->ea_size, ap->a_uio);
1981
return (error);
1982
}
1983
1984
static int
1985
tmpfs_listextattr(struct vop_listextattr_args *ap)
1986
{
1987
struct vnode *vp = ap->a_vp;
1988
struct tmpfs_node *node;
1989
struct tmpfs_extattr *ea;
1990
int error;
1991
1992
node = VP_TO_TMPFS_NODE(vp);
1993
if (VN_ISDEV(ap->a_vp))
1994
return (EOPNOTSUPP);
1995
error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace,
1996
ap->a_cred, ap->a_td, VREAD);
1997
if (error != 0)
1998
return (error);
1999
if (ap->a_size != NULL)
2000
*ap->a_size = 0;
2001
2002
LIST_FOREACH(ea, &node->tn_extattrs, ea_extattrs) {
2003
if (ea->ea_namespace != ap->a_attrnamespace)
2004
continue;
2005
if (ap->a_size != NULL)
2006
*ap->a_size += ea->ea_namelen + 1;
2007
if (ap->a_uio != NULL) {
2008
error = uiomove(&ea->ea_namelen, 1, ap->a_uio);
2009
if (error != 0)
2010
break;
2011
error = uiomove(ea->ea_name, ea->ea_namelen, ap->a_uio);
2012
if (error != 0)
2013
break;
2014
}
2015
}
2016
2017
return (error);
2018
}
2019
2020
static int
2021
tmpfs_setextattr(struct vop_setextattr_args *ap)
2022
{
2023
struct vnode *vp = ap->a_vp;
2024
struct tmpfs_mount *tmp;
2025
struct tmpfs_node *node;
2026
struct tmpfs_extattr *ea;
2027
struct tmpfs_extattr *new_ea;
2028
size_t attr_size;
2029
size_t namelen;
2030
ssize_t diff;
2031
int error;
2032
2033
node = VP_TO_TMPFS_NODE(vp);
2034
tmp = VFS_TO_TMPFS(vp->v_mount);
2035
attr_size = ap->a_uio->uio_resid;
2036
diff = 0;
2037
if (VN_ISDEV(ap->a_vp))
2038
return (EOPNOTSUPP);
2039
error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace,
2040
ap->a_cred, ap->a_td, VWRITE);
2041
if (error != 0)
2042
return (error);
2043
if (ap->a_name == NULL || ap->a_name[0] == '\0')
2044
return (EINVAL);
2045
namelen = strlen(ap->a_name);
2046
if (namelen > EXTATTR_MAXNAMELEN)
2047
return (EINVAL);
2048
2049
LIST_FOREACH(ea, &node->tn_extattrs, ea_extattrs) {
2050
if (ea->ea_namespace == ap->a_attrnamespace &&
2051
namelen == ea->ea_namelen &&
2052
memcmp(ap->a_name, ea->ea_name, namelen) == 0) {
2053
diff -= sizeof(struct tmpfs_extattr) + ea->ea_namelen +
2054
ea->ea_size;
2055
break;
2056
}
2057
}
2058
2059
diff += sizeof(struct tmpfs_extattr) + namelen + attr_size;
2060
if (!tmpfs_extattr_update_mem(tmp, diff))
2061
return (ENOSPC);
2062
new_ea = malloc(sizeof(struct tmpfs_extattr), M_TMPFSEA, M_WAITOK);
2063
new_ea->ea_namespace = ap->a_attrnamespace;
2064
new_ea->ea_name = malloc(namelen, M_TMPFSEA, M_WAITOK);
2065
new_ea->ea_namelen = namelen;
2066
memcpy(new_ea->ea_name, ap->a_name, namelen);
2067
if (attr_size != 0) {
2068
new_ea->ea_value = malloc(attr_size, M_TMPFSEA, M_WAITOK);
2069
new_ea->ea_size = attr_size;
2070
error = uiomove(new_ea->ea_value, attr_size, ap->a_uio);
2071
} else {
2072
new_ea->ea_value = NULL;
2073
new_ea->ea_size = 0;
2074
}
2075
if (error != 0) {
2076
tmpfs_extattr_update_mem(tmp, -diff);
2077
tmpfs_extattr_free(new_ea);
2078
return (error);
2079
}
2080
if (ea != NULL) {
2081
LIST_REMOVE(ea, ea_extattrs);
2082
tmpfs_extattr_free(ea);
2083
}
2084
LIST_INSERT_HEAD(&node->tn_extattrs, new_ea, ea_extattrs);
2085
return (0);
2086
}
2087
2088
static off_t
2089
tmpfs_seek_data_locked(vm_object_t obj, off_t noff)
2090
{
2091
vm_pindex_t p;
2092
2093
p = swap_pager_seek_data(obj, OFF_TO_IDX(noff));
2094
return (p == OFF_TO_IDX(noff) ? noff : IDX_TO_OFF(p));
2095
}
2096
2097
static int
2098
tmpfs_seek_clamp(struct tmpfs_node *tn, off_t *noff, bool seekdata)
2099
{
2100
if (*noff < tn->tn_size)
2101
return (0);
2102
if (seekdata)
2103
return (ENXIO);
2104
*noff = tn->tn_size;
2105
return (0);
2106
}
2107
2108
static off_t
2109
tmpfs_seek_hole_locked(vm_object_t obj, off_t noff)
2110
{
2111
2112
return (IDX_TO_OFF(swap_pager_seek_hole(obj, OFF_TO_IDX(noff))));
2113
}
2114
2115
static int
2116
tmpfs_seek_datahole(struct vnode *vp, off_t *off, bool seekdata)
2117
{
2118
struct tmpfs_node *tn;
2119
vm_object_t obj;
2120
off_t noff;
2121
int error;
2122
2123
if (vp->v_type != VREG)
2124
return (ENOTTY);
2125
tn = VP_TO_TMPFS_NODE(vp);
2126
noff = *off;
2127
if (noff < 0)
2128
return (ENXIO);
2129
error = tmpfs_seek_clamp(tn, &noff, seekdata);
2130
if (error != 0)
2131
return (error);
2132
obj = tn->tn_reg.tn_aobj;
2133
2134
VM_OBJECT_RLOCK(obj);
2135
noff = seekdata ? tmpfs_seek_data_locked(obj, noff) :
2136
tmpfs_seek_hole_locked(obj, noff);
2137
VM_OBJECT_RUNLOCK(obj);
2138
2139
error = tmpfs_seek_clamp(tn, &noff, seekdata);
2140
if (error == 0)
2141
*off = noff;
2142
return (error);
2143
}
2144
2145
static int
2146
tmpfs_ioctl(struct vop_ioctl_args *ap)
2147
{
2148
struct vnode *vp = ap->a_vp;
2149
int error = 0;
2150
2151
switch (ap->a_command) {
2152
case FIOSEEKDATA:
2153
case FIOSEEKHOLE:
2154
error = vn_lock(vp, LK_SHARED);
2155
if (error != 0) {
2156
error = EBADF;
2157
break;
2158
}
2159
error = tmpfs_seek_datahole(vp, (off_t *)ap->a_data,
2160
ap->a_command == FIOSEEKDATA);
2161
VOP_UNLOCK(vp);
2162
break;
2163
default:
2164
error = ENOTTY;
2165
break;
2166
}
2167
return (error);
2168
}
2169
2170
/*
2171
* Vnode operations vector used for files stored in a tmpfs file system.
2172
*/
2173
struct vop_vector tmpfs_vnodeop_entries = {
2174
.vop_default = &default_vnodeops,
2175
.vop_lookup = vfs_cache_lookup,
2176
.vop_cachedlookup = tmpfs_cached_lookup,
2177
.vop_create = tmpfs_create,
2178
.vop_mknod = tmpfs_mknod,
2179
.vop_open = tmpfs_open,
2180
.vop_close = tmpfs_close,
2181
.vop_fplookup_vexec = tmpfs_fplookup_vexec,
2182
.vop_fplookup_symlink = tmpfs_fplookup_symlink,
2183
.vop_access = tmpfs_access,
2184
.vop_stat = tmpfs_stat,
2185
.vop_getattr = tmpfs_getattr,
2186
.vop_setattr = tmpfs_setattr,
2187
.vop_read = tmpfs_read,
2188
.vop_read_pgcache = tmpfs_read_pgcache,
2189
.vop_write = tmpfs_write,
2190
.vop_deallocate = tmpfs_deallocate,
2191
.vop_fsync = tmpfs_fsync,
2192
.vop_remove = tmpfs_remove,
2193
.vop_link = tmpfs_link,
2194
.vop_rename = tmpfs_rename,
2195
.vop_mkdir = tmpfs_mkdir,
2196
.vop_rmdir = tmpfs_rmdir,
2197
.vop_symlink = tmpfs_symlink,
2198
.vop_readdir = tmpfs_readdir,
2199
.vop_readlink = tmpfs_readlink,
2200
.vop_inactive = tmpfs_inactive,
2201
.vop_need_inactive = tmpfs_need_inactive,
2202
.vop_reclaim = tmpfs_reclaim,
2203
.vop_print = tmpfs_print,
2204
.vop_pathconf = tmpfs_pathconf,
2205
.vop_vptofh = tmpfs_vptofh,
2206
.vop_whiteout = tmpfs_whiteout,
2207
.vop_bmap = VOP_EOPNOTSUPP,
2208
.vop_vptocnp = tmpfs_vptocnp,
2209
.vop_lock1 = vop_lock,
2210
.vop_unlock = vop_unlock,
2211
.vop_islocked = vop_islocked,
2212
.vop_deleteextattr = tmpfs_deleteextattr,
2213
.vop_getextattr = tmpfs_getextattr,
2214
.vop_listextattr = tmpfs_listextattr,
2215
.vop_setextattr = tmpfs_setextattr,
2216
.vop_add_writecount = vop_stdadd_writecount_nomsync,
2217
.vop_ioctl = tmpfs_ioctl,
2218
};
2219
VFS_VOP_VECTOR_REGISTER(tmpfs_vnodeop_entries);
2220
2221
/*
2222
* Same vector for mounts which do not use namecache.
2223
*/
2224
struct vop_vector tmpfs_vnodeop_nonc_entries = {
2225
.vop_default = &tmpfs_vnodeop_entries,
2226
.vop_lookup = tmpfs_lookup,
2227
};
2228
VFS_VOP_VECTOR_REGISTER(tmpfs_vnodeop_nonc_entries);
2229
2230