Print this page
5384 pvn_getpages may assert in valid scenarios


   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 1986, 2010, Oracle and/or its affiliates. All rights reserved.

  23  */
  24 
  25 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T     */
  26 /*        All Rights Reserved   */
  27 
  28 /*
  29  * University Copyright- Copyright (c) 1982, 1986, 1988
  30  * The Regents of the University of California
  31  * All Rights Reserved
  32  *
  33  * University Acknowledgment- Portions of this document are derived from
  34  * software developed by the University of California, Berkeley, and its
  35  * contributors.
  36  */
  37 
  38 /*
  39  * VM - paged vnode.
  40  *
  41  * This file supplies vm support for the vnode operations that deal with pages.
  42  */


1073          * dirty so that we know that when this page is written
1074          * back, the zeroed information will go out with it.  If
1075          * the page is not currently in memory, then the kzero
1076          * operation will cause it to be brought it.  We use kzero
1077          * instead of bzero so that if the page cannot be read in
1078          * for any reason, the system will not panic.  We need
1079          * to zero out a minimum of the fs given zbytes, but we
1080          * might also have to do more to get the entire last page.
1081          */
1082 
1083         if ((zbytes + (vplen & MAXBOFFSET)) > MAXBSIZE)
1084                 panic("pvn_vptrunc zbytes");
1085         addr = segmap_getmapflt(segkmap, vp, vplen,
1086             MAX(zbytes, PAGESIZE - (vplen & PAGEOFFSET)), 1, S_WRITE);
1087         (void) kzero(addr + (vplen & MAXBOFFSET),
1088             MAX(zbytes, PAGESIZE - (vplen & PAGEOFFSET)));
1089         (void) segmap_release(segkmap, addr, SM_WRITE | SM_ASYNC);
1090 }
1091 
1092 /*
1093  * Handles common work of the VOP_GETPAGE routines when more than
1094  * one page must be returned by calling a file system specific operation
1095  * to do most of the work.  Must be called with the vp already locked
1096  * by the VOP_GETPAGE routine.
1097  */
1098 int
1099 pvn_getpages(
1100         int (*getpage)(vnode_t *, u_offset_t, size_t, uint_t *, page_t *[],
1101                 size_t, struct seg *, caddr_t, enum seg_rw, cred_t *),
1102         struct vnode *vp,
1103         u_offset_t off,
1104         size_t len,
1105         uint_t *protp,
1106         page_t *pl[],
1107         size_t plsz,
1108         struct seg *seg,
1109         caddr_t addr,
1110         enum seg_rw rw,
1111         struct cred *cred)
1112 {
1113         page_t **ppp;
1114         u_offset_t o, eoff;
1115         size_t sz, xlen;
1116         int err;
1117 
1118         ASSERT(plsz >= len);         /* insure that we have enough space */

1119 
1120         /*
1121          * Loop one page at a time and let getapage function fill
1122          * in the next page in array.  We only allow one page to be
1123          * returned at a time (except for the last page) so that we
1124          * don't have any problems with duplicates and other such
1125          * painful problems.  This is a very simple minded algorithm,
1126          * but it does the job correctly.  We hope that the cost of a
1127          * getapage call for a resident page that we might have been
1128          * able to get from an earlier call doesn't cost too much.
1129          */
1130         ppp = pl;
1131         sz = PAGESIZE;
1132         eoff = off + len;
1133         xlen = len;
1134         for (o = off; o < eoff; o += PAGESIZE, addr += PAGESIZE,
1135             xlen -= PAGESIZE) {
1136                 if (o + PAGESIZE >= eoff) {
1137                         /*
1138                          * Last time through - allow the all of
1139                          * what's left of the pl[] array to be used.
1140                          */
1141                         sz = plsz - (o - off);
1142                 }
1143                 err = (*getpage)(vp, o, xlen, protp, ppp, sz, seg, addr,
1144                     rw, cred);
1145                 if (err) {
1146                         /*
1147                          * Release any pages we already got.
1148                          */
1149                         if (o > off && pl != NULL) {
1150                                 for (ppp = pl; *ppp != NULL; *ppp++ = NULL)
1151                                         (void) page_release(*ppp, 1);
1152                         }
1153                         break;
1154                 }
1155                 if (pl != NULL)
1156                         ppp++;




   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 1986, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  24  */
  25 
  26 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T     */
  27 /*        All Rights Reserved   */
  28 
  29 /*
  30  * University Copyright- Copyright (c) 1982, 1986, 1988
  31  * The Regents of the University of California
  32  * All Rights Reserved
  33  *
  34  * University Acknowledgment- Portions of this document are derived from
  35  * software developed by the University of California, Berkeley, and its
  36  * contributors.
  37  */
  38 
  39 /*
  40  * VM - paged vnode.
  41  *
  42  * This file supplies vm support for the vnode operations that deal with pages.
  43  */


1074          * dirty so that we know that when this page is written
1075          * back, the zeroed information will go out with it.  If
1076          * the page is not currently in memory, then the kzero
1077          * operation will cause it to be brought it.  We use kzero
1078          * instead of bzero so that if the page cannot be read in
1079          * for any reason, the system will not panic.  We need
1080          * to zero out a minimum of the fs given zbytes, but we
1081          * might also have to do more to get the entire last page.
1082          */
1083 
1084         if ((zbytes + (vplen & MAXBOFFSET)) > MAXBSIZE)
1085                 panic("pvn_vptrunc zbytes");
1086         addr = segmap_getmapflt(segkmap, vp, vplen,
1087             MAX(zbytes, PAGESIZE - (vplen & PAGEOFFSET)), 1, S_WRITE);
1088         (void) kzero(addr + (vplen & MAXBOFFSET),
1089             MAX(zbytes, PAGESIZE - (vplen & PAGEOFFSET)));
1090         (void) segmap_release(segkmap, addr, SM_WRITE | SM_ASYNC);
1091 }
1092 
1093 /*
1094  * Handles common work of the VOP_GETPAGE routines by iterating page by page
1095  * calling the getpage helper for each.


1096  */
1097 int
1098 pvn_getpages(
1099         int (*getpage)(vnode_t *, u_offset_t, size_t, uint_t *, page_t *[],
1100                 size_t, struct seg *, caddr_t, enum seg_rw, cred_t *),
1101         struct vnode *vp,
1102         u_offset_t off,
1103         size_t len,
1104         uint_t *protp,
1105         page_t *pl[],
1106         size_t plsz,
1107         struct seg *seg,
1108         caddr_t addr,
1109         enum seg_rw rw,
1110         struct cred *cred)
1111 {
1112         page_t **ppp;
1113         u_offset_t o, eoff;
1114         size_t sz, xlen;
1115         int err;
1116 
1117         /* ensure that we have enough space */
1118         ASSERT(pl == NULL || plsz >= len);
1119 
1120         /*
1121          * Loop one page at a time and let getapage function fill
1122          * in the next page in array.  We only allow one page to be
1123          * returned at a time (except for the last page) so that we
1124          * don't have any problems with duplicates and other such
1125          * painful problems.  This is a very simple minded algorithm,
1126          * but it does the job correctly.  We hope that the cost of a
1127          * getapage call for a resident page that we might have been
1128          * able to get from an earlier call doesn't cost too much.
1129          */
1130         ppp = pl;
1131         sz = (pl != NULL) ? PAGESIZE : 0;
1132         eoff = off + len;
1133         xlen = len;
1134         for (o = off; o < eoff; o += PAGESIZE, addr += PAGESIZE,
1135             xlen -= PAGESIZE) {
1136                 if (o + PAGESIZE >= eoff && pl != NULL) {
1137                         /*
1138                          * Last time through - allow the all of
1139                          * what's left of the pl[] array to be used.
1140                          */
1141                         sz = plsz - (o - off);
1142                 }
1143                 err = (*getpage)(vp, o, xlen, protp, ppp, sz, seg, addr,
1144                     rw, cred);
1145                 if (err) {
1146                         /*
1147                          * Release any pages we already got.
1148                          */
1149                         if (o > off && pl != NULL) {
1150                                 for (ppp = pl; *ppp != NULL; *ppp++ = NULL)
1151                                         (void) page_release(*ppp, 1);
1152                         }
1153                         break;
1154                 }
1155                 if (pl != NULL)
1156                         ppp++;