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"
58 #include "vol_prototypes.h"
61 #include <sys/lockf.h>
63 #if defined(AFS_SUN5_ENV) || defined(AFS_NT40_ENV) || defined(AFS_LINUX20_ENV)
70 #define afs_open open64
71 #else /* !O_LARGEFILE */
73 #endif /* !O_LARGEFILE */
75 /*@printflike@*/ extern void Log(const char *format, ...);
77 #define nFILES (sizeof (stuff)/sizeof(struct stuff))
79 /* Note: the volume creation functions herein leave the destroyMe flag in the
80 volume header ON: this means that the volumes will not be attached by the
81 file server and WILL BE DESTROYED the next time a system salvage is performed */
84 RemoveInodes(Device dev, VolumeId vid)
89 /* This relies on the fact that IDEC only needs the device and NT only
90 * needs the dev and vid to decrement volume special files.
92 IH_INIT(handle, dev, vid, -1);
93 for (i = 0; i < nFILES; i++) {
94 Inode inode = *stuff[i].inode;
96 IH_DEC(handle, inode, vid);
102 VCreateVolume(Error * ec, char *partname, VolId volumeId, VolId parentId)
103 { /* Should be the same as volumeId if there is
107 retVal = VCreateVolume_r(ec, partname, volumeId, parentId);
113 VCreateVolume_r(Error * ec, char *partname, VolId volumeId, VolId parentId)
114 { /* Should be the same as volumeId if there is
118 char headerName[VMAXPATHLEN], volumePath[VMAXPATHLEN];
120 struct DiskPartition64 *partition;
121 struct VolumeDiskHeader diskHeader;
129 memset(&vol, 0, sizeof(vol));
131 vol.parentId = parentId;
132 vol.copyDate = time(0); /* The only date which really means when this
133 * @i(instance) of this volume was created.
134 * Creation date does not mean this */
136 /* Initialize handle for error case below. */
139 /* Verify that the parition is valid before writing to it. */
140 if (!(partition = VGetPartition_r(partname, 0))) {
141 Log("VCreateVolume: partition %s is not in service.\n", partname);
145 #if defined(NEARINODE_HINT)
146 nearInodeHash(volumeId, nearInode);
147 nearInode %= partition->f_files;
149 VGetVolumePath(ec, vol.id, &part, &name);
150 if (*ec == VNOVOL || !strcmp(partition->name, part)) {
151 /* this case is ok */
153 /* return EXDEV if it's a clone to an alternate partition
154 * otherwise assume it's a move */
155 if (vol.parentId != vol.id) {
161 VLockPartition_r(partname);
162 memset(&tempHeader, 0, sizeof(tempHeader));
163 tempHeader.stamp.magic = VOLUMEHEADERMAGIC;
164 tempHeader.stamp.version = VOLUMEHEADERVERSION;
165 tempHeader.id = vol.id;
166 tempHeader.parent = vol.parentId;
167 vol.stamp.magic = VOLUMEINFOMAGIC;
168 vol.stamp.version = VOLUMEINFOVERSION;
169 vol.destroyMe = DESTROY_ME;
170 (void)afs_snprintf(headerName, sizeof headerName, VFORMAT, afs_printable_uint32_lu(vol.id));
171 (void)afs_snprintf(volumePath, sizeof volumePath, "%s/%s",
172 VPartitionPath(partition), headerName);
173 rc = stat(volumePath, &st);
174 if (rc == 0 || errno != ENOENT) {
176 Log("VCreateVolume: Header file %s already exists!\n",
180 Log("VCreateVolume: Error %d trying to stat header file %s\n",
186 device = partition->device;
188 for (i = 0; i < nFILES; i++) {
189 register struct stuff *p = &stuff[i];
194 IH_CREATE(NULL, device, VPartitionPath(partition), nearInode,
195 (p->inodeType == VI_LINKTABLE) ? vol.parentId : vol.id,
196 INODESPECIAL, p->inodeType, vol.parentId);
197 if (!(VALID_INO(*(p->inode)))) {
198 if (errno == EEXIST) {
199 /* Increment the reference count instead. */
204 *(p->inode) = nt_MakeSpecIno(VI_LINKTABLE);
206 *(p->inode) = namei_MakeSpecIno(vol.parentId, VI_LINKTABLE);
208 IH_INIT(lh, device, parentId, *(p->inode));
214 code = IH_INC(lh, *(p->inode), parentId);
215 FDH_REALLYCLOSE(fdP);
224 IH_CREATE(NULL, device, VPartitionPath(partition), nearInode,
225 vol.id, INODESPECIAL, p->inodeType, vol.parentId);
228 if (!VALID_INO(*(p->inode))) {
229 Log("VCreateVolume: Problem creating %s file associated with volume header %s\n", p->description, volumePath);
233 RemoveInodes(device, vol.id);
237 VDestroyVolumeDiskHeader(partition, volumeId, parentId);
240 IH_INIT(handle, device, vol.parentId, *(p->inode));
241 fdP = IH_OPEN(handle);
243 Log("VCreateVolume: Problem iopen inode %s (err=%d)\n",
244 PrintInode(NULL, *(p->inode)), errno);
247 if (FDH_SEEK(fdP, 0, SEEK_SET) < 0) {
248 Log("VCreateVolume: Problem lseek inode %s (err=%d)\n",
249 PrintInode(NULL, *(p->inode)), errno);
250 FDH_REALLYCLOSE(fdP);
253 if (FDH_WRITE(fdP, (char *)&p->stamp, sizeof(p->stamp)) !=
255 Log("VCreateVolume: Problem writing to inode %s (err=%d)\n",
256 PrintInode(NULL, *(p->inode)), errno);
257 FDH_REALLYCLOSE(fdP);
260 FDH_REALLYCLOSE(fdP);
262 nearInode = *(p->inode);
265 IH_INIT(handle, device, vol.parentId, tempHeader.volumeInfo);
266 fdP = IH_OPEN(handle);
268 Log("VCreateVolume: Problem iopen inode %s (err=%d)\n",
269 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);
278 if (FDH_WRITE(fdP, (char *)&vol, sizeof(vol)) != sizeof(vol)) {
279 Log("VCreateVolume: Problem writing to inode %s (err=%d)\n",
280 PrintInode(NULL, tempHeader.volumeInfo), errno);
281 FDH_REALLYCLOSE(fdP);
287 VolumeHeaderToDisk(&diskHeader, &tempHeader);
288 rc = VCreateVolumeDiskHeader(&diskHeader, partition);
290 Log("VCreateVolume: Error %d trying to write volume header for "
291 "volume %u on partition %s; volume not created\n", rc,
292 vol.id, VPartitionPath(partition));
299 return (VAttachVolumeByName_r(ec, partname, headerName, V_SECRETLY));
304 AssignVolumeName(register VolumeDiskData * vol, char *name, char *ext)
307 AssignVolumeName_r(vol, name, ext);
312 AssignVolumeName_r(register VolumeDiskData * vol, char *name, char *ext)
315 strncpy(vol->name, name, VNAMESIZE - 1);
316 vol->name[VNAMESIZE - 1] = '\0';
317 dot = strrchr(vol->name, '.');
318 if (dot && (strcmp(dot, ".backup") == 0 || strcmp(dot, ".readonly") == 0))
321 strncat(vol->name, ext, VNAMESIZE - 1 - strlen(vol->name));
325 CopyVolumeHeader_r(VolumeDiskData * from, VolumeDiskData * to)
327 /* The id and parentId fields are not copied; these are inviolate--the to volume
328 * is assumed to have already been created. The id's cannot be changed once
329 * creation has taken place, since they are embedded in the various inodes associated
330 * with the volume. The copydate is also inviolate--it always reflects the time
331 * this volume was created (compare with the creation date--the creation date of
332 * a backup volume is the creation date of the original parent, because the backup
333 * is used to backup the parent volume). */
337 parent = to->parentId;
338 copydate = to->copyDate;
339 memcpy(to, from, sizeof(*from));
341 to->parentId = parent;
342 to->copyDate = copydate;
343 to->destroyMe = DESTROY_ME; /* Caller must always clear this!!! */
344 to->stamp.magic = VOLUMEINFOMAGIC;
345 to->stamp.version = VOLUMEINFOVERSION;
350 CopyVolumeHeader(VolumeDiskData * from, VolumeDiskData * to)
355 code = CopyVolumeHeader_r(from, to);
361 ClearVolumeStats(register VolumeDiskData * vol)
364 ClearVolumeStats_r(vol);
369 ClearVolumeStats_r(register VolumeDiskData * vol)
371 memset(vol->weekUse, 0, sizeof(vol->weekUse));
377 * read an existing volume disk header.
379 * @param[in] volid volume id
380 * @param[in] dp disk partition object
381 * @param[out] hdr volume disk header
383 * @return operation status
385 * @retval -1 volume header doesn't exist
386 * @retval EIO failed to read volume header
391 VReadVolumeDiskHeader(VolumeId volid,
392 struct DiskPartition64 * dp,
393 VolumeDiskHeader_t * hdr)
397 char path[MAXPATHLEN];
399 (void)afs_snprintf(path, sizeof(path),
401 VPartitionPath(dp), afs_printable_uint32_lu(volid));
402 fd = open(path, O_RDONLY);
404 Log("VReadVolumeDiskHeader: Couldn't open header for volume %lu.\n",
405 afs_printable_uint32_lu(volid));
407 } else if (read(fd, hdr, sizeof(*hdr)) != sizeof(*hdr)) {
408 Log("VReadVolumeDiskHeader: Couldn't read header for volume %lu.\n",
409 afs_printable_uint32_lu(volid));
420 * write an existing volume disk header.
422 * @param[in] hdr volume disk header
423 * @param[in] dp disk partition object
424 * @param[in] cr assert if O_CREAT | O_EXCL should be passed to open()
426 * @return operation status
428 * @retval -1 volume header doesn't exist
429 * @retval EIO failed to write volume header
434 _VWriteVolumeDiskHeader(VolumeDiskHeader_t * hdr,
435 struct DiskPartition64 * dp,
440 char path[MAXPATHLEN];
444 (void)afs_snprintf(path, sizeof(path),
446 VPartitionPath(dp), afs_printable_uint32_lu(hdr->id));
447 fd = open(path, flags, 0644);
450 Log("_VWriteVolumeDiskHeader: Couldn't open header for volume %lu, "
451 "error = %d\n", afs_printable_uint32_lu(hdr->id), errno);
452 } else if (write(fd, hdr, sizeof(*hdr)) != sizeof(*hdr)) {
453 Log("_VWriteVolumeDiskHeader: Couldn't write header for volume %lu, "
454 "error = %d\n", afs_printable_uint32_lu(hdr->id), errno);
459 if (close(fd) != 0) {
460 Log("_VWriteVolumeDiskHeader: Error closing header for volume "
461 "%lu, errno %d\n", afs_printable_uint32_lu(hdr->id), errno);
469 * write an existing volume disk header.
471 * @param[in] hdr volume disk header
472 * @param[in] dp disk partition object
474 * @return operation status
476 * @retval ENOENT volume header doesn't exist
477 * @retval EIO failed to write volume header
480 VWriteVolumeDiskHeader(VolumeDiskHeader_t * hdr,
481 struct DiskPartition64 * dp)
485 code = _VWriteVolumeDiskHeader(hdr, dp, 0);
495 * create and write a volume disk header to disk.
497 * @param[in] hdr volume disk header
498 * @param[in] dp disk partition object
500 * @return operation status
502 * @retval EEXIST volume header already exists
503 * @retval EIO failed to write volume header
508 VCreateVolumeDiskHeader(VolumeDiskHeader_t * hdr,
509 struct DiskPartition64 * dp)
513 code = _VWriteVolumeDiskHeader(hdr, dp, O_CREAT | O_EXCL);
524 * destroy a volume disk header.
526 * @param[in] dp disk partition object
527 * @param[in] volid volume id
528 * @param[in] parent parent's volume id, 0 if unknown
530 * @return operation status
533 * @note if parent is 0, the parent volume ID will be looked up from the
536 * @note for non-DAFS, parent is currently ignored
539 VDestroyVolumeDiskHeader(struct DiskPartition64 * dp,
544 char path[MAXPATHLEN];
546 (void)afs_snprintf(path, sizeof(path),
548 VPartitionPath(dp), afs_printable_uint32_lu(volid));
551 Log("VDestroyVolumeDiskHeader: Couldn't unlink disk header, error = %d\n", errno);