diff options
-rw-r--r-- | include/sys/Makefile.am | 1 | ||||
-rw-r--r-- | include/sys/pathname.h | 70 | ||||
-rw-r--r-- | include/sys/zfs_vnops.h | 4 | ||||
-rw-r--r-- | lib/libzpool/Makefile.am | 1 | ||||
-rw-r--r-- | module/zfs/Makefile.in | 1 | ||||
-rw-r--r-- | module/zfs/pathname.c | 89 | ||||
-rw-r--r-- | module/zfs/zfs_replay.c | 4 | ||||
-rw-r--r-- | module/zfs/zfs_vnops.c | 21 | ||||
-rw-r--r-- | module/zfs/zpl_inode.c | 17 | ||||
-rw-r--r-- | module/zfs/zpl_xattr.c | 2 |
10 files changed, 178 insertions, 32 deletions
diff --git a/include/sys/Makefile.am b/include/sys/Makefile.am index 73e86d03b..98d7ad6fb 100644 --- a/include/sys/Makefile.am +++ b/include/sys/Makefile.am @@ -38,6 +38,7 @@ COMMON_H = \ $(top_srcdir)/include/sys/multilist.h \ $(top_srcdir)/include/sys/nvpair.h \ $(top_srcdir)/include/sys/nvpair_impl.h \ + $(top_srcdir)/include/sys/pathname.h \ $(top_srcdir)/include/sys/range_tree.h \ $(top_srcdir)/include/sys/refcount.h \ $(top_srcdir)/include/sys/rrwlock.h \ diff --git a/include/sys/pathname.h b/include/sys/pathname.h new file mode 100644 index 000000000..5db69b178 --- /dev/null +++ b/include/sys/pathname.h @@ -0,0 +1,70 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. + */ + +/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + +/* + * Portions of this source code were derived from Berkeley 4.3 BSD + * under license from the Regents of the University of California. + */ + +#ifndef _SYS_PATHNAME_H +#define _SYS_PATHNAME_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Pathname structure. + * System calls that operate on path names gather the path name + * from the system call into this structure and reduce it by + * peeling off translated components. If a symbolic link is + * encountered the new path name to be translated is also + * assembled in this structure. + * + * By convention pn_buf is not changed once it's been set to point + * to the underlying storage; routines which manipulate the pathname + * do so by changing pn_path and pn_pathlen. pn_pathlen is redundant + * since the path name is null-terminated, but is provided to make + * some computations faster. + */ +typedef struct pathname { + char *pn_buf; /* underlying storage */ + char *pn_path; /* remaining pathname */ + size_t pn_pathlen; /* remaining length */ + size_t pn_bufsize; /* total size of pn_buf */ +} pathname_t; + +extern void pn_alloc(struct pathname *); +extern void pn_alloc_sz(struct pathname *, size_t); +extern void pn_free(struct pathname *); + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_PATHNAME_H */ diff --git a/include/sys/zfs_vnops.h b/include/sys/zfs_vnops.h index c331035c5..157e7f9d5 100644 --- a/include/sys/zfs_vnops.h +++ b/include/sys/zfs_vnops.h @@ -47,7 +47,7 @@ extern int zfs_lookup(struct inode *dip, char *nm, struct inode **ipp, int flags, cred_t *cr, int *direntflags, pathname_t *realpnp); extern int zfs_create(struct inode *dip, char *name, vattr_t *vap, int excl, int mode, struct inode **ipp, cred_t *cr, int flag, vsecattr_t *vsecp); -extern int zfs_remove(struct inode *dip, char *name, cred_t *cr); +extern int zfs_remove(struct inode *dip, char *name, cred_t *cr, int flags); extern int zfs_mkdir(struct inode *dip, char *dirname, vattr_t *vap, struct inode **ipp, cred_t *cr, int flags, vsecattr_t *vsecp); extern int zfs_rmdir(struct inode *dip, char *name, struct inode *cwd, @@ -64,7 +64,7 @@ extern int zfs_symlink(struct inode *dip, char *name, vattr_t *vap, extern int zfs_follow_link(struct dentry *dentry, struct nameidata *nd); extern int zfs_readlink(struct inode *ip, uio_t *uio, cred_t *cr); extern int zfs_link(struct inode *tdip, struct inode *sip, - char *name, cred_t *cr); + char *name, cred_t *cr, int flags); extern void zfs_inactive(struct inode *ip); extern int zfs_space(struct inode *ip, int cmd, flock64_t *bfp, int flag, offset_t offset, cred_t *cr); diff --git a/lib/libzpool/Makefile.am b/lib/libzpool/Makefile.am index f45a57d71..3e59efa5c 100644 --- a/lib/libzpool/Makefile.am +++ b/lib/libzpool/Makefile.am @@ -64,6 +64,7 @@ KERNEL_C = \ lz4.c \ metaslab.c \ multilist.c \ + pathname.c \ range_tree.c \ refcount.c \ rrwlock.c \ diff --git a/module/zfs/Makefile.in b/module/zfs/Makefile.in index d3a0206c9..f33faf157 100644 --- a/module/zfs/Makefile.in +++ b/module/zfs/Makefile.in @@ -42,6 +42,7 @@ $(MODULE)-objs += lzjb.o $(MODULE)-objs += lz4.o $(MODULE)-objs += metaslab.o $(MODULE)-objs += multilist.o +$(MODULE)-objs += pathname.o $(MODULE)-objs += range_tree.o $(MODULE)-objs += refcount.o $(MODULE)-objs += rrwlock.o diff --git a/module/zfs/pathname.c b/module/zfs/pathname.c new file mode 100644 index 000000000..4ec132066 --- /dev/null +++ b/module/zfs/pathname.c @@ -0,0 +1,89 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + +/* + * University Copyright- Copyright (c) 1982, 1986, 1988 + * The Regents of the University of California + * All Rights Reserved + * + * University Acknowledgment- Portions of this document are derived from + * software developed by the University of California, Berkeley, and its + * contributors. + */ + + +#include <sys/types.h> +#include <sys/systm.h> +#include <sys/pathname.h> +#include <sys/kmem.h> + +/* + * Pathname utilities. + * + * In translating file names we copy each argument file + * name into a pathname structure where we operate on it. + * Each pathname structure can hold "pn_bufsize" characters + * including a terminating null, and operations here support + * allocating and freeing pathname structures, fetching + * strings from user space, getting the next character from + * a pathname, combining two pathnames (used in symbolic + * link processing), and peeling off the first component + * of a pathname. + */ + +/* + * Allocate contents of pathname structure. Structure is typically + * an automatic variable in calling routine for convenience. + * + * May sleep in the call to kmem_alloc() and so must not be called + * from interrupt level. + */ +void +pn_alloc(struct pathname *pnp) +{ + pn_alloc_sz(pnp, MAXPATHLEN); +} +void +pn_alloc_sz(struct pathname *pnp, size_t sz) +{ + pnp->pn_path = pnp->pn_buf = kmem_alloc(sz, KM_SLEEP); + pnp->pn_pathlen = 0; + pnp->pn_bufsize = sz; +} + +/* + * Free pathname resources. + */ +void +pn_free(struct pathname *pnp) +{ + /* pn_bufsize is usually MAXPATHLEN, but may not be */ + kmem_free(pnp->pn_buf, pnp->pn_bufsize); + pnp->pn_path = pnp->pn_buf = NULL; + pnp->pn_pathlen = pnp->pn_bufsize = 0; +} diff --git a/module/zfs/zfs_replay.c b/module/zfs/zfs_replay.c index 0ca1e03b5..b97a60ed8 100644 --- a/module/zfs/zfs_replay.c +++ b/module/zfs/zfs_replay.c @@ -548,7 +548,7 @@ zfs_replay_remove(zfs_sb_t *zsb, lr_remove_t *lr, boolean_t byteswap) switch ((int)lr->lr_common.lrc_txtype) { case TX_REMOVE: - error = zfs_remove(ZTOI(dzp), name, kcred); + error = zfs_remove(ZTOI(dzp), name, kcred, vflg); break; case TX_RMDIR: error = zfs_rmdir(ZTOI(dzp), name, NULL, kcred, vflg); @@ -584,7 +584,7 @@ zfs_replay_link(zfs_sb_t *zsb, lr_link_t *lr, boolean_t byteswap) if (lr->lr_common.lrc_txtype & TX_CI) vflg |= FIGNORECASE; - error = zfs_link(ZTOI(dzp), ZTOI(zp), name, kcred); + error = zfs_link(ZTOI(dzp), ZTOI(zp), name, kcred, vflg); iput(ZTOI(zp)); iput(ZTOI(dzp)); diff --git a/module/zfs/zfs_vnops.c b/module/zfs/zfs_vnops.c index 3c3d587e8..7a8cef017 100644 --- a/module/zfs/zfs_vnops.c +++ b/module/zfs/zfs_vnops.c @@ -1512,7 +1512,7 @@ uint64_t null_xattr = 0; /*ARGSUSED*/ int -zfs_remove(struct inode *dip, char *name, cred_t *cr) +zfs_remove(struct inode *dip, char *name, cred_t *cr, int flags) { znode_t *zp, *dzp = ITOZ(dip); znode_t *xzp; @@ -1528,9 +1528,7 @@ zfs_remove(struct inode *dip, char *name, cred_t *cr) boolean_t unlinked, toobig = FALSE; uint64_t txtype; pathname_t *realnmp = NULL; -#ifdef HAVE_PN_UTILS pathname_t realnm; -#endif /* HAVE_PN_UTILS */ int error; int zflg = ZEXISTS; boolean_t waited = B_FALSE; @@ -1539,13 +1537,11 @@ zfs_remove(struct inode *dip, char *name, cred_t *cr) ZFS_VERIFY_ZP(dzp); zilog = zsb->z_log; -#ifdef HAVE_PN_UTILS if (flags & FIGNORECASE) { zflg |= ZCILOOK; pn_alloc(&realnm); realnmp = &realnm; } -#endif /* HAVE_PN_UTILS */ top: xattr_obj = 0; @@ -1555,10 +1551,8 @@ top: */ if ((error = zfs_dirent_lock(&dl, dzp, name, &zp, zflg, NULL, realnmp))) { -#ifdef HAVE_PN_UTILS if (realnmp) pn_free(realnmp); -#endif /* HAVE_PN_UTILS */ ZFS_EXIT(zsb); return (error); } @@ -1642,10 +1636,8 @@ top: dmu_tx_abort(tx); goto top; } -#ifdef HAVE_PN_UTILS if (realnmp) pn_free(realnmp); -#endif /* HAVE_PN_UTILS */ dmu_tx_abort(tx); ZFS_EXIT(zsb); return (error); @@ -1711,18 +1703,14 @@ top: } txtype = TX_REMOVE; -#ifdef HAVE_PN_UTILS if (flags & FIGNORECASE) txtype |= TX_CI; -#endif /* HAVE_PN_UTILS */ zfs_log_remove(zilog, tx, txtype, dzp, name, obj); dmu_tx_commit(tx); out: -#ifdef HAVE_PN_UTILS if (realnmp) pn_free(realnmp); -#endif /* HAVE_PN_UTILS */ zfs_dirent_unlock(dl); zfs_inode_update(dzp); @@ -3782,7 +3770,8 @@ EXPORT_SYMBOL(zfs_readlink); */ /* ARGSUSED */ int -zfs_link(struct inode *tdip, struct inode *sip, char *name, cred_t *cr) +zfs_link(struct inode *tdip, struct inode *sip, char *name, cred_t *cr, + int flags) { znode_t *dzp = ITOZ(tdip); znode_t *tzp, *szp; @@ -3840,10 +3829,8 @@ zfs_link(struct inode *tdip, struct inode *sip, char *name, cred_t *cr) ZFS_EXIT(zsb); return (SET_ERROR(EILSEQ)); } -#ifdef HAVE_PN_UTILS if (flags & FIGNORECASE) zf |= ZCILOOK; -#endif /* HAVE_PN_UTILS */ /* * We do not support links between attributes and non-attributes @@ -3900,10 +3887,8 @@ top: if (error == 0) { uint64_t txtype = TX_LINK; -#ifdef HAVE_PN_UTILS if (flags & FIGNORECASE) txtype |= TX_CI; -#endif /* HAVE_PN_UTILS */ zfs_log_link(zilog, tx, txtype, dzp, szp, name); } diff --git a/module/zfs/zpl_inode.c b/module/zfs/zpl_inode.c index 7cf62783f..089e3a1bc 100644 --- a/module/zfs/zpl_inode.c +++ b/module/zfs/zpl_inode.c @@ -59,8 +59,7 @@ zpl_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) /* If we are a case insensitive fs, we need the real name */ if (zsb->z_case == ZFS_CASE_INSENSITIVE) { zfs_flags = FIGNORECASE; - pn.pn_bufsize = ZFS_MAXNAMELEN; - pn.pn_buf = kmem_zalloc(ZFS_MAXNAMELEN, KM_SLEEP); + pn_alloc(&pn); ppn = &pn; } @@ -83,7 +82,7 @@ zpl_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) * Fall through if the error is not ENOENT. Also free memory. */ if (ppn) { - kmem_free(pn.pn_buf, ZFS_MAXNAMELEN); + pn_free(ppn); if (error == -ENOENT) return (NULL); } @@ -105,7 +104,7 @@ zpl_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) ci_name.name = pn.pn_buf; ci_name.len = strlen(pn.pn_buf); new_dentry = d_add_ci(dentry, ip, &ci_name); - kmem_free(pn.pn_buf, ZFS_MAXNAMELEN); + pn_free(ppn); return (new_dentry); } else { return (d_splice_alias(ip, dentry)); @@ -157,7 +156,7 @@ zpl_create(struct inode *dir, struct dentry *dentry, zpl_umode_t mode, error = zpl_init_acl(ip, dir); if (error) - (void) zfs_remove(dir, dname(dentry), cr); + (void) zfs_remove(dir, dname(dentry), cr, 0); } spl_fstrans_unmark(cookie); @@ -200,7 +199,7 @@ zpl_mknod(struct inode *dir, struct dentry *dentry, zpl_umode_t mode, error = zpl_init_acl(ip, dir); if (error) - (void) zfs_remove(dir, dname(dentry), cr); + (void) zfs_remove(dir, dname(dentry), cr, 0); } spl_fstrans_unmark(cookie); @@ -221,7 +220,7 @@ zpl_unlink(struct inode *dir, struct dentry *dentry) crhold(cr); cookie = spl_fstrans_mark(); - error = -zfs_remove(dir, dname(dentry), cr); + error = -zfs_remove(dir, dname(dentry), cr, 0); /* * For a CI FS we must invalidate the dentry to prevent the @@ -389,7 +388,7 @@ zpl_symlink(struct inode *dir, struct dentry *dentry, const char *name) error = zpl_xattr_security_init(ip, dir, &dentry->d_name); if (error) - (void) zfs_remove(dir, dname(dentry), cr); + (void) zfs_remove(dir, dname(dentry), cr, 0); } spl_fstrans_unmark(cookie); @@ -537,7 +536,7 @@ zpl_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) igrab(ip); /* Use ihold() if available */ cookie = spl_fstrans_mark(); - error = -zfs_link(dir, ip, dname(dentry), cr); + error = -zfs_link(dir, ip, dname(dentry), cr, 0); if (error) { iput(ip); goto out; diff --git a/module/zfs/zpl_xattr.c b/module/zfs/zpl_xattr.c index 420091953..e8623384c 100644 --- a/module/zfs/zpl_xattr.c +++ b/module/zfs/zpl_xattr.c @@ -465,7 +465,7 @@ zpl_xattr_set_dir(struct inode *ip, const char *name, const void *value, /* Remove a specific name xattr when value is set to NULL. */ if (value == NULL) { if (xip) - error = -zfs_remove(dxip, (char *)name, cr); + error = -zfs_remove(dxip, (char *)name, cr, 0); goto out; } |