2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
13 Institution: The Information Technology Center, Carnegie-Mellon University
17 #include <afsconfig.h>
18 #include <afs/param.h>
22 #include <sys/types.h>
33 #ifdef AFS_PTHREAD_ENV
35 #else /* AFS_PTHREAD_ENV */
36 #include <afs/assert.h>
37 #endif /* AFS_PTHREAD_ENV */
40 #include <afs/afsint.h>
42 #include <afs/errors.h>
45 #include <afs/afssyscalls.h>
47 #include <afs/afsutil.h>
54 #include "partition.h"
55 #include "viceinode.h"
57 #include "volinodes.h"
59 #include <sys/lockf.h>
61 #if defined(AFS_SUN5_ENV) || defined(AFS_NT40_ENV) || defined(AFS_LINUX20_ENV)
68 #define afs_open open64
69 #else /* !O_LARGEFILE */
71 #endif /* !O_LARGEFILE */
73 /*@printflike@*/ extern void Log(const char *format, ...);
75 void AssignVolumeName(register VolumeDiskData * vol, char *name, char *ext);
76 void AssignVolumeName_r(register VolumeDiskData * vol, char *name, char *ext);
77 void ClearVolumeStats(register VolumeDiskData * vol);
78 void ClearVolumeStats_r(register VolumeDiskData * vol);
81 #define nFILES (sizeof (stuff)/sizeof(struct stuff))
83 /* Note: the volume creation functions herein leave the destroyMe flag in the
84 volume header ON: this means that the volumes will not be attached by the
85 file server and WILL BE DESTROYED the next time a system salvage is performed */
88 RemoveInodes(Device dev, VolumeId vid)
93 /* This relies on the fact that IDEC only needs the device and NT only
94 * needs the dev and vid to decrement volume special files.
96 IH_INIT(handle, dev, vid, -1);
97 for (i = 0; i < nFILES; i++) {
98 Inode inode = *stuff[i].inode;
100 IH_DEC(handle, inode, vid);
106 VCreateVolume(Error * ec, char *partname, VolId volumeId, VolId parentId)
107 { /* Should be the same as volumeId if there is
111 retVal = VCreateVolume_r(ec, partname, volumeId, parentId);
117 VCreateVolume_r(Error * ec, char *partname, VolId volumeId, VolId parentId)
118 { /* Should be the same as volumeId if there is
122 char headerName[32], volumePath[64];
124 struct DiskPartition64 *partition;
125 struct VolumeDiskHeader diskHeader;
132 memset(&vol, 0, sizeof(vol));
134 vol.parentId = parentId;
135 vol.copyDate = time(0); /* The only date which really means when this
136 * @i(instance) of this volume was created.
137 * Creation date does not mean this */
139 /* Initialize handle for error case below. */
142 /* Verify that the parition is valid before writing to it. */
143 if (!(partition = VGetPartition_r(partname, 0))) {
144 Log("VCreateVolume: partition %s is not in service.\n", partname);
148 #if defined(NEARINODE_HINT)
149 nearInodeHash(volumeId, nearInode);
150 nearInode %= partition->f_files;
152 VGetVolumePath(ec, vol.id, &part, &name);
153 if (*ec == VNOVOL || !strcmp(partition->name, part)) {
154 /* this case is ok */
156 /* return EXDEV if it's a clone to an alternate partition
157 * otherwise assume it's a move */
158 if (vol.parentId != vol.id) {
163 VLockPartition_r(partname);
164 memset(&tempHeader, 0, sizeof(tempHeader));
165 tempHeader.stamp.magic = VOLUMEHEADERMAGIC;
166 tempHeader.stamp.version = VOLUMEHEADERVERSION;
167 tempHeader.id = vol.id;
168 tempHeader.parent = vol.parentId;
169 vol.stamp.magic = VOLUMEINFOMAGIC;
170 vol.stamp.version = VOLUMEINFOVERSION;
171 vol.destroyMe = DESTROY_ME;
172 (void)afs_snprintf(headerName, sizeof headerName, VFORMAT, afs_cast_uint32(vol.id));
173 (void)afs_snprintf(volumePath, sizeof volumePath, "%s/%s",
174 VPartitionPath(partition), headerName);
175 fd = afs_open(volumePath, O_CREAT | O_EXCL | O_WRONLY, 0600);
177 if (errno == EEXIST) {
178 Log("VCreateVolume: Header file %s already exists!\n",
182 Log("VCreateVolume: Couldn't create header file %s for volume %u\n", volumePath, vol.id);
187 device = partition->device;
189 for (i = 0; i < nFILES; i++) {
190 register struct stuff *p = &stuff[i];
195 IH_CREATE(NULL, device, VPartitionPath(partition), nearInode,
196 (p->inodeType == VI_LINKTABLE) ? vol.parentId : vol.id,
197 INODESPECIAL, p->inodeType, vol.parentId);
198 if (!(VALID_INO(*(p->inode)))) {
199 if (errno == EEXIST) {
200 /* Increment the reference count instead. */
205 *(p->inode) = nt_MakeSpecIno(VI_LINKTABLE);
207 *(p->inode) = namei_MakeSpecIno(vol.parentId, VI_LINKTABLE);
209 IH_INIT(lh, device, parentId, *(p->inode));
215 code = IH_INC(lh, *(p->inode), parentId);
216 FDH_REALLYCLOSE(fdP);
225 IH_CREATE(NULL, device, VPartitionPath(partition), nearInode,
226 vol.id, INODESPECIAL, p->inodeType, vol.parentId);
229 if (!VALID_INO(*(p->inode))) {
230 Log("VCreateVolume: Problem creating %s file associated with volume header %s\n", p->description, volumePath);
234 RemoveInodes(device, vol.id);
239 IH_INIT(handle, device, vol.parentId, *(p->inode));
240 fdP = IH_OPEN(handle);
242 Log("VCreateVolume: Problem iopen inode %s (err=%d)\n",
243 PrintInode(NULL, *(p->inode)), errno);
246 if (FDH_SEEK(fdP, 0, SEEK_SET) < 0) {
247 Log("VCreateVolume: Problem lseek inode %s (err=%d)\n",
248 PrintInode(NULL, *(p->inode)), errno);
249 FDH_REALLYCLOSE(fdP);
252 if (FDH_WRITE(fdP, (char *)&p->stamp, sizeof(p->stamp)) !=
254 Log("VCreateVolume: Problem writing to inode %s (err=%d)\n",
255 PrintInode(NULL, *(p->inode)), errno);
256 FDH_REALLYCLOSE(fdP);
259 FDH_REALLYCLOSE(fdP);
261 nearInode = *(p->inode);
264 IH_INIT(handle, device, vol.parentId, tempHeader.volumeInfo);
265 fdP = IH_OPEN(handle);
267 Log("VCreateVolume: Problem iopen inode %s (err=%d)\n",
268 PrintInode(NULL, tempHeader.volumeInfo), errno);
272 if (FDH_SEEK(fdP, 0, SEEK_SET) < 0) {
273 Log("VCreateVolume: Problem lseek inode %s (err=%d)\n",
274 PrintInode(NULL, tempHeader.volumeInfo), errno);
275 FDH_REALLYCLOSE(fdP);
279 if (FDH_WRITE(fdP, (char *)&vol, sizeof(vol)) != sizeof(vol)) {
280 Log("VCreateVolume: Problem writing to inode %s (err=%d)\n",
281 PrintInode(NULL, tempHeader.volumeInfo), errno);
282 FDH_REALLYCLOSE(fdP);
289 VolumeHeaderToDisk(&diskHeader, &tempHeader);
290 if (write(fd, &diskHeader, sizeof(diskHeader)) != sizeof(diskHeader)) {
291 Log("VCreateVolume: Unable to write volume header %s; volume %u not created\n", volumePath, vol.id);
297 return (VAttachVolumeByName_r(ec, partname, headerName, V_SECRETLY));
302 AssignVolumeName(register VolumeDiskData * vol, char *name, char *ext)
305 AssignVolumeName_r(vol, name, ext);
310 AssignVolumeName_r(register VolumeDiskData * vol, char *name, char *ext)
313 strncpy(vol->name, name, VNAMESIZE - 1);
314 vol->name[VNAMESIZE - 1] = '\0';
315 dot = strrchr(vol->name, '.');
316 if (dot && (strcmp(dot, ".backup") == 0 || strcmp(dot, ".readonly") == 0))
319 strncat(vol->name, ext, VNAMESIZE - 1 - strlen(vol->name));
323 CopyVolumeHeader_r(VolumeDiskData * from, VolumeDiskData * to)
325 /* The id and parentId fields are not copied; these are inviolate--the to volume
326 * is assumed to have already been created. The id's cannot be changed once
327 * creation has taken place, since they are embedded in the various inodes associated
328 * with the volume. The copydate is also inviolate--it always reflects the time
329 * this volume was created (compare with the creation date--the creation date of
330 * a backup volume is the creation date of the original parent, because the backup
331 * is used to backup the parent volume). */
335 parent = to->parentId;
336 copydate = to->copyDate;
337 memcpy(to, from, sizeof(*from));
339 to->parentId = parent;
340 to->copyDate = copydate;
341 to->destroyMe = DESTROY_ME; /* Caller must always clear this!!! */
342 to->stamp.magic = VOLUMEINFOMAGIC;
343 to->stamp.version = VOLUMEINFOVERSION;
348 CopyVolumeHeader(VolumeDiskData * from, VolumeDiskData * to)
353 code = CopyVolumeHeader_r(from, to);
359 ClearVolumeStats(register VolumeDiskData * vol)
362 ClearVolumeStats_r(vol);
367 ClearVolumeStats_r(register VolumeDiskData * vol)
369 memset(vol->weekUse, 0, sizeof(vol->weekUse));